diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile index f44d60dd255..90b47e78021 100644 --- a/lib/libstand/Makefile +++ b/lib/libstand/Makefile @@ -20,23 +20,23 @@ WARNS?= 0 CFLAGS+= -ffreestanding -Wformat CFLAGS+= -I${.CURDIR} -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -mpreferred-stack-boundary=2 CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" CFLAGS+= -mno-sse3 .endif .if ${MACHINE} == "pc98" CFLAGS+= -Os .endif -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.if ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -msoft-float -D_STANDALONE -DNETIF_DEBUG .endif .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc64" CFLAGS+= -m32 -I. .endif -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "arm" CFLAGS+= -msoft-float -D_STANDALONE .endif @@ -54,19 +54,19 @@ SRCS+= ntoh.c # string functions from libc .PATH: ${.CURDIR}/../libc/string -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "powerpc" || \ - ${MACHINE_ARCH} == "powerpc64" || ${MACHINE_ARCH} == "sparc64" || \ - ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" || \ + ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "amd64" || \ + ${MACHINE_CPUARCH} == "arm" SRCS+= bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \ memcpy.c memmove.c memset.c qdivrem.c rindex.c strcat.c strchr.c \ strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c \ strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c .endif -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "arm" .PATH: ${.CURDIR}/../libc/arm/gen SRCS+= divsi3.S .endif -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" .PATH: ${.CURDIR}/../libc/ia64/string SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \ memcpy.S memmove.S memset.c rindex.c strcat.c strchr.c \ @@ -78,7 +78,7 @@ SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \ SRCS+= __divdi3.S __divsi3.S __moddi3.S __modsi3.S SRCS+= __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S .endif -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.if ${MACHINE_CPUARCH} == "powerpc" .PATH: ${.CURDIR}/../libc/quad SRCS+= ashldi3.c ashrdi3.c .PATH: ${.CURDIR}/../libc/powerpc/gen @@ -90,12 +90,12 @@ SRCS+= syncicache.c SRCS+= uuid_equal.c uuid_is_nil.c # _setjmp/_longjmp -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" .PATH: ${.CURDIR}/i386 .elif ${MACHINE_ARCH} == "powerpc64" .PATH: ${.CURDIR}/powerpc .else -.PATH: ${.CURDIR}/${MACHINE_ARCH} +.PATH: ${.CURDIR}/${MACHINE_CPUARCH} .endif SRCS+= _setjmp.S @@ -157,7 +157,7 @@ SRCS+= splitfs.c .include -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine cleandepend: cleanmachine cleanmachine: diff --git a/lib/libstand/libstand.3 b/lib/libstand/libstand.3 index d1c544ca768..2938e2d90cb 100644 --- a/lib/libstand/libstand.3 +++ b/lib/libstand/libstand.3 @@ -270,7 +270,6 @@ The .Li b conversion is provided to decode error registers. Its usage is: -.Pp .Bd -ragged -offset indent printf( .Qq reg=%b\en , @@ -285,7 +284,6 @@ Each is a sequence of characters, the first of which gives the bit number to be inspected (origin 1) and the next characters (up to a character less than 32) give the text to be displayed if the bit is set. Thus -.Pp .Bd -ragged -offset indent printf( .Qq reg=%b\en , @@ -295,7 +293,6 @@ printf( .Ed .Pp would give the output -.Pp .Bd -ragged -offset indent reg=3 .Ed @@ -303,7 +300,6 @@ reg=3 The .Li D conversion provides a hexdump facility, e.g. -.Pp .Bd -ragged -offset indent printf( .Qq %6D , diff --git a/lib/libstand/net.h b/lib/libstand/net.h index 9434c3ca31f..94f2aabf81e 100644 --- a/lib/libstand/net.h +++ b/lib/libstand/net.h @@ -50,7 +50,7 @@ #define MACPY(s, d) bcopy((char *)s, (char *)d, 6) -#define MAXTMO 20 /* seconds */ +#define MAXTMO 120 /* seconds */ #define MINTMO 2 /* seconds */ #define FNAME_SIZE 128 diff --git a/lib/libstand/nfs.c b/lib/libstand/nfs.c index 485944922b1..e49999de957 100644 --- a/lib/libstand/nfs.c +++ b/lib/libstand/nfs.c @@ -50,7 +50,10 @@ __FBSDID("$FreeBSD$"); #define NFS_DEBUGxx +#define NFSREAD_SIZE 1024 + /* Define our own NFS attributes without NQNFS stuff. */ +#ifdef OLD_NFSV2 struct nfsv2_fattrs { n_long fa_type; n_long fa_mode; @@ -68,7 +71,6 @@ struct nfsv2_fattrs { struct nfsv2_time fa_ctime; }; - struct nfs_read_args { u_char fh[NFS_FHSIZE]; n_long off; @@ -77,7 +79,6 @@ struct nfs_read_args { }; /* Data part of nfs rpc reply (also the largest thing we receive) */ -#define NFSREAD_SIZE 1024 struct nfs_read_repl { n_long errno; struct nfsv2_fattrs fa; @@ -116,6 +117,72 @@ struct nfs_iodesc { u_char fh[NFS_FHSIZE]; struct nfsv2_fattrs fa; /* all in network order */ }; +#else /* !OLD_NFSV2 */ + +/* NFSv3 definitions */ +#define NFS_V3MAXFHSIZE 64 +#define NFS_VER3 3 +#define RPCMNT_VER3 3 +#define NFSPROCV3_LOOKUP 3 +#define NFSPROCV3_READLINK 5 +#define NFSPROCV3_READ 6 +#define NFSPROCV3_READDIR 16 + +typedef struct { + uint32_t val[2]; +} n_quad; + +struct nfsv3_time { + uint32_t nfs_sec; + uint32_t nfs_nsec; +}; + +struct nfsv3_fattrs { + uint32_t fa_type; + uint32_t fa_mode; + uint32_t fa_nlink; + uint32_t fa_uid; + uint32_t fa_gid; + n_quad fa_size; + n_quad fa_used; + n_quad fa_rdev; + n_quad fa_fsid; + n_quad fa_fileid; + struct nfsv3_time fa_atime; + struct nfsv3_time fa_mtime; + struct nfsv3_time fa_ctime; +}; + +/* + * For NFSv3, the file handle is variable in size, so most fixed sized + * structures for arguments won't work. For most cases, a structure + * that starts with any fixed size section is followed by an array + * that covers the maximum size required. + */ +struct nfsv3_readdir_repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t cookiev0; + uint32_t cookiev1; +}; + +struct nfsv3_readdir_entry { + uint32_t follows; + uint32_t fid0; + uint32_t fid1; + uint32_t len; + uint32_t nameplus[0]; +}; + +struct nfs_iodesc { + struct iodesc *iodesc; + off_t off; + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + struct nfsv3_fattrs fa; /* all in network order */ +}; +#endif /* OLD_NFSV2 */ /* * XXX interactions with tftp? See nfswrapper.c for a confusing @@ -142,6 +209,7 @@ struct fs_ops nfs_fsops = { nfs_readdir }; +#ifdef OLD_NFSV2 /* * Fetch the root file handle (call mount daemon) * Return zero or error number. @@ -745,3 +813,675 @@ nfs_readdir(struct open_file *f, struct dirent *d) cookie = ntohl(roff->cookie); return 0; } +#else /* !OLD_NFSV2 */ +/* + * Fetch the root file handle (call mount daemon) + * Return zero or error number. + */ +int +nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp) +{ + int len; + struct args { + uint32_t len; + char path[FNAME_SIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + uint32_t authcnt; + uint32_t auth[7]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct repl d; + } rdata; + size_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_getrootfh: %s\n", path); +#endif + + args = &sdata.d; + repl = &rdata.d; + + bzero(args, sizeof(*args)); + len = strlen(path); + if (len > sizeof(args->path)) + len = sizeof(args->path); + args->len = htonl(len); + bcopy(path, args->path, len); + len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t)); + + cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT, + args, len, repl, sizeof(*repl)); + if (cc == -1) + /* errno was set by rpc_call */ + return (errno); + if (cc < 2 * sizeof (uint32_t)) + return (EBADRPC); + if (repl->errno != 0) + return (ntohl(repl->errno)); + *fhlenp = ntohl(repl->fhsize); + bcopy(repl->fh, fhp, *fhlenp); + return (0); +} + +/* + * Lookup a file. Store handle and attributes. + * Return zero or error number. + */ +int +nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd) +{ + int len, rlen, pos; + struct args { + uint32_t fhsize; + uint32_t fhplusname[1 + + (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)]; + } *args; + struct repl { + uint32_t errno; + uint32_t fhsize; + uint32_t fhplusattr[(NFS_V3MAXFHSIZE + + 2 * (sizeof(uint32_t) + + sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct repl d; + } rdata; + ssize_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("lookupfh: called\n"); +#endif + + args = &sdata.d; + repl = &rdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhplusname, d->fhsize); + len = strlen(name); + if (len > FNAME_SIZE) + len = FNAME_SIZE; + pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhplusname[pos++] = htonl(len); + bcopy(name, &args->fhplusname[pos], len); + len = sizeof(uint32_t) + pos * sizeof(uint32_t) + + roundup(len, sizeof(uint32_t)); + + rlen = sizeof(*repl); + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP, + args, len, repl, rlen); + if (cc == -1) + return (errno); /* XXX - from rpc_call */ + if (cc < 2 * sizeof(uint32_t)) + return (EIO); + if (repl->errno != 0) + /* saerrno.h now matches NFS error numbers. */ + return (ntohl(repl->errno)); + newfd->fhsize = ntohl(repl->fhsize); + bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize); + pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + if (repl->fhplusattr[pos++] == 0) + return (EIO); + bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa)); + return (0); +} + +#ifndef NFS_NOSYMLINK +/* + * Get the destination of a symbolic link. + */ +int +nfs_readlink(struct nfs_iodesc *d, char *buf) +{ + struct args { + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t len; + u_char path[NFS_MAXPATHLEN]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct repl d; + } rdata; + ssize_t cc; + +#ifdef NFS_DEBUG + if (debug) + printf("readlink: called\n"); +#endif + + args = &sdata.d; + repl = &rdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fh, d->fhsize); + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK, + args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), + repl, sizeof(*repl)); + if (cc == -1) + return (errno); + + if (cc < 2 * sizeof(uint32_t)) + return (EIO); + + if (repl->errno != 0) + return (ntohl(repl->errno)); + + if (repl->ok == 0) + return (EIO); + + repl->len = ntohl(repl->len); + if (repl->len > NFS_MAXPATHLEN) + return (ENAMETOOLONG); + + bcopy(repl->path, buf, repl->len); + buf[repl->len] = 0; + return (0); +} +#endif + +/* + * Read data from a file. + * Return transfer count or -1 (and set errno) + */ +ssize_t +nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len) +{ + struct args { + uint32_t fhsize; + uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3]; + } *args; + struct repl { + uint32_t errno; + uint32_t ok; + struct nfsv3_fattrs fa; + uint32_t count; + uint32_t eof; + uint32_t len; + u_char data[NFSREAD_SIZE]; + } *repl; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct repl d; + } rdata; + size_t cc; + long x; + int hlen, rlen, pos; + + args = &sdata.d; + repl = &rdata.d; + + bzero(args, sizeof(*args)); + args->fhsize = htonl(d->fhsize); + bcopy(d->fh, args->fhoffcnt, d->fhsize); + pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhoffcnt[pos++] = 0; + args->fhoffcnt[pos++] = htonl((uint32_t)off); + if (len > NFSREAD_SIZE) + len = NFSREAD_SIZE; + args->fhoffcnt[pos] = htonl((uint32_t)len); + hlen = sizeof(*repl) - NFSREAD_SIZE; + + cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ, + args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)), + repl, sizeof(*repl)); + if (cc == -1) + /* errno was already set by rpc_call */ + return (-1); + if (cc < hlen) { + errno = EBADRPC; + return (-1); + } + if (repl->errno != 0) { + errno = ntohl(repl->errno); + return (-1); + } + rlen = cc - hlen; + x = ntohl(repl->count); + if (rlen < x) { + printf("nfsread: short packet, %d < %ld\n", rlen, x); + errno = EBADRPC; + return (-1); + } + bcopy(repl->data, addr, x); + return (x); +} + +/* + * Open a file. + * return zero or error number + */ +int +nfs_open(const char *upath, struct open_file *f) +{ + struct iodesc *desc; + struct nfs_iodesc *currfd; + char buf[2 * NFS_V3MAXFHSIZE + 3]; + u_char *fh; + char *cp; + int i; +#ifndef NFS_NOSYMLINK + struct nfs_iodesc *newfd; + struct nfsv3_fattrs *fa; + char *ncp; + int c; + char namebuf[NFS_MAXPATHLEN + 1]; + char linkbuf[NFS_MAXPATHLEN + 1]; + int nlinks = 0; +#endif + int error; + char *path; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath); +#endif + if (!rootpath[0]) { + printf("no rootpath, no nfs\n"); + return (ENXIO); + } + + /* + * This is silly - we should look at dv_type but that value is + * arch dependant and we can't use it here. + */ +#ifndef __i386__ + if (strcmp(f->f_dev->dv_name, "net") != 0) + return (EINVAL); +#else + if (strcmp(f->f_dev->dv_name, "pxe") != 0) + return (EINVAL); +#endif + + if (!(desc = socktodesc(*(int *)(f->f_devdata)))) + return (EINVAL); + + /* Bind to a reserved port. */ + desc->myport = htons(--rpc_port); + desc->destip = rootip; + if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize, + nfs_root_node.fh))) + return (error); + nfs_root_node.iodesc = desc; + + fh = &nfs_root_node.fh[0]; + buf[0] = 'X'; + cp = &buf[1]; + for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) + sprintf(cp, "%02x", fh[i]); + sprintf(cp, "X"); + setenv("boot.nfsroot.server", inet_ntoa(rootip), 1); + setenv("boot.nfsroot.path", rootpath, 1); + setenv("boot.nfsroot.nfshandle", buf, 1); + sprintf(buf, "%d", nfs_root_node.fhsize); + setenv("boot.nfsroot.nfshandlelen", buf, 1); + +#ifndef NFS_NOSYMLINK + /* Fake up attributes for the root dir. */ + fa = &nfs_root_node.fa; + fa->fa_type = htonl(NFDIR); + fa->fa_mode = htonl(0755); + fa->fa_nlink = htonl(2); + + currfd = &nfs_root_node; + newfd = 0; + + cp = path = strdup(upath); + if (path == NULL) { + error = ENOMEM; + goto out; + } + while (*cp) { + /* + * Remove extra separators + */ + while (*cp == '/') + cp++; + + if (*cp == '\0') + break; + /* + * Check that current node is a directory. + */ + if (currfd->fa.fa_type != htonl(NFDIR)) { + error = ENOTDIR; + goto out; + } + + /* allocate file system specific data structure */ + newfd = malloc(sizeof(*newfd)); + if (newfd == NULL) { + error = ENOMEM; + goto out; + } + newfd->iodesc = currfd->iodesc; + newfd->off = 0; + + /* + * Get next component of path name. + */ + { + int len = 0; + + ncp = cp; + while ((c = *cp) != '\0' && c != '/') { + if (++len > NFS_MAXNAMLEN) { + error = ENOENT; + goto out; + } + cp++; + } + *cp = '\0'; + } + + /* lookup a file handle */ + error = nfs_lookupfh(currfd, ncp, newfd); + *cp = c; + if (error) + goto out; + + /* + * Check for symbolic link + */ + if (newfd->fa.fa_type == htonl(NFLNK)) { + int link_len, len; + + error = nfs_readlink(newfd, linkbuf); + if (error) + goto out; + + link_len = strlen(linkbuf); + len = strlen(cp); + + if (link_len + len > MAXPATHLEN + || ++nlinks > MAXSYMLINKS) { + error = ENOENT; + goto out; + } + + bcopy(cp, &namebuf[link_len], len + 1); + bcopy(linkbuf, namebuf, link_len); + + /* + * If absolute pathname, restart at root. + * If relative pathname, restart at parent directory. + */ + cp = namebuf; + if (*cp == '/') { + if (currfd != &nfs_root_node) + free(currfd); + currfd = &nfs_root_node; + } + + free(newfd); + newfd = 0; + + continue; + } + + if (currfd != &nfs_root_node) + free(currfd); + currfd = newfd; + newfd = 0; + } + + error = 0; + +out: + free(newfd); + free(path); +#else + /* allocate file system specific data structure */ + currfd = malloc(sizeof(*currfd)); + if (currfd != NULL) { + currfd->iodesc = desc; + currfd->off = 0; + + error = nfs_lookupfh(&nfs_root_node, upath, currfd); + } else + error = ENOMEM; +#endif + if (!error) { + f->f_fsdata = (void *)currfd; + return (0); + } + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s lookupfh failed: %s\n", + path, strerror(error)); +#endif +#ifndef NFS_NOSYMLINK + if (currfd != &nfs_root_node) +#endif + free(currfd); + + return (error); +} + +int +nfs_close(struct open_file *f) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_close: fp=0x%lx\n", (u_long)fp); +#endif + + if (fp != &nfs_root_node && fp) + free(fp); + f->f_fsdata = (void *)0; + + return (0); +} + +/* + * read a portion of a file + */ +int +nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + ssize_t cc; + char *addr = buf; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: size=%lu off=%d\n", (u_long)size, + (int)fp->off); +#endif + while ((int)size > 0) { + twiddle(); + cc = nfs_readdata(fp, fp->off, (void *)addr, size); + /* XXX maybe should retry on certain errors */ + if (cc == -1) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: read: %s", strerror(errno)); +#endif + return (errno); /* XXX - from nfs_readdata */ + } + if (cc == 0) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: hit EOF unexpectantly"); +#endif + goto ret; + } + fp->off += cc; + addr += cc; + size -= cc; + } +ret: + if (resid) + *resid = size; + + return (0); +} + +/* + * Not implemented. + */ +int +nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid) +{ + return (EROFS); +} + +off_t +nfs_seek(struct open_file *f, off_t offset, int where) +{ + struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata; + uint32_t size = ntohl(d->fa.fa_size.val[1]); + + switch (where) { + case SEEK_SET: + d->off = offset; + break; + case SEEK_CUR: + d->off += offset; + break; + case SEEK_END: + d->off = size - offset; + break; + default: + errno = EINVAL; + return (-1); + } + + return (d->off); +} + +/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */ +int nfs_stat_types[9] = { + 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 }; + +int +nfs_stat(struct open_file *f, struct stat *sb) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + uint32_t ftype, mode; + + ftype = ntohl(fp->fa.fa_type); + mode = ntohl(fp->fa.fa_mode); + mode |= nfs_stat_types[ftype & 7]; + + sb->st_mode = mode; + sb->st_nlink = ntohl(fp->fa.fa_nlink); + sb->st_uid = ntohl(fp->fa.fa_uid); + sb->st_gid = ntohl(fp->fa.fa_gid); + sb->st_size = ntohl(fp->fa.fa_size.val[1]); + + return (0); +} + +static int +nfs_readdir(struct open_file *f, struct dirent *d) +{ + struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + struct nfsv3_readdir_repl *repl; + struct nfsv3_readdir_entry *rent; + static char *buf; + static uint32_t cookie0 = 0; + static uint32_t cookie1 = 0; + size_t cc; + static uint32_t cookieverf0 = 0; + static uint32_t cookieverf1 = 0; + int pos; + + struct args { + uint32_t fhsize; + uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE]; + } *args; + struct { + uint32_t h[RPC_HEADER_WORDS]; + struct args d; + } sdata; + static struct { + uint32_t h[RPC_HEADER_WORDS]; + u_char d[NFS_READDIRSIZE]; + } rdata; + + if (cookie0 == 0 && cookie1 == 0) { + refill: + args = &sdata.d; + bzero(args, sizeof(*args)); + + args->fhsize = htonl(fp->fhsize); + bcopy(fp->fh, args->fhpluscookie, fp->fhsize); + pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t); + args->fhpluscookie[pos++] = cookie0; + args->fhpluscookie[pos++] = cookie1; + args->fhpluscookie[pos++] = cookieverf0; + args->fhpluscookie[pos++] = cookieverf1; + args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE); + + cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR, + args, 6 * sizeof(uint32_t) + + roundup(fp->fhsize, sizeof(uint32_t)), + rdata.d, sizeof(rdata.d)); + buf = rdata.d; + repl = (struct nfsv3_readdir_repl *)buf; + if (repl->errno != 0) + return (ntohl(repl->errno)); + cookieverf0 = repl->cookiev0; + cookieverf1 = repl->cookiev1; + buf += sizeof (struct nfsv3_readdir_repl); + } + rent = (struct nfsv3_readdir_entry *)buf; + + if (rent->follows == 0) { + /* fid0 is actually eof */ + if (rent->fid0 != 0) { + cookie0 = 0; + cookie1 = 0; + cookieverf0 = 0; + cookieverf1 = 0; + return (ENOENT); + } + goto refill; + } + + d->d_namlen = ntohl(rent->len); + bcopy(rent->nameplus, d->d_name, d->d_namlen); + d->d_name[d->d_namlen] = '\0'; + + pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t); + cookie0 = rent->nameplus[pos++]; + cookie1 = rent->nameplus[pos++]; + buf = (u_char *)&rent->nameplus[pos]; + return (0); +} +#endif /* OLD_NFSV2 */ diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index b2948646205..952a70b87ab 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -338,19 +338,16 @@ ENTRY(savectx) movl $MSR_FSBASE,%ecx rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%rax - movq %rax,PCB_FSBASE(%rdi) + movl %eax,PCB_FSBASE(%rdi) + movl %edx,PCB_FSBASE+4(%rdi) movl $MSR_GSBASE,%ecx rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%rax - movq %rax,PCB_GSBASE(%rdi) + movl %eax,PCB_GSBASE(%rdi) + movl %edx,PCB_GSBASE+4(%rdi) movl $MSR_KGSBASE,%ecx rdmsr - shlq $32,%rdx - leaq (%rax,%rdx),%rax - movq %rax,PCB_KGSBASE(%rdi) + movl %eax,PCB_KGSBASE(%rdi) + movl %edx,PCB_KGSBASE+4(%rdi) sgdt PCB_GDT(%rdi) sidt PCB_IDT(%rdi) diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S index c18f27f8e40..37e89a00744 100644 --- a/sys/amd64/amd64/exception.S +++ b/sys/amd64/amd64/exception.S @@ -108,6 +108,10 @@ IDTVEC(dbg) TRAP_NOEN(T_TRCTRAP) IDTVEC(bpt) TRAP_NOEN(T_BPTFLT) +#ifdef KDTRACE_HOOKS +IDTVEC(dtrace_ret) + TRAP_NOEN(T_DTRACE_RET) +#endif /* Regular traps; The cpu does not supply tf_err for these. */ #define TRAP(a) \ diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c index b188c97643b..7e4319e79b3 100644 --- a/sys/amd64/amd64/identcpu.c +++ b/sys/amd64/amd64/identcpu.c @@ -278,7 +278,7 @@ printcpuinfo(void) "\017xTPR" /* Send Task Priority Messages*/ "\020PDCM" /* Perf/Debug Capability MSR */ "\021" - "\022" + "\022PCID" /* Process-context Identifiers */ "\023DCA" /* Direct Cache Access */ "\024SSE4.1" "\025SSE4.2" diff --git a/sys/amd64/amd64/legacy.c b/sys/amd64/amd64/legacy.c index 9aa0365d26b..4123f84e224 100644 --- a/sys/amd64/amd64/legacy.c +++ b/sys/amd64/amd64/legacy.c @@ -60,7 +60,7 @@ struct legacy_device { static int legacy_probe(device_t); static int legacy_attach(device_t); static int legacy_print_child(device_t, device_t); -static device_t legacy_add_child(device_t bus, int order, const char *name, +static device_t legacy_add_child(device_t bus, u_int order, const char *name, int unit); static int legacy_read_ivar(device_t, device_t, int, uintptr_t *); static int legacy_write_ivar(device_t, device_t, int, uintptr_t); @@ -149,7 +149,7 @@ legacy_print_child(device_t bus, device_t child) } static device_t -legacy_add_child(device_t bus, int order, const char *name, int unit) +legacy_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct legacy_device *atdev; @@ -213,7 +213,7 @@ legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value) static void cpu_identify(driver_t *driver, device_t parent); static int cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result); -static device_t cpu_add_child(device_t bus, int order, const char *name, +static device_t cpu_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource_list *cpu_get_rlist(device_t dev, device_t child); @@ -277,7 +277,7 @@ cpu_identify(driver_t *driver, device_t parent) } static device_t -cpu_add_child(device_t bus, int order, const char *name, int unit) +cpu_add_child(device_t bus, u_int order, const char *name, int unit) { struct cpu_device *cd; device_t child; diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 6bec71b5be6..61a2cf879b2 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include "opt_msgbuf.h" #include "opt_perfmon.h" #include "opt_sched.h" +#include "opt_kdtrace.h" #include #include @@ -584,59 +585,89 @@ cpu_halt(void) } void (*cpu_idle_hook)(void) = NULL; /* ACPI idle hook. */ +static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ +static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ +TUNABLE_INT("machdep.idle_mwait", &idle_mwait); +SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, + 0, "Use MONITOR/MWAIT for short idle"); -static void -cpu_idle_hlt(int busy) -{ - /* - * we must absolutely guarentee that hlt is the next instruction - * after sti or we introduce a timing window. - */ - disable_intr(); - if (sched_runnable()) - enable_intr(); - else - __asm __volatile("sti; hlt"); -} +#define STATE_RUNNING 0x0 +#define STATE_MWAIT 0x1 +#define STATE_SLEEPING 0x2 static void cpu_idle_acpi(int busy) { + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_SLEEPING; disable_intr(); - if (sched_runnable()) + if (sched_runnable()) enable_intr(); else if (cpu_idle_hook) cpu_idle_hook(); else __asm __volatile("sti; hlt"); + *state = STATE_RUNNING; } -static int cpu_ident_amdc1e = 0; - -static int -cpu_probe_amdc1e(void) +static void +cpu_idle_hlt(int busy) { + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_SLEEPING; + /* + * We must absolutely guarentee that hlt is the next instruction + * after sti or we introduce a timing window. + */ + disable_intr(); + if (sched_runnable()) + enable_intr(); + else + __asm __volatile("sti; hlt"); + *state = STATE_RUNNING; +} + +/* + * MWAIT cpu power states. Lower 4 bits are sub-states. + */ +#define MWAIT_C0 0xf0 +#define MWAIT_C1 0x00 +#define MWAIT_C2 0x10 +#define MWAIT_C3 0x20 +#define MWAIT_C4 0x30 + +static void +cpu_idle_mwait(int busy) +{ + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_MWAIT; + if (!sched_runnable()) { + cpu_monitor(state, 0, 0); + if (*state == STATE_MWAIT) + cpu_mwait(0, MWAIT_C1); + } + *state = STATE_RUNNING; +} + +static void +cpu_idle_spin(int busy) +{ + int *state; int i; - /* - * Forget it, if we're not using local APIC timer. - */ - if (resource_disabled("apic", 0) || - (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0)) - return (0); - - /* - * Detect the presence of C1E capability mostly on latest - * dual-cores (or future) k8 family. - */ - if (cpu_vendor_id == CPU_VENDOR_AMD && - (cpu_id & 0x00000f00) == 0x00000f00 && - (cpu_id & 0x0fff0000) >= 0x00040000) { - cpu_ident_amdc1e = 1; - return (1); + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_RUNNING; + for (i = 0; i < 1000; i++) { + if (sched_runnable()) + return; + cpu_spinwait(); } - - return (0); } /* @@ -654,110 +685,83 @@ cpu_probe_amdc1e(void) #define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT) static void -cpu_idle_amdc1e(int busy) +cpu_probe_amdc1e(void) { - disable_intr(); - if (sched_runnable()) - enable_intr(); - else { - uint64_t msr; - - msr = rdmsr(MSR_AMDK8_IPM); - if (msr & AMDK8_CMPHALT) - wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); - - if (cpu_idle_hook) - cpu_idle_hook(); - else - __asm __volatile("sti; hlt"); + /* + * Detect the presence of C1E capability mostly on latest + * dual-cores (or future) k8 family. + */ + if (cpu_vendor_id == CPU_VENDOR_AMD && + (cpu_id & 0x00000f00) == 0x00000f00 && + (cpu_id & 0x0fff0000) >= 0x00040000) { + cpu_ident_amdc1e = 1; } } -static void -cpu_idle_spin(int busy) -{ - return; -} - void (*cpu_idle_fn)(int) = cpu_idle_acpi; void cpu_idle(int busy) { + uint64_t msr; + + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", + busy, curcpu); #ifdef SMP if (mp_grab_cpu_hlt()) return; #endif - cpu_idle_fn(busy); -} - -/* - * mwait cpu power states. Lower 4 bits are sub-states. - */ -#define MWAIT_C0 0xf0 -#define MWAIT_C1 0x00 -#define MWAIT_C2 0x10 -#define MWAIT_C3 0x20 -#define MWAIT_C4 0x30 - -#define MWAIT_DISABLED 0x0 -#define MWAIT_WOKEN 0x1 -#define MWAIT_WAITING 0x2 - -static void -cpu_idle_mwait(int busy) -{ - int *mwait; - - mwait = (int *)PCPU_PTR(monitorbuf); - *mwait = MWAIT_WAITING; - if (sched_runnable()) - return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); -} - -static void -cpu_idle_mwait_hlt(int busy) -{ - int *mwait; - - mwait = (int *)PCPU_PTR(monitorbuf); - if (busy == 0) { - *mwait = MWAIT_DISABLED; - cpu_idle_hlt(busy); - return; + /* If we are busy - try to use fast methods. */ + if (busy) { + if ((cpu_feature2 & CPUID2_MON) && idle_mwait) { + cpu_idle_mwait(busy); + goto out; + } } - *mwait = MWAIT_WAITING; - if (sched_runnable()) - return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); + + /* If we have time - switch timers into idle mode. */ + if (!busy) { + critical_enter(); + cpu_idleclock(); + } + + /* Apply AMD APIC timer C1E workaround. */ + if (cpu_ident_amdc1e && cpu_disable_deep_sleep) { + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + } + + /* Call main idle method. */ + cpu_idle_fn(busy); + + /* Switch timers mack into active mode. */ + if (!busy) { + cpu_activeclock(); + critical_exit(); + } +out: + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", + busy, curcpu); } int cpu_idle_wakeup(int cpu) { struct pcpu *pcpu; - int *mwait; + int *state; - if (cpu_idle_fn == cpu_idle_spin) - return (1); - if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt) - return (0); pcpu = pcpu_find(cpu); - mwait = (int *)pcpu->pc_monitorbuf; + state = (int *)pcpu->pc_monitorbuf; /* * This doesn't need to be atomic since missing the race will * simply result in unnecessary IPIs. */ - if (cpu_idle_fn == cpu_idle_mwait_hlt && *mwait == MWAIT_DISABLED) + if (*state == STATE_SLEEPING) return (0); - *mwait = MWAIT_WOKEN; - + if (*state == STATE_MWAIT) + *state = STATE_RUNNING; return (1); } @@ -770,8 +774,6 @@ struct { } idle_tbl[] = { { cpu_idle_spin, "spin" }, { cpu_idle_mwait, "mwait" }, - { cpu_idle_mwait_hlt, "mwait_hlt" }, - { cpu_idle_amdc1e, "amdc1e" }, { cpu_idle_hlt, "hlt" }, { cpu_idle_acpi, "acpi" }, { NULL, NULL } @@ -790,16 +792,20 @@ idle_sysctl_available(SYSCTL_HANDLER_ARGS) if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; - if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 && - cpu_ident_amdc1e == 0) + if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && + cpu_idle_hook == NULL) continue; - p += sprintf(p, "%s, ", idle_tbl[i].id_name); + p += sprintf(p, "%s%s", p != avail ? ", " : "", + idle_tbl[i].id_name); } error = sysctl_handle_string(oidp, avail, 0, req); free(avail, M_TEMP); return (error); } +SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, idle_sysctl_available, "A", "list of available idle functions"); + static int idle_sysctl(SYSCTL_HANDLER_ARGS) { @@ -823,8 +829,8 @@ idle_sysctl(SYSCTL_HANDLER_ARGS) if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; - if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 && - cpu_ident_amdc1e == 0) + if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && + cpu_idle_hook == NULL) continue; if (strcmp(idle_tbl[i].id_name, buf)) continue; @@ -834,9 +840,6 @@ idle_sysctl(SYSCTL_HANDLER_ARGS) return (EINVAL); } -SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, - 0, 0, idle_sysctl_available, "A", "list of available idle functions"); - SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, idle_sysctl, "A", "currently selected idle function"); @@ -1089,6 +1092,9 @@ extern inthand_t IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), IDTVEC(xmm), IDTVEC(dblfault), +#ifdef KDTRACE_HOOKS + IDTVEC(dtrace_ret), +#endif IDTVEC(fast_syscall), IDTVEC(fast_syscall32); #ifdef DDB @@ -1617,6 +1623,9 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) setidt(IDT_AC, &IDTVEC(align), SDT_SYSIGT, SEL_KPL, 0); setidt(IDT_MC, &IDTVEC(mchk), SDT_SYSIGT, SEL_KPL, 0); setidt(IDT_XF, &IDTVEC(xmm), SDT_SYSIGT, SEL_KPL, 0); +#ifdef KDTRACE_HOOKS + setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), SDT_SYSIGT, SEL_UPL, 0); +#endif r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (long) idt; @@ -1736,8 +1745,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) } #endif - if (cpu_probe_amdc1e()) - cpu_idle_fn = cpu_idle_amdc1e; + cpu_probe_amdc1e(); /* Location of kernel stack for locore */ return ((u_int64_t)thread0.td_pcb); @@ -1792,7 +1800,7 @@ makectx(struct trapframe *tf, struct pcb *pcb) pcb->pcb_rbp = tf->tf_rbp; pcb->pcb_rbx = tf->tf_rbx; pcb->pcb_rip = tf->tf_rip; - pcb->pcb_rsp = (ISPL(tf->tf_cs)) ? tf->tf_rsp : (long)(tf + 1) - 8; + pcb->pcb_rsp = tf->tf_rsp; } int diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index 034ae77cc82..c509b67974b 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -118,7 +118,6 @@ u_long *ipi_invlcache_counts[MAXCPU]; u_long *ipi_rendezvous_counts[MAXCPU]; u_long *ipi_lazypmap_counts[MAXCPU]; static u_long *ipi_hardclock_counts[MAXCPU]; -static u_long *ipi_statclock_counts[MAXCPU]; #endif extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32); @@ -127,7 +126,6 @@ extern inthand_t IDTVEC(fast_syscall), IDTVEC(fast_syscall32); * Local data and functions. */ -static cpumask_t logical_cpus; static volatile cpumask_t ipi_nmi_pending; /* used to hold the AP's until we are ready to release them */ @@ -153,8 +151,8 @@ int apic_cpuids[MAX_APIC_ID + 1]; static volatile u_int cpu_ipi_pending[MAXCPU]; static u_int boot_address; -static int cpu_logical; -static int cpu_cores; +static int cpu_logical; /* logical cpus per core */ +static int cpu_cores; /* cores per package */ static void assign_cpu_ids(void); static void set_interrupt_apic_ids(void); @@ -162,8 +160,8 @@ static int start_all_aps(void); static int start_ap(int apic_id); static void release_aps(void *dummy); -static cpumask_t hlt_logical_cpus; -static cpumask_t hyperthreading_cpus; +static int hlt_logical_cpus; +static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */ static cpumask_t hyperthreading_cpus_mask; static int hyperthreading_allowed = 1; static struct sysctl_ctx_list logical_cpu_clist; @@ -176,25 +174,106 @@ mem_range_AP_init(void) mem_range_softc.mr_op->initAP(&mem_range_softc); } +static void +topo_probe_amd(void) +{ + + /* AMD processors do not support HTT. */ + cpu_cores = (amd_feature2 & AMDID2_CMP) != 0 ? + (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; + cpu_logical = 1; +} + +/* + * Round up to the next power of two, if necessary, and then + * take log2. + * Returns -1 if argument is zero. + */ +static __inline int +mask_width(u_int x) +{ + + return (fls(x << (1 - powerof2(x))) - 1); +} + +static void +topo_probe_0x4(void) +{ + u_int p[4]; + int pkg_id_bits; + int core_id_bits; + int max_cores; + int max_logical; + int id; + + /* Both zero and one here mean one logical processor per package. */ + max_logical = (cpu_feature & CPUID_HTT) != 0 ? + (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1; + if (max_logical <= 1) + return; + + /* + * Because of uniformity assumption we examine only + * those logical processors that belong to the same + * package as BSP. Further, we count number of + * logical processors that belong to the same core + * as BSP thus deducing number of threads per core. + */ + cpuid_count(0x04, 0, p); + max_cores = ((p[0] >> 26) & 0x3f) + 1; + core_id_bits = mask_width(max_logical/max_cores); + if (core_id_bits < 0) + return; + pkg_id_bits = core_id_bits + mask_width(max_cores); + + for (id = 0; id <= MAX_APIC_ID; id++) { + /* Check logical CPU availability. */ + if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled) + continue; + /* Check if logical CPU has the same package ID. */ + if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits)) + continue; + cpu_cores++; + /* Check if logical CPU has the same package and core IDs. */ + if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits)) + cpu_logical++; + } + + cpu_cores /= cpu_logical; + hyperthreading_cpus = cpu_logical; +} + static void topo_probe_0xb(void) { - int logical; - int p[4]; + u_int p[4]; int bits; - int type; int cnt; int i; + int logical; + int type; int x; - /* We only support two levels for now. */ + /* We only support three levels for now. */ for (i = 0; i < 3; i++) { - cpuid_count(0x0B, i, p); + cpuid_count(0x0b, i, p); + + /* Fall back if CPU leaf 11 doesn't really exist. */ + if (i == 0 && p[1] == 0) { + topo_probe_0x4(); + return; + } + bits = p[0] & 0x1f; logical = p[1] &= 0xffff; type = (p[2] >> 8) & 0xff; if (type == 0 || logical == 0) break; + /* + * Because of uniformity assumption we examine only + * those logical processors that belong to the same + * package as BSP. + */ for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) { if (!cpu_info[x].cpu_present || cpu_info[x].cpu_disabled) @@ -212,76 +291,16 @@ topo_probe_0xb(void) cpu_cores /= cpu_logical; } -static void -topo_probe_0x4(void) -{ - u_int threads_per_cache, p[4]; - u_int htt, cmp; - int i; - - htt = cmp = 1; - /* - * If this CPU supports HTT or CMP then mention the - * number of physical/logical cores it contains. - */ - if (cpu_feature & CPUID_HTT) - htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - if (cpu_vendor_id == CPU_VENDOR_AMD && (amd_feature2 & AMDID2_CMP)) - cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; - else if (cpu_vendor_id == CPU_VENDOR_INTEL && (cpu_high >= 4)) { - cpuid_count(4, 0, p); - if ((p[0] & 0x1f) != 0) - cmp = ((p[0] >> 26) & 0x3f) + 1; - } - cpu_cores = cmp; - cpu_logical = htt / cmp; - - /* Setup the initial logical CPUs info. */ - if (cpu_feature & CPUID_HTT) - logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - - /* - * Work out if hyperthreading is *really* enabled. This - * is made really ugly by the fact that processors lie: Dual - * core processors claim to be hyperthreaded even when they're - * not, presumably because they want to be treated the same - * way as HTT with respect to per-cpu software licensing. - * At the time of writing (May 12, 2005) the only hyperthreaded - * cpus are from Intel, and Intel's dual-core processors can be - * identified via the "deterministic cache parameters" cpuid - * calls. - */ - /* - * First determine if this is an Intel processor which claims - * to have hyperthreading support. - */ - if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) { - /* - * If the "deterministic cache parameters" cpuid calls - * are available, use them. - */ - if (cpu_high >= 4) { - /* Ask the processor about the L1 cache. */ - for (i = 0; i < 1; i++) { - cpuid_count(4, i, p); - threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1; - if (hyperthreading_cpus < threads_per_cache) - hyperthreading_cpus = threads_per_cache; - if ((p[0] & 0x1f) == 0) - break; - } - } - - /* - * If the deterministic cache parameters are not - * available, or if no caches were reported to exist, - * just accept what the HTT flag indicated. - */ - if (hyperthreading_cpus == 0) - hyperthreading_cpus = logical_cpus; - } -} - +/* + * Both topology discovery code and code that consumes topology + * information assume top-down uniformity of the topology. + * That is, all physical packages must be identical and each + * core in a package must have the same number of threads. + * Topology information is queried only on BSP, on which this + * code runs and for which it can query CPUID information. + * Then topology is extrapolated on all packages using the + * uniformity assumption. + */ static void topo_probe(void) { @@ -290,13 +309,31 @@ topo_probe(void) if (cpu_topo_probed) return; - logical_cpus = logical_cpus_mask = 0; - if (cpu_high >= 0xb) - topo_probe_0xb(); - else if (cpu_high) - topo_probe_0x4(); + logical_cpus_mask = 0; + if (cpu_vendor_id == CPU_VENDOR_AMD) + topo_probe_amd(); + else if (cpu_vendor_id == CPU_VENDOR_INTEL) { + /* + * See Intel(R) 64 Architecture Processor + * Topology Enumeration article for details. + * + * Note that 0x1 <= cpu_high < 4 case should be + * compatible with topo_probe_0x4() logic when + * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1) + * or it should trigger the fallback otherwise. + */ + if (cpu_high >= 0xb) + topo_probe_0xb(); + else if (cpu_high >= 0x1) + topo_probe_0x4(); + } + + /* + * Fallback: assume each logical CPU is in separate + * physical package. That is, no multi-core, no SMT. + */ if (cpu_cores == 0) - cpu_cores = mp_ncpus > 0 ? mp_ncpus : 1; + cpu_cores = 1; if (cpu_logical == 0) cpu_logical = 1; cpu_topo_probed = 1; @@ -676,7 +713,8 @@ init_secondary(void) printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid)); /* Determine if we are a logical CPU. */ - if (logical_cpus > 1 && PCPU_GET(apic_id) % logical_cpus != 0) + /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */ + if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0) logical_cpus_mask |= PCPU_GET(cpumask); /* Determine if we are a hyperthread. */ @@ -1196,16 +1234,22 @@ smp_masked_invlpg_range(cpumask_t mask, vm_offset_t addr1, vm_offset_t addr2) void ipi_bitmap_handler(struct trapframe frame) { + struct trapframe *oldframe; + struct thread *td; int cpu = PCPU_GET(cpuid); u_int ipi_bitmap; + critical_enter(); + td = curthread; + td->td_intr_nesting_level++; + oldframe = td->td_intr_frame; + td->td_intr_frame = &frame; ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]); - if (ipi_bitmap & (1 << IPI_PREEMPT)) { #ifdef COUNT_IPIS (*ipi_preempt_counts[cpu])++; #endif - sched_preempt(curthread); + sched_preempt(td); } if (ipi_bitmap & (1 << IPI_AST)) { #ifdef COUNT_IPIS @@ -1217,14 +1261,11 @@ ipi_bitmap_handler(struct trapframe frame) #ifdef COUNT_IPIS (*ipi_hardclock_counts[cpu])++; #endif - hardclockintr(&frame); - } - if (ipi_bitmap & (1 << IPI_STATCLOCK)) { -#ifdef COUNT_IPIS - (*ipi_statclock_counts[cpu])++; -#endif - statclockintr(&frame); + hardclockintr(); } + td->td_intr_frame = oldframe; + td->td_intr_nesting_level--; + critical_exit(); } /* @@ -1579,8 +1620,6 @@ mp_ipi_intrcnt(void *dummy) intrcnt_add(buf, &ipi_lazypmap_counts[i]); snprintf(buf, sizeof(buf), "cpu%d:hardclock", i); intrcnt_add(buf, &ipi_hardclock_counts[i]); - snprintf(buf, sizeof(buf), "cpu%d:statclock", i); - intrcnt_add(buf, &ipi_statclock_counts[i]); } } SYSINIT(mp_ipi_intrcnt, SI_SUB_INTR, SI_ORDER_MIDDLE, mp_ipi_intrcnt, NULL); diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c index 4c701a0e9d3..037d4ac4e72 100644 --- a/sys/amd64/amd64/nexus.c +++ b/sys/amd64/amd64/nexus.c @@ -83,7 +83,7 @@ static int nexus_probe(device_t); static int nexus_attach(device_t); static int nexus_print_all_resources(device_t dev); static int nexus_print_child(device_t, device_t); -static device_t nexus_add_child(device_t bus, int order, const char *name, +static device_t nexus_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -293,7 +293,7 @@ nexus_print_child(device_t bus, device_t child) } static device_t -nexus_add_child(device_t bus, int order, const char *name, int unit) +nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index ca575085f65..020391756d8 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -620,7 +620,8 @@ pmap_init_pat(void) if (sysenv != NULL) { if (strncmp(sysenv, "MacBook5,1", 10) == 0 || strncmp(sysenv, "MacBookPro5,5", 13) == 0 || - strncmp(sysenv, "Macmini3,1", 10) == 0) + strncmp(sysenv, "Macmini3,1", 10) == 0 || + strncmp(sysenv, "iMac9,1", 7) == 0) pat_works = 0; freeenv(sysenv); } @@ -1162,26 +1163,33 @@ pmap_is_current(pmap_t pmap) vm_paddr_t pmap_extract(pmap_t pmap, vm_offset_t va) { - vm_paddr_t rtval; + pdp_entry_t *pdpe; + pd_entry_t *pde; pt_entry_t *pte; - pd_entry_t pde, *pdep; + vm_paddr_t pa; - rtval = 0; + pa = 0; PMAP_LOCK(pmap); - pdep = pmap_pde(pmap, va); - if (pdep != NULL) { - pde = *pdep; - if (pde) { - if ((pde & PG_PS) != 0) - rtval = (pde & PG_PS_FRAME) | (va & PDRMASK); - else { - pte = pmap_pde_to_pte(pdep, va); - rtval = (*pte & PG_FRAME) | (va & PAGE_MASK); + pdpe = pmap_pdpe(pmap, va); + if (pdpe != NULL && (*pdpe & PG_V) != 0) { + if ((*pdpe & PG_PS) != 0) + pa = (*pdpe & PG_PS_FRAME) | (va & PDPMASK); + else { + pde = pmap_pdpe_to_pde(pdpe, va); + if ((*pde & PG_V) != 0) { + if ((*pde & PG_PS) != 0) { + pa = (*pde & PG_PS_FRAME) | + (va & PDRMASK); + } else { + pte = pmap_pde_to_pte(pde, va); + pa = (*pte & PG_FRAME) | + (va & PAGE_MASK); + } } } } PMAP_UNLOCK(pmap); - return (rtval); + return (pa); } /* diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 36425547ff7..69e94d95f90 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include "opt_isa.h" #include "opt_kdb.h" #include "opt_kdtrace.h" -#include "opt_ktrace.h" #include #include @@ -70,9 +69,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#endif #ifdef HWPMC_HOOKS #include #endif @@ -113,6 +109,13 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func; * implementation opaque. */ systrace_probe_func_t systrace_probe_func; + +/* + * These hooks are necessary for the pid, usdt and fasttrap providers. + */ +dtrace_fasttrap_probe_ptr_t dtrace_fasttrap_probe_ptr; +dtrace_pid_probe_ptr_t dtrace_pid_probe_ptr; +dtrace_return_probe_ptr_t dtrace_return_probe_ptr; #endif extern void trap(struct trapframe *frame); @@ -243,6 +246,55 @@ trap(struct trapframe *frame) if (dtrace_trap_func != NULL) if ((*dtrace_trap_func)(frame, type)) goto out; + if (type == T_DTRACE_PROBE || type == T_DTRACE_RET || + type == T_BPTFLT) { + struct reg regs; + + regs.r_r15 = frame->tf_r15; + regs.r_r14 = frame->tf_r14; + regs.r_r13 = frame->tf_r13; + regs.r_r12 = frame->tf_r12; + regs.r_r11 = frame->tf_r11; + regs.r_r10 = frame->tf_r10; + regs.r_r9 = frame->tf_r9; + regs.r_r8 = frame->tf_r8; + regs.r_rdi = frame->tf_rdi; + regs.r_rsi = frame->tf_rsi; + regs.r_rbp = frame->tf_rbp; + regs.r_rbx = frame->tf_rbx; + regs.r_rdx = frame->tf_rdx; + regs.r_rcx = frame->tf_rcx; + regs.r_rax = frame->tf_rax; + regs.r_rip = frame->tf_rip; + regs.r_cs = frame->tf_cs; + regs.r_rflags = frame->tf_rflags; + regs.r_rsp = frame->tf_rsp; + regs.r_ss = frame->tf_ss; + if (frame->tf_flags & TF_HASSEGS) { + regs.r_ds = frame->tf_ds; + regs.r_es = frame->tf_es; + regs.r_fs = frame->tf_fs; + regs.r_gs = frame->tf_gs; + } else { + regs.r_ds = 0; + regs.r_es = 0; + regs.r_fs = 0; + regs.r_gs = 0; + } + if (type == T_DTRACE_PROBE && + dtrace_fasttrap_probe_ptr != NULL && + dtrace_fasttrap_probe_ptr(®s) == 0) + goto out; + if (type == T_BPTFLT && + dtrace_pid_probe_ptr != NULL && + dtrace_pid_probe_ptr(®s) == 0) + goto out; + if (type == T_DTRACE_RET && + dtrace_return_probe_ptr != NULL && + dtrace_return_probe_ptr(®s) == 0) + goto out; + + } #endif if ((frame->tf_rflags & PSL_I) == 0) { diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index e7873e93cd6..3bc62996893 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -55,7 +55,6 @@ options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options KBD_INSTALL_CDEV # install a CDEV entry in /dev @@ -112,6 +111,7 @@ device hptiop # Highpoint RocketRaid 3xxx series device isp # Qlogic family #device ispfw # Firmware for QLogic HBAs- normally a module device mpt # LSI-Logic MPT-Fusion +device mps # LSI-Logic MPT-Fusion 2 #device ncr # NCR/Symbios Logic device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') device trm # Tekram DC395U/UW/F DC315U adapters diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES index 67fbcd7460e..e69e4ad8890 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -421,6 +421,7 @@ options SAFE_RNDTEST # enable rndtest support # vpd: Vital Product Data kernel interface # asmc: Apple System Management Controller # si: Specialix International SI/XIO or SX intelligent serial card +# tpm: Trusted Platform Module # Notes on the Specialix SI/XIO driver: # The host card is memory, not IO mapped. @@ -436,6 +437,7 @@ device smbios device vpd device asmc #device si +device tpm # # Laptop/Notebook options: diff --git a/sys/amd64/ia32/ia32_syscall.c b/sys/amd64/ia32/ia32_syscall.c index 6a649aeeb19..9a3488e6ac2 100644 --- a/sys/amd64/ia32/ia32_syscall.c +++ b/sys/amd64/ia32/ia32_syscall.c @@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$"); #include "opt_clock.h" #include "opt_cpu.h" #include "opt_isa.h" -#include "opt_ktrace.h" #include #include @@ -65,9 +64,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#endif #include #include diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h index 2ebf7c2582f..ae2f5b90791 100644 --- a/sys/amd64/include/apicvar.h +++ b/sys/amd64/include/apicvar.h @@ -123,8 +123,7 @@ #define IPI_AST 0 /* Generate software trap. */ #define IPI_PREEMPT 1 #define IPI_HARDCLOCK 2 -#define IPI_STATCLOCK 3 -#define IPI_BITMAP_LAST IPI_STATCLOCK +#define IPI_BITMAP_LAST IPI_HARDCLOCK #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST) #define IPI_STOP (APIC_IPI_INTS + 7) /* Stop CPU until restarted. */ diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h index 123e2faea81..a991e3870ae 100644 --- a/sys/amd64/include/cpufunc.h +++ b/sys/amd64/include/cpufunc.h @@ -421,40 +421,40 @@ invlpg(u_long addr) __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory"); } -static __inline u_int +static __inline u_short rfs(void) { - u_int sel; - __asm __volatile("mov %%fs,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%fs,%0" : "=rm" (sel)); return (sel); } -static __inline u_int +static __inline u_short rgs(void) { - u_int sel; - __asm __volatile("mov %%gs,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%gs,%0" : "=rm" (sel)); return (sel); } -static __inline u_int +static __inline u_short rss(void) { - u_int sel; - __asm __volatile("mov %%ss,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%ss,%0" : "=rm" (sel)); return (sel); } static __inline void -load_ds(u_int sel) +load_ds(u_short sel) { - __asm __volatile("mov %0,%%ds" : : "rm" (sel)); + __asm __volatile("movw %0,%%ds" : : "rm" (sel)); } static __inline void -load_es(u_int sel) +load_es(u_short sel) { - __asm __volatile("mov %0,%%es" : : "rm" (sel)); + __asm __volatile("movw %0,%%es" : : "rm" (sel)); } static __inline void @@ -476,10 +476,10 @@ cpu_mwait(int extensions, int hints) #define MSR_FSBASE 0xc0000100 #endif static __inline void -load_fs(u_int sel) +load_fs(u_short sel) { /* Preserve the fsbase value across the selector load */ - __asm __volatile("rdmsr; mov %0,%%fs; wrmsr" + __asm __volatile("rdmsr; movw %0,%%fs; wrmsr" : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx"); } @@ -487,28 +487,28 @@ load_fs(u_int sel) #define MSR_GSBASE 0xc0000101 #endif static __inline void -load_gs(u_int sel) +load_gs(u_short sel) { /* * Preserve the gsbase value across the selector load. * Note that we have to disable interrupts because the gsbase * being trashed happens to be the kernel gsbase at the time. */ - __asm __volatile("pushfq; cli; rdmsr; mov %0,%%gs; wrmsr; popfq" + __asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq" : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx"); } #else /* Usable by userland */ static __inline void -load_fs(u_int sel) +load_fs(u_short sel) { - __asm __volatile("mov %0,%%fs" : : "rm" (sel)); + __asm __volatile("movw %0,%%fs" : : "rm" (sel)); } static __inline void -load_gs(u_int sel) +load_gs(u_short sel) { - __asm __volatile("mov %0,%%gs" : : "rm" (sel)); + __asm __volatile("movw %0,%%gs" : : "rm" (sel)); } #endif @@ -692,8 +692,8 @@ void load_dr4(u_int64_t dr4); void load_dr5(u_int64_t dr5); void load_dr6(u_int64_t dr6); void load_dr7(u_int64_t dr7); -void load_fs(u_int sel); -void load_gs(u_int sel); +void load_fs(u_short sel); +void load_gs(u_short sel); void ltr(u_short sel); void outb(u_int port, u_char data); void outl(u_int port, u_int data); diff --git a/sys/amd64/include/elf.h b/sys/amd64/include/elf.h index 678f5d3ba0f..1f5c754d663 100644 --- a/sys/amd64/include/elf.h +++ b/sys/amd64/include/elf.h @@ -88,8 +88,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ /* * Relocation types. diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 282c1aeda15..22dc95ab057 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -214,6 +214,7 @@ struct region_descriptor { #define IDT_XF 19 /* #XF: SIMD Floating-Point Exception */ #define IDT_IO_INTS NRSVIDT /* Base of IDT entries for I/O interrupts. */ #define IDT_SYSCALL 0x80 /* System Call Interrupt Vector */ +#define IDT_DTRACE_RET 0x92 /* DTrace pid provider Interrupt Vector */ /* * Entries in the Global Descriptor Table (GDT) diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h index 4af459423be..4fb92cba144 100644 --- a/sys/amd64/include/specialreg.h +++ b/sys/amd64/include/specialreg.h @@ -126,6 +126,7 @@ #define CPUID2_CX16 0x00002000 #define CPUID2_XTPR 0x00004000 #define CPUID2_PDCM 0x00008000 +#define CPUID2_PCID 0x00020000 #define CPUID2_DCA 0x00040000 #define CPUID2_SSE41 0x00080000 #define CPUID2_SSE42 0x00100000 diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h index f0176b2c97e..d8e36b5aaf3 100644 --- a/sys/amd64/include/trap.h +++ b/sys/amd64/include/trap.h @@ -62,6 +62,8 @@ #define T_MCHK 28 /* machine check trap */ #define T_XMMFLT 29 /* SIMD floating-point exception */ #define T_RESERVED 30 /* reserved (unknown) */ +#define T_DTRACE_RET 31 /* DTrace pid return */ +#define T_DTRACE_PROBE 32 /* DTrace fasttrap probe */ /* XXX most of the following codes aren't used, but could be. */ diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h index f86b184d7b6..dd0c0c9b555 100644 --- a/sys/amd64/include/vmparam.h +++ b/sys/amd64/include/vmparam.h @@ -205,7 +205,7 @@ * is the total KVA space allocated for kmem_map. */ #ifndef VM_KMEM_SIZE_SCALE -#define VM_KMEM_SIZE_SCALE (3) +#define VM_KMEM_SIZE_SCALE (1) #endif /* diff --git a/sys/amd64/linux32/linux32_proto.h b/sys/amd64/linux32/linux32_proto.h index 2e52467b3a7..56a3741fad8 100644 --- a/sys/amd64/linux32/linux32_proto.h +++ b/sys/amd64/linux32/linux32_proto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 210431 2010-07-23 21:30:33Z kib + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 213544 2010-10-08 07:18:44Z kib */ #ifndef _LINUX_SYSPROTO_H_ diff --git a/sys/amd64/linux32/linux32_syscall.h b/sys/amd64/linux32/linux32_syscall.h index 6c2596b9873..b81db48f95a 100644 --- a/sys/amd64/linux32/linux32_syscall.h +++ b/sys/amd64/linux32/linux32_syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 210431 2010-07-23 21:30:33Z kib + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 213544 2010-10-08 07:18:44Z kib */ #define LINUX_SYS_exit 1 diff --git a/sys/amd64/linux32/linux32_sysent.c b/sys/amd64/linux32/linux32_sysent.c index d054a254e4f..d94078167a5 100644 --- a/sys/amd64/linux32/linux32_sysent.c +++ b/sys/amd64/linux32/linux32_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 210431 2010-07-23 21:30:33Z kib + * created from FreeBSD: head/sys/amd64/linux32/syscalls.master 213544 2010-10-08 07:18:44Z kib */ #include "opt_compat.h" @@ -267,7 +267,7 @@ struct sysent linux_sysent[] = { { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 245 = linux_io_setup */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 246 = linux_io_destroy */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 247 = linux_io_getevents */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = inux_io_submit */ + { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 248 = linux_io_submit */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 249 = linux_io_cancel */ { 0, (sy_call_t *)linux_fadvise64, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 250 = linux_fadvise64 */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 251 = */ diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index b9b182ed0e7..f8719c40ce2 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -1210,4 +1210,4 @@ static moduledata_t linux_elf_mod = { 0 }; -DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index cff2ad763b0..9c89946165c 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -416,7 +416,7 @@ 245 AUE_NULL UNIMPL linux_io_setup 246 AUE_NULL UNIMPL linux_io_destroy 247 AUE_NULL UNIMPL linux_io_getevents -248 AUE_NULL UNIMPL inux_io_submit +248 AUE_NULL UNIMPL linux_io_submit 249 AUE_NULL UNIMPL linux_io_cancel 250 AUE_NULL STD { int linux_fadvise64(void); } 251 AUE_NULL UNIMPL diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index 09c20264819..4b62e9846df 100644 --- a/sys/arm/arm/cpufunc.c +++ b/sys/arm/arm/cpufunc.c @@ -397,7 +397,7 @@ struct cpu_functions sheeva_cpufuncs = { cpufunc_nullop, /* flush_brnchtgt_C */ (void *)cpufunc_nullop, /* flush_brnchtgt_E */ - (void *)cpufunc_nullop, /* sleep */ + sheeva_cpu_sleep, /* sleep */ /* Soft functions */ @@ -1076,6 +1076,9 @@ set_cpufuncs() FC_DCACHE_STREAM_EN | FC_WR_ALLOC_EN | FC_BRANCH_TARG_BUF_DIS | FC_L2CACHE_EN); } + + /* Use powersave on this CPU. */ + cpu_do_powersave = 1; } else cpufuncs = armv5_ec_cpufuncs; diff --git a/sys/arm/arm/cpufunc_asm_sheeva.S b/sys/arm/arm/cpufunc_asm_sheeva.S index a52fbf8b050..d1855470647 100644 --- a/sys/arm/arm/cpufunc_asm_sheeva.S +++ b/sys/arm/arm/cpufunc_asm_sheeva.S @@ -392,3 +392,10 @@ ENTRY(sheeva_control_ext) mcrne p15, 1, r2, c15, c1, 0 /* Write new control register */ mov r0, r3 /* Return old value */ RET + +ENTRY(sheeva_cpu_sleep) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 /* Drain write buffer */ + mcr p15, 0, r0, c7, c0, 4 /* Wait for interrupt */ + mov pc, lr + diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c index 584960f8344..4efca1436f7 100644 --- a/sys/arm/arm/nexus.c +++ b/sys/arm/arm/nexus.c @@ -74,7 +74,7 @@ static struct rman mem_rman; static int nexus_probe(device_t); static int nexus_attach(device_t); static int nexus_print_child(device_t, device_t); -static device_t nexus_add_child(device_t, int, const char *, int); +static device_t nexus_add_child(device_t, u_int, const char *, int); static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static int nexus_activate_resource(device_t, device_t, int, int, @@ -166,7 +166,7 @@ nexus_print_child(device_t bus, device_t child) } static device_t -nexus_add_child(device_t bus, int order, const char *name, int unit) +nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c index 3bcbbe0c98b..f33a692e730 100644 --- a/sys/arm/arm/pmap.c +++ b/sys/arm/arm/pmap.c @@ -3158,8 +3158,6 @@ pmap_remove_all(vm_page_t m) *ptep = 0; PTE_SYNC_CURRENT(pv->pv_pmap, ptep); pmap_free_l2_bucket(pv->pv_pmap, l2b, 1); - if (pv->pv_flags & PVF_WIRED) - pv->pv_pmap->pm_stats.wired_count--; pv->pv_pmap->pm_stats.resident_count--; flags |= pv->pv_flags; } diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c index efc731bd47a..e979dcb7e28 100644 --- a/sys/arm/at91/at91.c +++ b/sys/arm/at91/at91.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2005 Olivier Houchard. All rights reserved. + * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,14 +44,23 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include +#include +#include static struct at91_softc *at91_softc; static void at91_eoi(void *); +extern const struct pmap_devmap at91_devmap[]; + +uint32_t at91_chip_id; + +#ifdef AT91C_MASTER_CLOCK uint32_t at91_master_clock = AT91C_MASTER_CLOCK; +#else +uint32_t at91_master_clock; +#endif static int at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, @@ -99,6 +109,19 @@ at91_barrier(void *t, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, { } +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (NULL); +} + +int +bus_dma_get_range_nb(void) +{ + return (0); +} + bs_protos(generic); bs_protos(generic_armv4); @@ -212,6 +235,7 @@ struct bus_space at91_bs_tag = { static int at91_probe(device_t dev) { + device_set_desc(dev, "AT91 device bus"); arm_post_filter = at91_eoi; return (0); @@ -224,324 +248,38 @@ at91_identify(driver_t *drv, device_t parent) BUS_ADD_CHILD(parent, 0, "atmelarm", 0); } -struct arm32_dma_range * -bus_dma_get_range(void) -{ - - return (NULL); -} - -int -bus_dma_get_range_nb(void) -{ - return (0); -} - -extern void irq_entry(void); - -static void -at91_add_child(device_t dev, int prio, const char *name, int unit, - bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) -{ - device_t kid; - struct at91_ivar *ivar; - - kid = device_add_child_ordered(dev, prio, name, unit); - if (kid == NULL) { - printf("Can't add child %s%d ordered\n", name, unit); - return; - } - ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); - if (ivar == NULL) { - device_delete_child(dev, kid); - printf("Can't add alloc ivar\n"); - return; - } - device_set_ivars(kid, ivar); - resource_list_init(&ivar->resources); - if (irq0 != -1) - bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); - if (irq1 != 0) - bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); - if (irq2 != 0) - bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); - if (addr != 0) - bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); -} - -struct cpu_devs -{ - const char *name; - int unit; - bus_addr_t mem_base; - bus_size_t mem_len; - int irq0; - int irq1; - int irq2; -}; - -struct cpu_devs at91rm9200_devs[] = -{ - // All the "system" devices - { - "at91_st", 0, - AT91RM92_BASE + AT91RM92_ST_BASE, AT91RM92_ST_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_pio", 0, - AT91RM92_BASE + AT91RM92_PIOA_BASE, AT91RM92_PIO_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_pio", 1, - AT91RM92_BASE + AT91RM92_PIOB_BASE, AT91RM92_PIO_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_pio", 2, - AT91RM92_BASE + AT91RM92_PIOC_BASE, AT91RM92_PIO_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_pio", 3, - AT91RM92_BASE + AT91RM92_PIOD_BASE, AT91RM92_PIO_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_pmc", 0, - AT91RM92_BASE + AT91RM92_PMC_BASE, AT91RM92_PMC_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_aic", 0, - AT91RM92_BASE + AT91RM92_AIC_BASE, AT91RM92_AIC_SIZE, - 0 // Interrupt controller has no interrupts! - }, - { - "at91_rtc", 0, - AT91RM92_BASE + AT91RM92_RTC_BASE, AT91RM92_RTC_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "at91_mc", 0, - AT91RM92_BASE + AT91RM92_MC_BASE, AT91RM92_MC_SIZE, - AT91RM92_IRQ_SYSTEM - }, - - // All other devices - { - "at91_tc", 0, - AT91RM92_BASE + AT91RM92_TC0_BASE, AT91RM92_TC_SIZE, - AT91RM92_IRQ_TC0, AT91RM92_IRQ_TC1, AT91RM92_IRQ_TC2 - }, - { - "at91_tc", 1, - AT91RM92_BASE + AT91RM92_TC1_BASE, AT91RM92_TC_SIZE, - AT91RM92_IRQ_TC3, AT91RM92_IRQ_TC4, AT91RM92_IRQ_TC5 - }, - { - "at91_udp", 0, - AT91RM92_BASE + AT91RM92_UDP_BASE, AT91RM92_UDP_SIZE, - AT91RM92_IRQ_UDP, AT91RM92_IRQ_PIOB - }, - { - "at91_mci", 0, - AT91RM92_BASE + AT91RM92_MCI_BASE, AT91RM92_MCI_SIZE, - AT91RM92_IRQ_MCI - }, - { - "at91_twi", 0, - AT91RM92_BASE + AT91RM92_TWI_BASE, AT91RM92_TWI_SIZE, - AT91RM92_IRQ_TWI - }, - { - "ate", 0, - AT91RM92_BASE + AT91RM92_EMAC_BASE, AT91RM92_EMAC_SIZE, - AT91RM92_IRQ_EMAC - }, -#ifndef SKYEYE_WORKAROUNDS - { - "uart", 0, - AT91RM92_BASE + AT91RM92_DBGU_BASE, AT91RM92_DBGU_SIZE, - AT91RM92_IRQ_SYSTEM - }, - { - "uart", 1, - AT91RM92_BASE + AT91RM92_USART0_BASE, AT91RM92_USART_SIZE, - AT91RM92_IRQ_USART0 - }, - { - "uart", 2, - AT91RM92_BASE + AT91RM92_USART1_BASE, AT91RM92_USART_SIZE, - AT91RM92_IRQ_USART1 - }, - { - "uart", 3, - AT91RM92_BASE + AT91RM92_USART2_BASE, AT91RM92_USART_SIZE, - AT91RM92_IRQ_USART2 - }, - { - "uart", 4, - AT91RM92_BASE + AT91RM92_USART3_BASE, AT91RM92_USART_SIZE, - AT91RM92_IRQ_USART3 - }, -#else - { - "uart", 0, - AT91RM92_BASE + AT91RM92_USART0_BASE, AT91RM92_USART_SIZE, - AT91RM92_IRQ_USART0 - }, -#endif - { - "at91_ssc", 0, - AT91RM92_BASE + AT91RM92_SSC0_BASE, AT91RM92_SSC_SIZE, - AT91RM92_IRQ_SSC0 - }, - { - "at91_ssc", 1, - AT91RM92_BASE + AT91RM92_SSC1_BASE, AT91RM92_SSC_SIZE, - AT91RM92_IRQ_SSC1 - }, - { - "at91_ssc", 2, - AT91RM92_BASE + AT91RM92_SSC2_BASE, AT91RM92_SSC_SIZE, - AT91RM92_IRQ_SSC2 - }, - { - "spi", 0, - AT91RM92_BASE + AT91RM92_SPI_BASE, AT91RM92_SPI_SIZE, - AT91RM92_IRQ_SPI - }, - { - "ohci", 0, - AT91RM92_OHCI_BASE, AT91RM92_OHCI_SIZE, - AT91RM92_IRQ_UHP - }, - { - "at91_cfata", 0, - AT91RM92_CF_BASE, AT91RM92_CF_SIZE, - -1 - }, - { 0, 0, 0, 0, 0 } -}; - -static void -at91_cpu_add_builtin_children(device_t dev, struct at91_softc *sc) -{ - int i; - struct cpu_devs *walker; - - // XXX should look at the device id in the DBGU register and - // XXX based on the CPU load in these devices - for (i = 0, walker = at91rm9200_devs; walker->name; i++, walker++) { - at91_add_child(dev, i, walker->name, walker->unit, - walker->mem_base, walker->mem_len, walker->irq0, - walker->irq1, walker->irq2); - } -} - -#define NORMDEV 50 - -/* - * Standard priority levels for the system. 0 is lowest and 7 is highest. - * These values are the ones Atmel uses for its Linux port, which differ - * a little form the ones that are in the standard distribution. Also, - * the ones marked with 'TWEEK' are different based on experience. - */ -static int irq_prio[32] = -{ - 7, /* Advanced Interrupt Controller (FIQ) */ - 7, /* System Peripherals */ - 1, /* Parallel IO Controller A */ - 1, /* Parallel IO Controller B */ - 1, /* Parallel IO Controller C */ - 1, /* Parallel IO Controller D */ - 5, /* USART 0 */ - 5, /* USART 1 */ - 5, /* USART 2 */ - 5, /* USART 3 */ - 0, /* Multimedia Card Interface */ - 2, /* USB Device Port */ - 4, /* Two-Wire Interface */ /* TWEEK */ - 5, /* Serial Peripheral Interface */ - 4, /* Serial Synchronous Controller 0 */ - 6, /* Serial Synchronous Controller 1 */ /* TWEEK */ - 4, /* Serial Synchronous Controller 2 */ - 0, /* Timer Counter 0 */ - 6, /* Timer Counter 1 */ /* TWEEK */ - 0, /* Timer Counter 2 */ - 0, /* Timer Counter 3 */ - 0, /* Timer Counter 4 */ - 0, /* Timer Counter 5 */ - 2, /* USB Host port */ - 3, /* Ethernet MAC */ - 0, /* Advanced Interrupt Controller (IRQ0) */ - 0, /* Advanced Interrupt Controller (IRQ1) */ - 0, /* Advanced Interrupt Controller (IRQ2) */ - 0, /* Advanced Interrupt Controller (IRQ3) */ - 0, /* Advanced Interrupt Controller (IRQ4) */ - 0, /* Advanced Interrupt Controller (IRQ5) */ - 0 /* Advanced Interrupt Controller (IRQ6) */ -}; - static int at91_attach(device_t dev) { struct at91_softc *sc = device_get_softc(dev); - int i; + const struct pmap_devmap *pdevmap; at91_softc = sc; sc->sc_st = &at91_bs_tag; - sc->sc_sh = AT91RM92_BASE; + sc->sc_sh = AT91_BASE; sc->dev = dev; - if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_SYS_BASE, - AT91RM92_SYS_SIZE, &sc->sc_sys_sh) != 0) - panic("Enable to map IRQ registers"); + sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "AT91 IRQs"; - sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "AT91 Memory"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) panic("at91_attach: failed to set up IRQ rman"); - if (rman_init(&sc->sc_mem_rman) != 0 || - rman_manage_region(&sc->sc_mem_rman, 0xdff00000ul, - 0xdffffffful) != 0) + + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "AT91 Memory"; + if (rman_init(&sc->sc_mem_rman) != 0) panic("at91_attach: failed to set up memory rman"); - if (rman_manage_region(&sc->sc_mem_rman, AT91RM92_OHCI_BASE, - AT91RM92_OHCI_BASE + AT91RM92_OHCI_SIZE - 1) != 0) - panic("at91_attach: failed to set up ohci memory"); - if (rman_manage_region(&sc->sc_mem_rman, AT91RM92_CF_BASE, - AT91RM92_CF_BASE + AT91RM92_CF_SIZE - 1) != 0) - panic("at91_attach: failed to set up CompactFlash ATA memory"); - - for (i = 0; i < 32; i++) { - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SVR + - i * 4, i); - /* Priority. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SMR + i * 4, - irq_prio[i]); - if (i < 8) - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_EOICR, - 1); + for ( pdevmap = at91_devmap; pdevmap->pd_va != 0; pdevmap++) { + if (rman_manage_region(&sc->sc_mem_rman, pdevmap->pd_va, + pdevmap->pd_va + pdevmap->pd_size - 1) != 0) + panic("at91_attach: failed to set up memory rman"); } - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SPU, 32); - /* No debug. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_DCR, 0); - /* Disable and clear all interrupts. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IDCR, 0xffffffff); - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_ICCR, 0xffffffff); - /* XXX */ - /* Disable all interrupts for RTC (0xe24 == RTC_IDR) */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff); - /* DIsable all interrupts for DBGU */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x20c, 0xffffffff); - /* Disable all interrupts for the SDRAM controller */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff); - at91_cpu_add_builtin_children(dev, sc); + /* Our device list will be added automatically by the cpu device + * e.g. at91rm9200.c when it is identified. To ensure that the + * CPU and PMC are attached first any other "identified" devices + * call BUS_ADD_CHILD(9) with an "order" of at least 2. */ bus_generic_probe(dev); bus_generic_attach(dev); @@ -630,11 +368,11 @@ at91_setup_intr(device_t dev, device_t child, { struct at91_softc *sc = device_get_softc(dev); - if (rman_get_start(ires) == AT91RM92_IRQ_SYSTEM && filt == NULL) + if (rman_get_start(ires) == sc->sc_irq_system && filt == NULL) panic("All system interrupt ISRs must be FILTER"); BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, arg, cookiep); - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IECR, + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IECR, 1 << rman_get_start(ires)); return (0); } @@ -645,7 +383,7 @@ at91_teardown_intr(device_t dev, device_t child, struct resource *res, { struct at91_softc *sc = device_get_softc(dev); - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IDCR, + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 1 << rman_get_start(res)); return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); } @@ -697,8 +435,7 @@ arm_mask_irq(uintptr_t nb) { bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, IC_IDCR, 1 << nb); - + at91_softc->sc_aic_sh, IC_IDCR, 1 << nb); } int @@ -708,12 +445,12 @@ arm_get_next_irq(int last __unused) int irq; irq = bus_space_read_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, IC_IVR); + at91_softc->sc_aic_sh, IC_IVR); status = bus_space_read_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, IC_ISR); + at91_softc->sc_aic_sh, IC_ISR); if (status == 0) { bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, IC_EOICR, 1); + at91_softc->sc_aic_sh, IC_EOICR, 1); return (-1); } return (irq); @@ -724,16 +461,15 @@ arm_unmask_irq(uintptr_t nb) { bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, IC_IECR, 1 << nb); - bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, + at91_softc->sc_aic_sh, IC_IECR, 1 << nb); + bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh, IC_EOICR, 0); - } static void at91_eoi(void *unused) { - bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, + bus_space_write_4(at91_softc->sc_st, at91_softc->sc_aic_sh, IC_EOICR, 0); } @@ -761,6 +497,7 @@ static driver_t at91_driver = { at91_methods, sizeof(struct at91_softc), }; + static devclass_t at91_devclass; DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0); diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index 1e63ee6a9ca..bf686eba396 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -90,9 +90,10 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include -#include -#include +#include +#include #define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ #define KERNEL_PT_KERN 1 @@ -140,7 +141,7 @@ static void *boot_arg2; static struct trapframe proc0_tf; /* Static device mappings. */ -static const struct pmap_devmap at91rm9200_devmap[] = { +const struct pmap_devmap at91_devmap[] = { /* * Map the on-board devices VA == PA so that we can access them * with the MMU on or off. @@ -153,60 +154,88 @@ static const struct pmap_devmap at91rm9200_devmap[] = { */ 0xdff00000, 0xfff00000, - 0x100000, + 0x00100000, VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, - /* - * We can't just map the OHCI registers VA == PA, because - * AT91RM92_OHCI_BASE belongs to the userland address space. + /* We can't just map the OHCI registers VA == PA, because + * AT91xx_xxx_BASE belongs to the userland address space. * We could just choose a different virtual address, but a better * solution would probably be to just use pmap_mapdev() to allocate * KVA, as we don't need the OHCI controller before the vm * initialization is done. However, the AT91 resource allocation * system doesn't know how to use pmap_mapdev() yet. + * Care must be taken to ensure PA and VM address do not overlap + * between entries. */ { /* * Add the ohci controller, and anything else that might be * on this chip select for a VA/PA mapping. */ + /* Internal Memory 1MB */ AT91RM92_OHCI_BASE, AT91RM92_OHCI_PA_BASE, - AT91RM92_OHCI_SIZE, + 0x00100000, VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, { - /* CompactFlash controller. */ + /* CompactFlash controller. Portion of EBI CS4 1MB */ AT91RM92_CF_BASE, AT91RM92_CF_PA_BASE, - AT91RM92_CF_SIZE, + 0x00100000, + VM_PROT_READ|VM_PROT_WRITE, + PTE_NOCACHE, + }, + /* The next two should be good for the 9260, 9261 and 9G20 since + * addresses mapping is the same. */ + { + /* Internal Memory 1MB */ + AT91SAM9G20_OHCI_BASE, + AT91SAM9G20_OHCI_PA_BASE, + 0x00100000, VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, { - 0, - 0, - 0, - 0, - 0, - } + /* EBI CS3 256MB */ + AT91SAM9G20_NAND_BASE, + AT91SAM9G20_NAND_PA_BASE, + AT91SAM9G20_NAND_SIZE, + VM_PROT_READ|VM_PROT_WRITE, + PTE_NOCACHE, + }, + { 0, 0, 0, 0, 0, } }; long at91_ramsize(void) { - uint32_t *SDRAMC = (uint32_t *)(AT91RM92_BASE + AT91RM92_SDRAMC_BASE); + uint32_t *SDRAMC = (uint32_t *)(AT91_BASE + AT91RM92_SDRAMC_BASE); uint32_t cr, mr; int banks, rows, cols, bw; - cr = SDRAMC[AT91RM92_SDRAMC_CR / 4]; - mr = SDRAMC[AT91RM92_SDRAMC_MR / 4]; - bw = (mr & AT91RM92_SDRAMC_MR_DBW_16) ? 1 : 2; - banks = (cr & AT91RM92_SDRAMC_CR_NB_4) ? 2 : 1; - rows = ((cr & AT91RM92_SDRAMC_CR_NR_MASK) >> 2) + 11; - cols = (cr & AT91RM92_SDRAMC_CR_NC_MASK) + 8; + if (at91_is_rm92()) { + SDRAMC = (uint32_t *)(AT91_BASE + AT91RM92_SDRAMC_BASE); + cr = SDRAMC[AT91RM92_SDRAMC_CR / 4]; + mr = SDRAMC[AT91RM92_SDRAMC_MR / 4]; + banks = (cr & AT91RM92_SDRAMC_CR_NB_4) ? 2 : 1; + rows = ((cr & AT91RM92_SDRAMC_CR_NR_MASK) >> 2) + 11; + cols = (cr & AT91RM92_SDRAMC_CR_NC_MASK) + 8; + bw = (mr & AT91RM92_SDRAMC_MR_DBW_16) ? 1 : 2; + } else { + /* This should be good for the 9260, 9261 and 9G20 as addresses + * and registers are the same */ + SDRAMC = (uint32_t *)(AT91_BASE + AT91SAM9G20_SDRAMC_BASE); + cr = SDRAMC[AT91SAM9G20_SDRAMC_CR / 4]; + mr = SDRAMC[AT91SAM9G20_SDRAMC_MR / 4]; + banks = (cr & AT91SAM9G20_SDRAMC_CR_NB_4) ? 2 : 1; + rows = ((cr & AT91SAM9G20_SDRAMC_CR_NR_MASK) >> 2) + 11; + cols = (cr & AT91SAM9G20_SDRAMC_CR_NC_MASK) + 8; + bw = (cr & AT91SAM9G20_SDRAMC_CR_DBW_16) ? 1 : 2; + } + return (1 << (cols + rows + banks + bw)); } @@ -326,12 +355,18 @@ initarm(void *arg, void *arg2) VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); } - pmap_devmap_bootstrap(l1pagetable, at91rm9200_devmap); + pmap_devmap_bootstrap(l1pagetable, at91_devmap); cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + cninit(); + + /* Get chip id so device drivers know about differences */ + at91_chip_id = *(volatile uint32_t *) + (AT91_BASE + AT91_DBGU_BASE + DBGU_C1R); + memsize = board_init(); physmem = memsize / PAGE_SIZE; diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c index 5ca60b93aa7..17cf9c25efd 100644 --- a/sys/arm/at91/at91_mci.c +++ b/sys/arm/at91/at91_mci.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2006 Bernd Walter. All rights reserved. * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -52,16 +54,19 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include + #include #include #include + #include #include #include #include "mmcbr_if.h" +#include "opt_at91.h" + #define BBSZ 512 struct at91_mci_softc { @@ -69,8 +74,9 @@ struct at91_mci_softc { device_t dev; int sc_cap; #define CAP_HAS_4WIRE 1 /* Has 4 wire bus */ -#define CAP_NEEDS_BOUNCE 2 /* broken hardware needing bounce */ +#define CAP_NEEDS_BYTESWAP 2 /* broken hardware needing bounce */ int flags; + int has_4wire; #define CMD_STARTED 1 #define STOP_STARTED 2 struct resource *irq_res; /* IRQ resource */ @@ -89,7 +95,7 @@ struct at91_mci_softc { static inline uint32_t RD4(struct at91_mci_softc *sc, bus_size_t off) { - return bus_read_4(sc->mem_res, off); + return (bus_read_4(sc->mem_res, off)); } static inline void @@ -140,7 +146,13 @@ at91_mci_init(device_t dev) WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */ WR4(sc, MCI_DTOR, MCI_DTOR_DTOMUL_1M | 1); WR4(sc, MCI_MR, 0x834a); // XXX GROSS HACK FROM LINUX +#ifndef AT91_MCI_SLOT_B WR4(sc, MCI_SDCR, 0); /* SLOT A, 1 bit bus */ +#else + /* XXX Really should add second "unit" but nobody using using + * a two slot card that we know of. XXX */ + WR4(sc, MCI_SDCR, 1); /* SLOT B, 1 bit bus */ +#endif } static void @@ -165,11 +177,16 @@ static int at91_mci_attach(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); - int err; + struct sysctl_ctx_list *sctx; + struct sysctl_oid *soid; device_t child; + int err; sc->dev = dev; - sc->sc_cap = CAP_NEEDS_BOUNCE; + + sc->sc_cap = 0; + if (at91_is_rm92()) + sc->sc_cap |= CAP_NEEDS_BYTESWAP; err = at91_mci_activate(dev); if (err) goto out; @@ -201,13 +218,28 @@ at91_mci_attach(device_t dev) AT91_MCI_LOCK_DESTROY(sc); goto out; } + + sctx = device_get_sysctl_ctx(dev); + soid = device_get_sysctl_tree(dev); + SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "4wire", + CTLFLAG_RW, &sc->has_4wire, 0, "has 4 wire SD Card bus"); + +#ifdef AT91_MCI_HAS_4WIRE + sc->has_4wire = 1; +#endif + if (sc->has_4wire) + sc->sc_cap |= CAP_HAS_4WIRE; + + sc->host.f_min = at91_master_clock / 512; sc->host.f_min = 375000; - sc->host.f_max = at91_master_clock / 2; /* Typically 30MHz */ + sc->host.f_max = at91_master_clock / 2; + if (sc->host.f_max > 50000000) + sc->host.f_max = 50000000; /* Limit to 50MHz */ + sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + sc->host.caps = 0; if (sc->sc_cap & CAP_HAS_4WIRE) - sc->host.caps = MMC_CAP_4_BIT_DATA; - else - sc->host.caps = 0; + sc->host.caps |= MMC_CAP_4_BIT_DATA; child = device_add_child(dev, "mmc", 0); device_set_ivars(dev, &sc->host); err = bus_generic_attach(dev); @@ -237,11 +269,13 @@ at91_mci_activate(device_t dev) RF_ACTIVE); if (sc->mem_res == NULL) goto errout; + rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) goto errout; + return (0); errout: at91_mci_deactivate(dev); @@ -316,14 +350,16 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) uint32_t *src, *dst; int i; struct mmc_data *data; - struct mmc_request *req; void *vaddr; bus_addr_t paddr; sc->curcmd = cmd; data = cmd->data; cmdr = cmd->opcode; - req = cmd->mrq; + + /* XXX Upper layers don't always set this */ + cmd->mrq = sc->req; + if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) cmdr |= MCI_CMDR_RSPTYP_NO; else { @@ -364,26 +400,30 @@ at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) if (cmdr & MCI_CMDR_TRDIR) vaddr = cmd->data->data; else { - if (sc->sc_cap & CAP_NEEDS_BOUNCE) { - vaddr = sc->bounce_buffer; - src = (uint32_t *)cmd->data->data; - dst = (uint32_t *)vaddr; + /* Use bounce buffer even if we don't need + * byteswap, since buffer may straddle a page + * boundry, and we don't handle multi-segment + * transfers in hardware. + * (page issues seen from 'bsdlabel -w' which + * uses raw geom access to the volume). + * Greg Ansley (gja (at) ansley.com) + */ + vaddr = sc->bounce_buffer; + src = (uint32_t *)cmd->data->data; + dst = (uint32_t *)vaddr; + if (sc->sc_cap & CAP_NEEDS_BYTESWAP) { for (i = 0; i < data->len / 4; i++) dst[i] = bswap32(src[i]); - } - else - vaddr = cmd->data->data; + } else + memcpy(dst, src, data->len); } data->xfer_len = 0; if (bus_dmamap_load(sc->dmatag, sc->map, vaddr, data->len, at91_mci_getaddr, &paddr, 0) != 0) { - if (req->cmd->flags & STOP_STARTED) - req->stop->error = MMC_ERR_NO_MEMORY; - else - req->cmd->error = MMC_ERR_NO_MEMORY; + cmd->error = MMC_ERR_NO_MEMORY; sc->req = NULL; sc->curcmd = NULL; - req->done(req); + cmd->mrq->done(cmd->mrq); return; } sc->mapped++; @@ -451,7 +491,7 @@ at91_mci_request(device_t brdev, device_t reqdev, struct mmc_request *req) // XXX maybe the idea is naive... if (sc->req != NULL) { AT91_MCI_UNLOCK(sc); - return EBUSY; + return (EBUSY); } sc->req = req; sc->flags = 0; @@ -503,7 +543,7 @@ at91_mci_read_done(struct at91_mci_softc *sc) bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->dmatag, sc->map); sc->mapped--; - if (sc->sc_cap & CAP_NEEDS_BOUNCE) { + if (sc->sc_cap & CAP_NEEDS_BYTESWAP) { walker = (uint32_t *)cmd->data->data; len = cmd->data->len / 4; for (i = 0; i < len; i++) @@ -653,6 +693,13 @@ at91_mci_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) *(int *)result = sc->host.ios.vdd; break; case MMCBR_IVAR_CAPS: + if (sc->has_4wire) { + sc->sc_cap |= CAP_HAS_4WIRE; + sc->host.caps |= MMC_CAP_4_BIT_DATA; + } else { + sc->sc_cap &= ~CAP_HAS_4WIRE; + sc->host.caps &= ~MMC_CAP_4_BIT_DATA; + } *(int *)result = sc->host.caps; break; case MMCBR_IVAR_MAX_DATA: diff --git a/sys/arm/at91/at91_pio.c b/sys/arm/at91/at91_pio.c index e141212f970..853e5880382 100644 --- a/sys/arm/at91/at91_pio.c +++ b/sys/arm/at91/at91_pio.c @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include #include @@ -58,7 +58,7 @@ struct at91_pio_softc static inline uint32_t RD4(struct at91_pio_softc *sc, bus_size_t off) { - return bus_read_4(sc->mem_res, off); + return (bus_read_4(sc->mem_res, off)); } static inline void @@ -283,7 +283,7 @@ at91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, void at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_ASR / 4] = periph_a_mask; PIO[PIO_PDR / 4] = periph_a_mask; @@ -296,7 +296,7 @@ at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) void at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_BSR / 4] = periph_b_mask; PIO[PIO_PDR / 4] = periph_b_mask; @@ -309,7 +309,7 @@ at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) void at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_PER / 4] = gpio_mask; } @@ -317,7 +317,7 @@ at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) void at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_ODR / 4] = input_enable_mask; } @@ -325,7 +325,7 @@ at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) void at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_OER / 4] = output_enable_mask; if (use_pullup) @@ -337,7 +337,7 @@ at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) void at91_pio_gpio_set(uint32_t pio, uint32_t data_mask) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_SODR / 4] = data_mask; } @@ -345,7 +345,7 @@ at91_pio_gpio_set(uint32_t pio, uint32_t data_mask) void at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_CODR / 4] = data_mask; } @@ -353,7 +353,7 @@ at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) uint8_t at91_pio_gpio_get(uint32_t pio, uint32_t data_mask) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); data_mask &= PIO[PIO_PDSR / 4]; @@ -363,7 +363,7 @@ at91_pio_gpio_get(uint32_t pio, uint32_t data_mask) void at91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (use_deglitch) PIO[PIO_IFER / 4] = data_mask; @@ -376,7 +376,7 @@ void at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, int enable_interrupt) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (enable_interrupt) PIO[PIO_IER / 4] = data_mask; @@ -388,7 +388,7 @@ at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, uint32_t at91_pio_gpio_clear_interrupt(uint32_t pio) { - uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); + uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); /* reading this register will clear the interrupts */ return (PIO[PIO_ISR / 4]); } diff --git a/sys/arm/at91/at91_pio_rm9200.h b/sys/arm/at91/at91_pio_rm9200.h index 16d1ccb65f0..fa4fae3d42a 100644 --- a/sys/arm/at91/at91_pio_rm9200.h +++ b/sys/arm/at91/at91_pio_rm9200.h @@ -1,5 +1,9 @@ /* $FreeBSD$ */ +#ifndef ARM_AT91_AT91_PIO_RM9200_H +#define ARM_AT91_AT91_PIO_RM9200_H + +#include /* * These defines come from an atmel file that says specifically that it * has no copyright. @@ -8,317 +12,197 @@ //***************************************************************************** // PIO DEFINITIONS FOR AT91RM9200 //***************************************************************************** -#define AT91C_PIO_PA0 (1u << 0) // Pin Controlled by PA0 #define AT91C_PA0_MISO (AT91C_PIO_PA0) // SPI Master In Slave #define AT91C_PA0_PCK3 (AT91C_PIO_PA0) // PMC Programmable Clock Output 3 -#define AT91C_PIO_PA1 (1u << 1) // Pin Controlled by PA1 #define AT91C_PA1_MOSI (AT91C_PIO_PA1) // SPI Master Out Slave #define AT91C_PA1_PCK0 (AT91C_PIO_PA1) // PMC Programmable Clock Output 0 -#define AT91C_PIO_PA10 (1u << 10) // Pin Controlled by PA10 #define AT91C_PA10_ETX1 (AT91C_PIO_PA10) // Ethernet MAC Transmit Data 1 #define AT91C_PA10_MCDB1 (AT91C_PIO_PA10) // Multimedia Card B Data 1 -#define AT91C_PIO_PA11 (1u << 11) // Pin Controlled by PA11 #define AT91C_PA11_ECRS_ECRSDV (AT91C_PIO_PA11) // Ethernet MAC Carrier Sense/Carrier Sense and Data Valid #define AT91C_PA11_MCDB2 (AT91C_PIO_PA11) // Multimedia Card B Data 2 -#define AT91C_PIO_PA12 (1u << 12) // Pin Controlled by PA12 #define AT91C_PA12_ERX0 (AT91C_PIO_PA12) // Ethernet MAC Receive Data 0 #define AT91C_PA12_MCDB3 (AT91C_PIO_PA12) // Multimedia Card B Data 3 -#define AT91C_PIO_PA13 (1u << 13) // Pin Controlled by PA13 #define AT91C_PA13_ERX1 (AT91C_PIO_PA13) // Ethernet MAC Receive Data 1 #define AT91C_PA13_TCLK0 (AT91C_PIO_PA13) // Timer Counter 0 external clock input -#define AT91C_PIO_PA14 (1u << 14) // Pin Controlled by PA14 #define AT91C_PA14_ERXER (AT91C_PIO_PA14) // Ethernet MAC Receive Error #define AT91C_PA14_TCLK1 (AT91C_PIO_PA14) // Timer Counter 1 external clock input -#define AT91C_PIO_PA15 (1u << 15) // Pin Controlled by PA15 #define AT91C_PA15_EMDC (AT91C_PIO_PA15) // Ethernet MAC Management Data Clock #define AT91C_PA15_TCLK2 (AT91C_PIO_PA15) // Timer Counter 2 external clock input -#define AT91C_PIO_PA16 (1u << 16) // Pin Controlled by PA16 #define AT91C_PA16_EMDIO (AT91C_PIO_PA16) // Ethernet MAC Management Data Input/Output #define AT91C_PA16_IRQ6 (AT91C_PIO_PA16) // AIC Interrupt input 6 -#define AT91C_PIO_PA17 (1u << 17) // Pin Controlled by PA17 #define AT91C_PA17_TXD0 (AT91C_PIO_PA17) // USART 0 Transmit Data #define AT91C_PA17_TIOA0 (AT91C_PIO_PA17) // Timer Counter 0 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PA18 (1u << 18) // Pin Controlled by PA18 #define AT91C_PA18_RXD0 (AT91C_PIO_PA18) // USART 0 Receive Data #define AT91C_PA18_TIOB0 (AT91C_PIO_PA18) // Timer Counter 0 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PA19 (1u << 19) // Pin Controlled by PA19 #define AT91C_PA19_SCK0 (AT91C_PIO_PA19) // USART 0 Serial Clock #define AT91C_PA19_TIOA1 (AT91C_PIO_PA19) // Timer Counter 1 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PA2 (1u << 2) // Pin Controlled by PA2 #define AT91C_PA2_SPCK (AT91C_PIO_PA2) // SPI Serial Clock #define AT91C_PA2_IRQ4 (AT91C_PIO_PA2) // AIC Interrupt Input 4 -#define AT91C_PIO_PA20 (1u << 20) // Pin Controlled by PA20 #define AT91C_PA20_CTS0 (AT91C_PIO_PA20) // USART 0 Clear To Send #define AT91C_PA20_TIOB1 (AT91C_PIO_PA20) // Timer Counter 1 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PA21 (1u << 21) // Pin Controlled by PA21 #define AT91C_PA21_RTS0 (AT91C_PIO_PA21) // Usart 0 Ready To Send #define AT91C_PA21_TIOA2 (AT91C_PIO_PA21) // Timer Counter 2 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PA22 (1u << 22) // Pin Controlled by PA22 #define AT91C_PA22_RXD2 (AT91C_PIO_PA22) // USART 2 Receive Data #define AT91C_PA22_TIOB2 (AT91C_PIO_PA22) // Timer Counter 2 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PA23 (1u << 23) // Pin Controlled by PA23 #define AT91C_PA23_TXD2 (AT91C_PIO_PA23) // USART 2 Transmit Data #define AT91C_PA23_IRQ3 (AT91C_PIO_PA23) // Interrupt input 3 -#define AT91C_PIO_PA24 (1u << 24) // Pin Controlled by PA24 #define AT91C_PA24_SCK2 (AT91C_PIO_PA24) // USART2 Serial Clock #define AT91C_PA24_PCK1 (AT91C_PIO_PA24) // PMC Programmable Clock Output 1 -#define AT91C_PIO_PA25 (1u << 25) // Pin Controlled by PA25 #define AT91C_PA25_TWD (AT91C_PIO_PA25) // TWI Two-wire Serial Data #define AT91C_PA25_IRQ2 (AT91C_PIO_PA25) // Interrupt input 2 -#define AT91C_PIO_PA26 (1u << 26) // Pin Controlled by PA26 #define AT91C_PA26_TWCK (AT91C_PIO_PA26) // TWI Two-wire Serial Clock #define AT91C_PA26_IRQ1 (AT91C_PIO_PA26) // Interrupt input 1 -#define AT91C_PIO_PA27 (1u << 27) // Pin Controlled by PA27 #define AT91C_PA27_MCCK (AT91C_PIO_PA27) // Multimedia Card Clock #define AT91C_PA27_TCLK3 (AT91C_PIO_PA27) // Timer Counter 3 External Clock Input -#define AT91C_PIO_PA28 (1u << 28) // Pin Controlled by PA28 #define AT91C_PA28_MCCDA (AT91C_PIO_PA28) // Multimedia Card A Command #define AT91C_PA28_TCLK4 (AT91C_PIO_PA28) // Timer Counter 4 external Clock Input -#define AT91C_PIO_PA29 (1u << 29) // Pin Controlled by PA29 #define AT91C_PA29_MCDA0 (AT91C_PIO_PA29) // Multimedia Card A Data 0 #define AT91C_PA29_TCLK5 (AT91C_PIO_PA29) // Timer Counter 5 external clock input -#define AT91C_PIO_PA3 (1u << 3) // Pin Controlled by PA3 #define AT91C_PA3_NPCS0 (AT91C_PIO_PA3) // SPI Peripheral Chip Select 0 #define AT91C_PA3_IRQ5 (AT91C_PIO_PA3) // AIC Interrupt Input 5 -#define AT91C_PIO_PA30 (1u << 30) // Pin Controlled by PA30 #define AT91C_PA30_DRXD (AT91C_PIO_PA30) // DBGU Debug Receive Data #define AT91C_PA30_CTS2 (AT91C_PIO_PA30) // Usart 2 Clear To Send -#define AT91C_PIO_PA31 (1u << 31) // Pin Controlled by PA31 #define AT91C_PA31_DTXD (AT91C_PIO_PA31) // DBGU Debug Transmit Data #define AT91C_PA31_RTS2 (AT91C_PIO_PA31) // USART 2 Ready To Send -#define AT91C_PIO_PA4 (1u << 4) // Pin Controlled by PA4 #define AT91C_PA4_NPCS1 (AT91C_PIO_PA4) // SPI Peripheral Chip Select 1 #define AT91C_PA4_PCK1 (AT91C_PIO_PA4) // PMC Programmable Clock Output 1 -#define AT91C_PIO_PA5 (1u << 5) // Pin Controlled by PA5 #define AT91C_PA5_NPCS2 (AT91C_PIO_PA5) // SPI Peripheral Chip Select 2 #define AT91C_PA5_TXD3 (AT91C_PIO_PA5) // USART 3 Transmit Data -#define AT91C_PIO_PA6 (1u << 6) // Pin Controlled by PA6 #define AT91C_PA6_NPCS3 (AT91C_PIO_PA6) // SPI Peripheral Chip Select 3 #define AT91C_PA6_RXD3 (AT91C_PIO_PA6) // USART 3 Receive Data -#define AT91C_PIO_PA7 (1u << 7) // Pin Controlled by PA7 #define AT91C_PA7_ETXCK_EREFCK (AT91C_PIO_PA7) // Ethernet MAC Transmit Clock/Reference Clock #define AT91C_PA7_PCK2 (AT91C_PIO_PA7) // PMC Programmable Clock 2 -#define AT91C_PIO_PA8 (1u << 8) // Pin Controlled by PA8 #define AT91C_PA8_ETXEN (AT91C_PIO_PA8) // Ethernet MAC Transmit Enable #define AT91C_PA8_MCCDB (AT91C_PIO_PA8) // Multimedia Card B Command -#define AT91C_PIO_PA9 (1u << 9) // Pin Controlled by PA9 #define AT91C_PA9_ETX0 (AT91C_PIO_PA9) // Ethernet MAC Transmit Data 0 #define AT91C_PA9_MCDB0 (AT91C_PIO_PA9) // Multimedia Card B Data 0 -#define AT91C_PIO_PB0 (1u << 0) // Pin Controlled by PB0 #define AT91C_PB0_TF0 (AT91C_PIO_PB0) // SSC Transmit Frame Sync 0 #define AT91C_PB0_TIOB3 (AT91C_PIO_PB0) // Timer Counter 3 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PB1 (1u << 1) // Pin Controlled by PB1 #define AT91C_PB1_TK0 (AT91C_PIO_PB1) // SSC Transmit Clock 0 #define AT91C_PB1_CTS3 (AT91C_PIO_PB1) // USART 3 Clear To Send -#define AT91C_PIO_PB10 (1u << 10) // Pin Controlled by PB10 #define AT91C_PB10_RK1 (AT91C_PIO_PB10) // SSC Receive Clock 1 #define AT91C_PB10_TIOA5 (AT91C_PIO_PB10) // Timer Counter 5 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PB11 (1u << 11) // Pin Controlled by PB11 #define AT91C_PB11_RF1 (AT91C_PIO_PB11) // SSC Receive Frame Sync 1 #define AT91C_PB11_TIOB5 (AT91C_PIO_PB11) // Timer Counter 5 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PB12 (1u << 12) // Pin Controlled by PB12 #define AT91C_PB12_TF2 (AT91C_PIO_PB12) // SSC Transmit Frame Sync 2 #define AT91C_PB12_ETX2 (AT91C_PIO_PB12) // Ethernet MAC Transmit Data 2 -#define AT91C_PIO_PB13 (1u << 13) // Pin Controlled by PB13 #define AT91C_PB13_TK2 (AT91C_PIO_PB13) // SSC Transmit Clock 2 #define AT91C_PB13_ETX3 (AT91C_PIO_PB13) // Ethernet MAC Transmit Data 3 -#define AT91C_PIO_PB14 (1u << 14) // Pin Controlled by PB14 #define AT91C_PB14_TD2 (AT91C_PIO_PB14) // SSC Transmit Data 2 #define AT91C_PB14_ETXER (AT91C_PIO_PB14) // Ethernet MAC Transmikt Coding Error -#define AT91C_PIO_PB15 (1u << 15) // Pin Controlled by PB15 #define AT91C_PB15_RD2 (AT91C_PIO_PB15) // SSC Receive Data 2 #define AT91C_PB15_ERX2 (AT91C_PIO_PB15) // Ethernet MAC Receive Data 2 -#define AT91C_PIO_PB16 (1u << 16) // Pin Controlled by PB16 #define AT91C_PB16_RK2 (AT91C_PIO_PB16) // SSC Receive Clock 2 #define AT91C_PB16_ERX3 (AT91C_PIO_PB16) // Ethernet MAC Receive Data 3 -#define AT91C_PIO_PB17 (1u << 17) // Pin Controlled by PB17 #define AT91C_PB17_RF2 (AT91C_PIO_PB17) // SSC Receive Frame Sync 2 #define AT91C_PB17_ERXDV (AT91C_PIO_PB17) // Ethernet MAC Receive Data Valid -#define AT91C_PIO_PB18 (1u << 18) // Pin Controlled by PB18 #define AT91C_PB18_RI1 (AT91C_PIO_PB18) // USART 1 Ring Indicator #define AT91C_PB18_ECOL (AT91C_PIO_PB18) // Ethernet MAC Collision Detected -#define AT91C_PIO_PB19 (1u << 19) // Pin Controlled by PB19 #define AT91C_PB19_DTR1 (AT91C_PIO_PB19) // USART 1 Data Terminal ready #define AT91C_PB19_ERXCK (AT91C_PIO_PB19) // Ethernet MAC Receive Clock -#define AT91C_PIO_PB2 (1u << 2) // Pin Controlled by PB2 #define AT91C_PB2_TD0 (AT91C_PIO_PB2) // SSC Transmit data #define AT91C_PB2_SCK3 (AT91C_PIO_PB2) // USART 3 Serial Clock -#define AT91C_PIO_PB20 (1u << 20) // Pin Controlled by PB20 #define AT91C_PB20_TXD1 (AT91C_PIO_PB20) // USART 1 Transmit Data -#define AT91C_PIO_PB21 (1u << 21) // Pin Controlled by PB21 #define AT91C_PB21_RXD1 (AT91C_PIO_PB21) // USART 1 Receive Data -#define AT91C_PIO_PB22 (1u << 22) // Pin Controlled by PB22 #define AT91C_PB22_SCK1 (AT91C_PIO_PB22) // USART1 Serial Clock -#define AT91C_PIO_PB23 (1u << 23) // Pin Controlled by PB23 #define AT91C_PB23_DCD1 (AT91C_PIO_PB23) // USART 1 Data Carrier Detect -#define AT91C_PIO_PB24 (1u << 24) // Pin Controlled by PB24 #define AT91C_PB24_CTS1 (AT91C_PIO_PB24) // USART 1 Clear To Send -#define AT91C_PIO_PB25 (1u << 25) // Pin Controlled by PB25 #define AT91C_PB25_DSR1 (AT91C_PIO_PB25) // USART 1 Data Set ready #define AT91C_PB25_EF100 (AT91C_PIO_PB25) // Ethernet MAC Force 100 Mbits/sec -#define AT91C_PIO_PB26 (1u << 26) // Pin Controlled by PB26 #define AT91C_PB26_RTS1 (AT91C_PIO_PB26) // Usart 0 Ready To Send -#define AT91C_PIO_PB27 (1u << 27) // Pin Controlled by PB27 #define AT91C_PB27_PCK0 (AT91C_PIO_PB27) // PMC Programmable Clock Output 0 -#define AT91C_PIO_PB28 (1u << 28) // Pin Controlled by PB28 #define AT91C_PB28_FIQ (AT91C_PIO_PB28) // AIC Fast Interrupt Input -#define AT91C_PIO_PB29 (1u << 29) // Pin Controlled by PB29 #define AT91C_PB29_IRQ0 (AT91C_PIO_PB29) // Interrupt input 0 -#define AT91C_PIO_PB3 (1u << 3) // Pin Controlled by PB3 #define AT91C_PB3_RD0 (AT91C_PIO_PB3) // SSC Receive Data #define AT91C_PB3_MCDA1 (AT91C_PIO_PB3) // Multimedia Card A Data 1 -#define AT91C_PIO_PB4 (1u << 4) // Pin Controlled by PB4 #define AT91C_PB4_RK0 (AT91C_PIO_PB4) // SSC Receive Clock #define AT91C_PB4_MCDA2 (AT91C_PIO_PB4) // Multimedia Card A Data 2 -#define AT91C_PIO_PB5 (1u << 5) // Pin Controlled by PB5 #define AT91C_PB5_RF0 (AT91C_PIO_PB5) // SSC Receive Frame Sync 0 #define AT91C_PB5_MCDA3 (AT91C_PIO_PB5) // Multimedia Card A Data 3 -#define AT91C_PIO_PB6 (1u << 6) // Pin Controlled by PB6 #define AT91C_PB6_TF1 (AT91C_PIO_PB6) // SSC Transmit Frame Sync 1 #define AT91C_PB6_TIOA3 (AT91C_PIO_PB6) // Timer Counter 4 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PB7 (1u << 7) // Pin Controlled by PB7 #define AT91C_PB7_TK1 (AT91C_PIO_PB7) // SSC Transmit Clock 1 #define AT91C_PB7_TIOB3 (AT91C_PIO_PB7) // Timer Counter 3 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PB8 (1u << 8) // Pin Controlled by PB8 #define AT91C_PB8_TD1 (AT91C_PIO_PB8) // SSC Transmit Data 1 #define AT91C_PB8_TIOA4 (AT91C_PIO_PB8) // Timer Counter 4 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PB9 (1u << 9) // Pin Controlled by PB9 #define AT91C_PB9_RD1 (AT91C_PIO_PB9) // SSC Receive Data 1 #define AT91C_PB9_TIOB4 (AT91C_PIO_PB9) // Timer Counter 4 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PC0 (1u << 0) // Pin Controlled by PC0 #define AT91C_PC0_BFCK (AT91C_PIO_PC0) // Burst Flash Clock -#define AT91C_PIO_PC1 (1u << 1) // Pin Controlled by PC1 #define AT91C_PC1_BFRDY_SMOE (AT91C_PIO_PC1) // Burst Flash Ready -#define AT91C_PIO_PC10 (1u << 10) // Pin Controlled by PC10 #define AT91C_PC10_NCS4_CFCS (AT91C_PIO_PC10) // Compact Flash Chip Select -#define AT91C_PIO_PC11 (1u << 11) // Pin Controlled by PC11 #define AT91C_PC11_NCS5_CFCE1 (AT91C_PIO_PC11) // Chip Select 5 / Compact Flash Chip Enable 1 -#define AT91C_PIO_PC12 (1u << 12) // Pin Controlled by PC12 #define AT91C_PC12_NCS6_CFCE2 (AT91C_PIO_PC12) // Chip Select 6 / Compact Flash Chip Enable 2 -#define AT91C_PIO_PC13 (1u << 13) // Pin Controlled by PC13 #define AT91C_PC13_NCS7 (AT91C_PIO_PC13) // Chip Select 7 -#define AT91C_PIO_PC14 (1u << 14) // Pin Controlled by PC14 -#define AT91C_PIO_PC15 (1u << 15) // Pin Controlled by PC15 -#define AT91C_PIO_PC16 (1u << 16) // Pin Controlled by PC16 #define AT91C_PC16_D16 (AT91C_PIO_PC16) // Data Bus [16] -#define AT91C_PIO_PC17 (1u << 17) // Pin Controlled by PC17 #define AT91C_PC17_D17 (AT91C_PIO_PC17) // Data Bus [17] -#define AT91C_PIO_PC18 (1u << 18) // Pin Controlled by PC18 #define AT91C_PC18_D18 (AT91C_PIO_PC18) // Data Bus [18] -#define AT91C_PIO_PC19 (1u << 19) // Pin Controlled by PC19 #define AT91C_PC19_D19 (AT91C_PIO_PC19) // Data Bus [19] -#define AT91C_PIO_PC2 (1u << 2) // Pin Controlled by PC2 #define AT91C_PC2_BFAVD (AT91C_PIO_PC2)u // Burst Flash Address Valid -#define AT91C_PIO_PC20 (1u << 20) // Pin Controlled by PC20 #define AT91C_PC20_D20 (AT91C_PIO_PC20) // Data Bus [20] -#define AT91C_PIO_PC21 (1u << 21) // Pin Controlled by PC21 #define AT91C_PC21_D21 (AT91C_PIO_PC21) // Data Bus [21] -#define AT91C_PIO_PC22 (1u << 22) // Pin Controlled by PC22 #define AT91C_PC22_D22 (AT91C_PIO_PC22) // Data Bus [22] -#define AT91C_PIO_PC23 (1u << 23) // Pin Controlled by PC23 #define AT91C_PC23_D23 (AT91C_PIO_PC23) // Data Bus [23] -#define AT91C_PIO_PC24 (1u << 24) // Pin Controlled by PC24 #define AT91C_PC24_D24 (AT91C_PIO_PC24) // Data Bus [24] -#define AT91C_PIO_PC25 (1u << 25) // Pin Controlled by PC25 #define AT91C_PC25_D25 (AT91C_PIO_PC25) // Data Bus [25] -#define AT91C_PIO_PC26 (1u << 26) // Pin Controlled by PC26 #define AT91C_PC26_D26 (AT91C_PIO_PC26) // Data Bus [26] -#define AT91C_PIO_PC27 (1u << 27) // Pin Controlled by PC27 #define AT91C_PC27_D27 (AT91C_PIO_PC27) // Data Bus [27] -#define AT91C_PIO_PC28 (1u << 28) // Pin Controlled by PC28 #define AT91C_PC28_D28 (AT91C_PIO_PC28) // Data Bus [28] -#define AT91C_PIO_PC29 (1u << 29) // Pin Controlled by PC29 #define AT91C_PC29_D29 (AT91C_PIO_PC29) // Data Bus [29] -#define AT91C_PIO_PC3 (1u << 3) // Pin Controlled by PC3 #define AT91C_PC3_BFBAA_SMWE (AT91C_PIO_PC3) // Burst Flash Address Advance / SmartMedia Write Enable -#define AT91C_PIO_PC30 (1u << 30) // Pin Controlled by PC30 #define AT91C_PC30_D30 (AT91C_PIO_PC30) // Data Bus [30] -#define AT91C_PIO_PC31 (1u << 31) // Pin Controlled by PC31 #define AT91C_PC31_D31 (AT91C_PIO_PC31) // Data Bus [31] -#define AT91C_PIO_PC4 (1u << 4) // Pin Controlled by PC4 #define AT91C_PC4_BFOE (AT91C_PIO_PC4) // Burst Flash Output Enable -#define AT91C_PIO_PC5 (1u << 5) // Pin Controlled by PC5 #define AT91C_PC5_BFWE (AT91C_PIO_PC5) // Burst Flash Write Enable -#define AT91C_PIO_PC6 (1u << 6) // Pin Controlled by PC6 #define AT91C_PC6_NWAIT (AT91C_PIO_PC6) // NWAIT -#define AT91C_PIO_PC7 (1u << 7) // Pin Controlled by PC7 #define AT91C_PC7_A23 (AT91C_PIO_PC7) // Address Bus[23] -#define AT91C_PIO_PC8 (1u << 8) // Pin Controlled by PC8 #define AT91C_PC8_A24 (AT91C_PIO_PC8) // Address Bus[24] -#define AT91C_PIO_PC9 (1u << 9) // Pin Controlled by PC9 #define AT91C_PC9_A25_CFRNW (AT91C_PIO_PC9) // Address Bus[25] / Compact Flash Read Not Write -#define AT91C_PIO_PD0 (1u << 0) // Pin Controlled by PD0 #define AT91C_PD0_ETX0 (AT91C_PIO_PD0) // Ethernet MAC Transmit Data 0 -#define AT91C_PIO_PD1 (1u << 1) // Pin Controlled by PD1 #define AT91C_PD1_ETX1 (AT91C_PIO_PD1) // Ethernet MAC Transmit Data 1 -#define AT91C_PIO_PD10 (1u << 10) // Pin Controlled by PD10 #define AT91C_PD10_PCK3 (AT91C_PIO_PD10) // PMC Programmable Clock Output 3 #define AT91C_PD10_TPS1 (AT91C_PIO_PD10) // ETM ARM9 pipeline status 1 -#define AT91C_PIO_PD11 (1u << 11) // Pin Controlled by PD11 #define AT91C_PD11_ (AT91C_PIO_PD11) // #define AT91C_PD11_TPS2 (AT91C_PIO_PD11) // ETM ARM9 pipeline status 2 -#define AT91C_PIO_PD12 (1u << 12) // Pin Controlled by PD12 #define AT91C_PD12_ (AT91C_PIO_PD12) // #define AT91C_PD12_TPK0 (AT91C_PIO_PD12) // ETM Trace Packet 0 -#define AT91C_PIO_PD13 (1u << 13) // Pin Controlled by PD13 #define AT91C_PD13_ (AT91C_PIO_PD13) // #define AT91C_PD13_TPK1 (AT91C_PIO_PD13) // ETM Trace Packet 1 -#define AT91C_PIO_PD14 (1u << 14) // Pin Controlled by PD14 #define AT91C_PD14_ (AT91C_PIO_PD14) // #define AT91C_PD14_TPK2 (AT91C_PIO_PD14) // ETM Trace Packet 2 -#define AT91C_PIO_PD15 (1u << 15) // Pin Controlled by PD15 #define AT91C_PD15_TD0 (AT91C_PIO_PD15) // SSC Transmit data #define AT91C_PD15_TPK3 (AT91C_PIO_PD15) // ETM Trace Packet 3 -#define AT91C_PIO_PD16 (1u << 16) // Pin Controlled by PD16 #define AT91C_PD16_TD1 (AT91C_PIO_PD16) // SSC Transmit Data 1 #define AT91C_PD16_TPK4 (AT91C_PIO_PD16) // ETM Trace Packet 4 -#define AT91C_PIO_PD17 (1u << 17) // Pin Controlled by PD17 #define AT91C_PD17_TD2 (AT91C_PIO_PD17) // SSC Transmit Data 2 #define AT91C_PD17_TPK5 (AT91C_PIO_PD17) // ETM Trace Packet 5 -#define AT91C_PIO_PD18 (1u << 18) // Pin Controlled by PD18 #define AT91C_PD18_NPCS1 (AT91C_PIO_PD18) // SPI Peripheral Chip Select 1 #define AT91C_PD18_TPK6 (AT91C_PIO_PD18) // ETM Trace Packet 6 -#define AT91C_PIO_PD19 (1u << 19) // Pin Controlled by PD19 #define AT91C_PD19_NPCS2 (AT91C_PIO_PD19) // SPI Peripheral Chip Select 2 #define AT91C_PD19_TPK7 (AT91C_PIO_PD19) // ETM Trace Packet 7 -#define AT91C_PIO_PD2 (1u << 2) // Pin Controlled by PD2 #define AT91C_PD2_ETX2 (AT91C_PIO_PD2) // Ethernet MAC Transmit Data 2 -#define AT91C_PIO_PD20 (1u << 20) // Pin Controlled by PD20 #define AT91C_PD20_NPCS3 (AT91C_PIO_PD20) // SPI Peripheral Chip Select 3 #define AT91C_PD20_TPK8 (AT91C_PIO_PD20) // ETM Trace Packet 8 -#define AT91C_PIO_PD21 (1u << 21) // Pin Controlled by PD21 #define AT91C_PD21_RTS0 (AT91C_PIO_PD21) // Usart 0 Ready To Send #define AT91C_PD21_TPK9 (AT91C_PIO_PD21) // ETM Trace Packet 9 -#define AT91C_PIO_PD22 (1u << 22) // Pin Controlled by PD22 #define AT91C_PD22_RTS1 (AT91C_PIO_PD22) // Usart 0 Ready To Send #define AT91C_PD22_TPK10 (AT91C_PIO_PD22) // ETM Trace Packet 10 -#define AT91C_PIO_PD23 (1u << 23) // Pin Controlled by PD23 #define AT91C_PD23_RTS2 (AT91C_PIO_PD23) // USART 2 Ready To Send #define AT91C_PD23_TPK11 (AT91C_PIO_PD23) // ETM Trace Packet 11 -#define AT91C_PIO_PD24 (1u << 24) // Pin Controlled by PD24 #define AT91C_PD24_RTS3 (AT91C_PIO_PD24) // USART 3 Ready To Send #define AT91C_PD24_TPK12 (AT91C_PIO_PD24) // ETM Trace Packet 12 -#define AT91C_PIO_PD25 (1u << 25) // Pin Controlled by PD25 #define AT91C_PD25_DTR1 (AT91C_PIO_PD25) // USART 1 Data Terminal ready #define AT91C_PD25_TPK13 (AT91C_PIO_PD25) // ETM Trace Packet 13 -#define AT91C_PIO_PD26 (1u << 26) // Pin Controlled by PD26 #define AT91C_PD26_TPK14 (AT91C_PIO_PD26) // ETM Trace Packet 14 -#define AT91C_PIO_PD27 (1u << 27) // Pin Controlled by PD27 #define AT91C_PD27_TPK15 (AT91C_PIO_PD27) // ETM Trace Packet 15 -#define AT91C_PIO_PD3 (1u << 3) // Pin Controlled by PD3 #define AT91C_PD3_ETX3 (AT91C_PIO_PD3) // Ethernet MAC Transmit Data 3 -#define AT91C_PIO_PD4 (1u << 4) // Pin Controlled by PD4 #define AT91C_PD4_ETXEN (AT91C_PIO_PD4) // Ethernet MAC Transmit Enable -#define AT91C_PIO_PD5 (1u << 5) // Pin Controlled by PD5 #define AT91C_PD5_ETXER (AT91C_PIO_PD5) // Ethernet MAC Transmikt Coding Error -#define AT91C_PIO_PD6 (1u << 6) // Pin Controlled by PD6 #define AT91C_PD6_DTXD (AT91C_PIO_PD6) // DBGU Debug Transmit Data -#define AT91C_PIO_PD7 (1u << 7) // Pin Controlled by PD7 #define AT91C_PD7_PCK0 (AT91C_PIO_PD7) // PMC Programmable Clock Output 0 #define AT91C_PD7_TSYNC (AT91C_PIO_PD7) // ETM Synchronization signal -#define AT91C_PIO_PD8 (1u << 8) // Pin Controlled by PD8 #define AT91C_PD8_PCK1 (AT91C_PIO_PD8) // PMC Programmable Clock Output 1 #define AT91C_PD8_TCLK (AT91C_PIO_PD8) // ETM Trace Clock signal -#define AT91C_PIO_PD9 (1u << 9) // Pin Controlled by PD9 #define AT91C_PD9_PCK2 (AT91C_PIO_PD9) // PMC Programmable Clock 2 #define AT91C_PD9_TPS0 (AT91C_PIO_PD9) // ETM ARM9 pipeline status 0 + +#endif /* ARM_AT91_AT91_PIO_RM9200_H */ diff --git a/sys/arm/at91/at91_pio_sam9.h b/sys/arm/at91/at91_pio_sam9.h deleted file mode 100644 index d3c8f0655e6..00000000000 --- a/sys/arm/at91/at91_pio_sam9.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Theses defines come from an atmel file that says specifically that it - * has no copyright. - */ - -/* $FreeBSD$ */ - -// ***************************************************************************** -// PIO DEFINITIONS FOR AT91SAM9261 -// ***************************************************************************** -#define AT91C_PIO_PA0 ((unsigned int) 1 << 0) // Pin Controlled by PA0 -#define AT91C_PA0_MISO0 ((unsigned int) AT91C_PIO_PA0) // SPI0 Master In Slave -#define AT91C_PA0_MCDA0 ((unsigned int) AT91C_PIO_PA0) // Multimedia Card A Data 0 -#define AT91C_PIO_PA1 ((unsigned int) 1 << 1) // Pin Controlled by PA1 -#define AT91C_PA1_MOSI0 ((unsigned int) AT91C_PIO_PA1) // SPI0 Master Out Slave -#define AT91C_PA1_MCCDA ((unsigned int) AT91C_PIO_PA1) // Multimedia Card A Command -#define AT91C_PIO_PA10 ((unsigned int) 1 << 10) // Pin Controlled by PA10 -#define AT91C_PA10_DTXD ((unsigned int) AT91C_PIO_PA10) // DBGU Debug Transmit Data -#define AT91C_PA10_PCK3 ((unsigned int) AT91C_PIO_PA10) // PMC Programmable clock Output 3 -#define AT91C_PIO_PA11 ((unsigned int) 1 << 11) // Pin Controlled by PA11 -#define AT91C_PA11_TSYNC ((unsigned int) AT91C_PIO_PA11) // Trace Synchronization Signal -#define AT91C_PA11_SCK1 ((unsigned int) AT91C_PIO_PA11) // USART1 Serial Clock -#define AT91C_PIO_PA12 ((unsigned int) 1 << 12) // Pin Controlled by PA12 -#define AT91C_PA12_TCLK ((unsigned int) AT91C_PIO_PA12) // Trace Clock -#define AT91C_PA12_RTS1 ((unsigned int) AT91C_PIO_PA12) // USART1 Ready To Send -#define AT91C_PIO_PA13 ((unsigned int) 1 << 13) // Pin Controlled by PA13 -#define AT91C_PA13_TPS0 ((unsigned int) AT91C_PIO_PA13) // Trace ARM Pipeline Status 0 -#define AT91C_PA13_CTS1 ((unsigned int) AT91C_PIO_PA13) // USART1 Clear To Send -#define AT91C_PIO_PA14 ((unsigned int) 1 << 14) // Pin Controlled by PA14 -#define AT91C_PA14_TPS1 ((unsigned int) AT91C_PIO_PA14) // Trace ARM Pipeline Status 1 -#define AT91C_PA14_SCK2 ((unsigned int) AT91C_PIO_PA14) // USART2 Serial Clock -#define AT91C_PIO_PA15 ((unsigned int) 1 << 15) // Pin Controlled by PA15 -#define AT91C_PA15_TPS2 ((unsigned int) AT91C_PIO_PA15) // Trace ARM Pipeline Status 2 -#define AT91C_PA15_RTS2 ((unsigned int) AT91C_PIO_PA15) // USART2 Ready To Send -#define AT91C_PIO_PA16 ((unsigned int) 1 << 16) // Pin Controlled by PA16 -#define AT91C_PA16_TPK0 ((unsigned int) AT91C_PIO_PA16) // Trace Packet Port 0 -#define AT91C_PA16_CTS2 ((unsigned int) AT91C_PIO_PA16) // USART2 Clear To Send -#define AT91C_PIO_PA17 ((unsigned int) 1 << 17) // Pin Controlled by PA17 -#define AT91C_PA17_TPK1 ((unsigned int) AT91C_PIO_PA17) // Trace Packet Port 1 -#define AT91C_PA17_TF1 ((unsigned int) AT91C_PIO_PA17) // SSC1 Transmit Frame Sync -#define AT91C_PIO_PA18 ((unsigned int) 1 << 18) // Pin Controlled by PA18 -#define AT91C_PA18_TPK2 ((unsigned int) AT91C_PIO_PA18) // Trace Packet Port 2 -#define AT91C_PA18_TK1 ((unsigned int) AT91C_PIO_PA18) // SSC1 Transmit Clock -#define AT91C_PIO_PA19 ((unsigned int) 1 << 19) // Pin Controlled by PA19 -#define AT91C_PA19_TPK3 ((unsigned int) AT91C_PIO_PA19) // Trace Packet Port 3 -#define AT91C_PA19_TD1 ((unsigned int) AT91C_PIO_PA19) // SSC1 Transmit Data -#define AT91C_PIO_PA2 ((unsigned int) 1 << 2) // Pin Controlled by PA2 -#define AT91C_PA2_SPCK0 ((unsigned int) AT91C_PIO_PA2) // SPI0 Serial Clock -#define AT91C_PA2_MCCK ((unsigned int) AT91C_PIO_PA2) // Multimedia Card Clock -#define AT91C_PIO_PA20 ((unsigned int) 1 << 20) // Pin Controlled by PA20 -#define AT91C_PA20_TPK4 ((unsigned int) AT91C_PIO_PA20) // Trace Packet Port 4 -#define AT91C_PA20_RD1 ((unsigned int) AT91C_PIO_PA20) // SSC1 Receive Data -#define AT91C_PIO_PA21 ((unsigned int) 1 << 21) // Pin Controlled by PA21 -#define AT91C_PA21_TPK5 ((unsigned int) AT91C_PIO_PA21) // Trace Packet Port 5 -#define AT91C_PA21_RK1 ((unsigned int) AT91C_PIO_PA21) // SSC1 Receive Clock -#define AT91C_PIO_PA22 ((unsigned int) 1 << 22) // Pin Controlled by PA22 -#define AT91C_PA22_TPK6 ((unsigned int) AT91C_PIO_PA22) // Trace Packet Port 6 -#define AT91C_PA22_RF1 ((unsigned int) AT91C_PIO_PA22) // SSC1 Receive Frame Sync -#define AT91C_PIO_PA23 ((unsigned int) 1 << 23) // Pin Controlled by PA23 -#define AT91C_PA23_TPK7 ((unsigned int) AT91C_PIO_PA23) // Trace Packet Port 7 -#define AT91C_PA23_RTS0 ((unsigned int) AT91C_PIO_PA23) // USART0 Ready To Send -#define AT91C_PIO_PA24 ((unsigned int) 1 << 24) // Pin Controlled by PA24 -#define AT91C_PA24_TPK8 ((unsigned int) AT91C_PIO_PA24) // Trace Packet Port 8 -#define AT91C_PA24_NPCS11 ((unsigned int) AT91C_PIO_PA24) // SPI1 Peripheral Chip Select 1 -#define AT91C_PIO_PA25 ((unsigned int) 1 << 25) // Pin Controlled by PA25 -#define AT91C_PA25_TPK9 ((unsigned int) AT91C_PIO_PA25) // Trace Packet Port 9 -#define AT91C_PA25_NPCS12 ((unsigned int) AT91C_PIO_PA25) // SPI1 Peripheral Chip Select 2 -#define AT91C_PIO_PA26 ((unsigned int) 1 << 26) // Pin Controlled by PA26 -#define AT91C_PA26_TPK10 ((unsigned int) AT91C_PIO_PA26) // Trace Packet Port 10 -#define AT91C_PA26_NPCS13 ((unsigned int) AT91C_PIO_PA26) // SPI1 Peripheral Chip Select 3 -#define AT91C_PIO_PA27 ((unsigned int) 1 << 27) // Pin Controlled by PA27 -#define AT91C_PA27_TPK11 ((unsigned int) AT91C_PIO_PA27) // Trace Packet Port 11 -#define AT91C_PA27_NPCS01 ((unsigned int) AT91C_PIO_PA27) // SPI0 Peripheral Chip Select 1 -#define AT91C_PIO_PA28 ((unsigned int) 1 << 28) // Pin Controlled by PA28 -#define AT91C_PA28_TPK12 ((unsigned int) AT91C_PIO_PA28) // Trace Packet Port 12 -#define AT91C_PA28_NPCS02 ((unsigned int) AT91C_PIO_PA28) // SPI0 Peripheral Chip Select 2 -#define AT91C_PIO_PA29 ((unsigned int) 1 << 29) // Pin Controlled by PA29 -#define AT91C_PA29_TPK13 ((unsigned int) AT91C_PIO_PA29) // Trace Packet Port 13 -#define AT91C_PA29_NPCS03 ((unsigned int) AT91C_PIO_PA29) // SPI0 Peripheral Chip Select 3 -#define AT91C_PIO_PA3 ((unsigned int) 1 << 3) // Pin Controlled by PA3 -#define AT91C_PA3_NPCS00 ((unsigned int) AT91C_PIO_PA3) // SPI0 Peripheral Chip Select 0 -#define AT91C_PIO_PA30 ((unsigned int) 1 << 30) // Pin Controlled by PA30 -#define AT91C_PA30_TPK14 ((unsigned int) AT91C_PIO_PA30) // Trace Packet Port 14 -#define AT91C_PA30_A23 ((unsigned int) AT91C_PIO_PA30) // Address Bus bit 23 -#define AT91C_PIO_PA31 ((unsigned int) 1 << 31) // Pin Controlled by PA31 -#define AT91C_PA31_TPK15 ((unsigned int) AT91C_PIO_PA31) // Trace Packet Port 15 -#define AT91C_PA31_A24 ((unsigned int) AT91C_PIO_PA31) // Address Bus bit 24 -#define AT91C_PIO_PA4 ((unsigned int) 1 << 4) // Pin Controlled by PA4 -#define AT91C_PA4_NPCS01 ((unsigned int) AT91C_PIO_PA4) // SPI0 Peripheral Chip Select 1 -#define AT91C_PA4_MCDA1 ((unsigned int) AT91C_PIO_PA4) // Multimedia Card A Data 1 -#define AT91C_PIO_PA5 ((unsigned int) 1 << 5) // Pin Controlled by PA5 -#define AT91C_PA5_NPCS02 ((unsigned int) AT91C_PIO_PA5) // SPI0 Peripheral Chip Select 2 -#define AT91C_PA5_MCDA2 ((unsigned int) AT91C_PIO_PA5) // Multimedia Card A Data 2 -#define AT91C_PIO_PA6 ((unsigned int) 1 << 6) // Pin Controlled by PA6 -#define AT91C_PA6_NPCS03 ((unsigned int) AT91C_PIO_PA6) // SPI0 Peripheral Chip Select 3 -#define AT91C_PA6_MCDA3 ((unsigned int) AT91C_PIO_PA6) // Multimedia Card A Data 3 -#define AT91C_PIO_PA7 ((unsigned int) 1 << 7) // Pin Controlled by PA7 -#define AT91C_PA7_TWD ((unsigned int) AT91C_PIO_PA7) // TWI Two-wire Serial Data -#define AT91C_PA7_PCK0 ((unsigned int) AT91C_PIO_PA7) // PMC Programmable clock Output 0 -#define AT91C_PIO_PA8 ((unsigned int) 1 << 8) // Pin Controlled by PA8 -#define AT91C_PA8_TWCK ((unsigned int) AT91C_PIO_PA8) // TWI Two-wire Serial Clock -#define AT91C_PA8_PCK1 ((unsigned int) AT91C_PIO_PA8) // PMC Programmable clock Output 1 -#define AT91C_PIO_PA9 ((unsigned int) 1 << 9) // Pin Controlled by PA9 -#define AT91C_PA9_DRXD ((unsigned int) AT91C_PIO_PA9) // DBGU Debug Receive Data -#define AT91C_PA9_PCK2 ((unsigned int) AT91C_PIO_PA9) // PMC Programmable clock Output 2 -#define AT91C_PIO_PB0 ((unsigned int) 1 << 0) // Pin Controlled by PB0 -#define AT91C_PB0_LCDVSYNC ((unsigned int) AT91C_PIO_PB0) // LCD Vertical Synchronization -#define AT91C_PIO_PB1 ((unsigned int) 1 << 1) // Pin Controlled by PB1 -#define AT91C_PB1_LCDHSYNC ((unsigned int) AT91C_PIO_PB1) // LCD Horizontal Synchronization -#define AT91C_PIO_PB10 ((unsigned int) 1 << 10) // Pin Controlled by PB10 -#define AT91C_PB10_LCDD5 ((unsigned int) AT91C_PIO_PB10) // LCD Data Bus Bit 5 -#define AT91C_PB10_LCDD10 ((unsigned int) AT91C_PIO_PB10) // LCD Data Bus Bit 10 -#define AT91C_PIO_PB11 ((unsigned int) 1 << 11) // Pin Controlled by PB11 -#define AT91C_PB11_LCDD6 ((unsigned int) AT91C_PIO_PB11) // LCD Data Bus Bit 6 -#define AT91C_PB11_LCDD11 ((unsigned int) AT91C_PIO_PB11) // LCD Data Bus Bit 11 -#define AT91C_PIO_PB12 ((unsigned int) 1 << 12) // Pin Controlled by PB12 -#define AT91C_PB12_LCDD7 ((unsigned int) AT91C_PIO_PB12) // LCD Data Bus Bit 7 -#define AT91C_PB12_LCDD12 ((unsigned int) AT91C_PIO_PB12) // LCD Data Bus Bit 12 -#define AT91C_PIO_PB13 ((unsigned int) 1 << 13) // Pin Controlled by PB13 -#define AT91C_PB13_LCDD8 ((unsigned int) AT91C_PIO_PB13) // LCD Data Bus Bit 8 -#define AT91C_PB13_LCDD13 ((unsigned int) AT91C_PIO_PB13) // LCD Data Bus Bit 13 -#define AT91C_PIO_PB14 ((unsigned int) 1 << 14) // Pin Controlled by PB14 -#define AT91C_PB14_LCDD9 ((unsigned int) AT91C_PIO_PB14) // LCD Data Bus Bit 9 -#define AT91C_PB14_LCDD14 ((unsigned int) AT91C_PIO_PB14) // LCD Data Bus Bit 14 -#define AT91C_PIO_PB15 ((unsigned int) 1 << 15) // Pin Controlled by PB15 -#define AT91C_PB15_LCDD10 ((unsigned int) AT91C_PIO_PB15) // LCD Data Bus Bit 10 -#define AT91C_PB15_LCDD15 ((unsigned int) AT91C_PIO_PB15) // LCD Data Bus Bit 15 -#define AT91C_PIO_PB16 ((unsigned int) 1 << 16) // Pin Controlled by PB16 -#define AT91C_PB16_LCDD11 ((unsigned int) AT91C_PIO_PB16) // LCD Data Bus Bit 11 -#define AT91C_PB16_LCDD19 ((unsigned int) AT91C_PIO_PB16) // LCD Data Bus Bit 19 -#define AT91C_PIO_PB17 ((unsigned int) 1 << 17) // Pin Controlled by PB17 -#define AT91C_PB17_LCDD12 ((unsigned int) AT91C_PIO_PB17) // LCD Data Bus Bit 12 -#define AT91C_PB17_LCDD20 ((unsigned int) AT91C_PIO_PB17) // LCD Data Bus Bit 20 -#define AT91C_PIO_PB18 ((unsigned int) 1 << 18) // Pin Controlled by PB18 -#define AT91C_PB18_LCDD13 ((unsigned int) AT91C_PIO_PB18) // LCD Data Bus Bit 13 -#define AT91C_PB18_LCDD21 ((unsigned int) AT91C_PIO_PB18) // LCD Data Bus Bit 21 -#define AT91C_PIO_PB19 ((unsigned int) 1 << 19) // Pin Controlled by PB19 -#define AT91C_PB19_LCDD14 ((unsigned int) AT91C_PIO_PB19) // LCD Data Bus Bit 14 -#define AT91C_PB19_LCDD22 ((unsigned int) AT91C_PIO_PB19) // LCD Data Bus Bit 22 -#define AT91C_PIO_PB2 ((unsigned int) 1 << 2) // Pin Controlled by PB2 -#define AT91C_PB2_LCDDOTCK ((unsigned int) AT91C_PIO_PB2) // LCD Dot Clock -#define AT91C_PB2_PCK0 ((unsigned int) AT91C_PIO_PB2) // PMC Programmable clock Output 0 -#define AT91C_PIO_PB20 ((unsigned int) 1 << 20) // Pin Controlled by PB20 -#define AT91C_PB20_LCDD15 ((unsigned int) AT91C_PIO_PB20) // LCD Data Bus Bit 15 -#define AT91C_PB20_LCDD23 ((unsigned int) AT91C_PIO_PB20) // LCD Data Bus Bit 23 -#define AT91C_PIO_PB21 ((unsigned int) 1 << 21) // Pin Controlled by PB21 -#define AT91C_PB21_TF0 ((unsigned int) AT91C_PIO_PB21) // SSC0 Transmit Frame Sync -#define AT91C_PB21_LCDD16 ((unsigned int) AT91C_PIO_PB21) // LCD Data Bus Bit 16 -#define AT91C_PIO_PB22 ((unsigned int) 1 << 22) // Pin Controlled by PB22 -#define AT91C_PB22_TK0 ((unsigned int) AT91C_PIO_PB22) // SSC0 Transmit Clock -#define AT91C_PB22_LCDD17 ((unsigned int) AT91C_PIO_PB22) // LCD Data Bus Bit 17 -#define AT91C_PIO_PB23 ((unsigned int) 1 << 23) // Pin Controlled by PB23 -#define AT91C_PB23_TD0 ((unsigned int) AT91C_PIO_PB23) // SSC0 Transmit Data -#define AT91C_PB23_LCDD18 ((unsigned int) AT91C_PIO_PB23) // LCD Data Bus Bit 18 -#define AT91C_PIO_PB24 ((unsigned int) 1 << 24) // Pin Controlled by PB24 -#define AT91C_PB24_RD0 ((unsigned int) AT91C_PIO_PB24) // SSC0 Receive Data -#define AT91C_PB24_LCDD19 ((unsigned int) AT91C_PIO_PB24) // LCD Data Bus Bit 19 -#define AT91C_PIO_PB25 ((unsigned int) 1 << 25) // Pin Controlled by PB25 -#define AT91C_PB25_RK0 ((unsigned int) AT91C_PIO_PB25) // SSC0 Receive Clock -#define AT91C_PB25_LCDD20 ((unsigned int) AT91C_PIO_PB25) // LCD Data Bus Bit 20 -#define AT91C_PIO_PB26 ((unsigned int) 1 << 26) // Pin Controlled by PB26 -#define AT91C_PB26_RF0 ((unsigned int) AT91C_PIO_PB26) // SSC0 Receive Frame Sync -#define AT91C_PB26_LCDD21 ((unsigned int) AT91C_PIO_PB26) // LCD Data Bus Bit 21 -#define AT91C_PIO_PB27 ((unsigned int) 1 << 27) // Pin Controlled by PB27 -#define AT91C_PB27_NPCS11 ((unsigned int) AT91C_PIO_PB27) // SPI1 Peripheral Chip Select 1 -#define AT91C_PB27_LCDD22 ((unsigned int) AT91C_PIO_PB27) // LCD Data Bus Bit 22 -#define AT91C_PIO_PB28 ((unsigned int) 1 << 28) // Pin Controlled by PB28 -#define AT91C_PB28_NPCS10 ((unsigned int) AT91C_PIO_PB28) // SPI1 Peripheral Chip Select 0 -#define AT91C_PB28_LCDD23 ((unsigned int) AT91C_PIO_PB28) // LCD Data Bus Bit 23 -#define AT91C_PIO_PB29 ((unsigned int) 1 << 29) // Pin Controlled by PB29 -#define AT91C_PB29_SPCK1 ((unsigned int) AT91C_PIO_PB29) // SPI1 Serial Clock -#define AT91C_PB29_IRQ2 ((unsigned int) AT91C_PIO_PB29) // Interrupt input 2 -#define AT91C_PIO_PB3 ((unsigned int) 1 << 3) // Pin Controlled by PB3 -#define AT91C_PB3_LCDDEN ((unsigned int) AT91C_PIO_PB3) // LCD Data Enable -#define AT91C_PIO_PB30 ((unsigned int) 1 << 30) // Pin Controlled by PB30 -#define AT91C_PB30_MISO1 ((unsigned int) AT91C_PIO_PB30) // SPI1 Master In Slave -#define AT91C_PB30_IRQ1 ((unsigned int) AT91C_PIO_PB30) // Interrupt input 1 -#define AT91C_PIO_PB31 ((unsigned int) 1 << 31) // Pin Controlled by PB31 -#define AT91C_PB31_MOSI1 ((unsigned int) AT91C_PIO_PB31) // SPI1 Master Out Slave -#define AT91C_PB31_PCK2 ((unsigned int) AT91C_PIO_PB31) // PMC Programmable clock Output 2 -#define AT91C_PIO_PB4 ((unsigned int) 1 << 4) // Pin Controlled by PB4 -#define AT91C_PB4_LCDCC ((unsigned int) AT91C_PIO_PB4) // LCD Contrast Control -#define AT91C_PB4_LCDD2 ((unsigned int) AT91C_PIO_PB4) // LCD Data Bus Bit 2 -#define AT91C_PIO_PB5 ((unsigned int) 1 << 5) // Pin Controlled by PB5 -#define AT91C_PB5_LCDD0 ((unsigned int) AT91C_PIO_PB5) // LCD Data Bus Bit 0 -#define AT91C_PB5_LCDD3 ((unsigned int) AT91C_PIO_PB5) // LCD Data Bus Bit 3 -#define AT91C_PIO_PB6 ((unsigned int) 1 << 6) // Pin Controlled by PB6 -#define AT91C_PB6_LCDD1 ((unsigned int) AT91C_PIO_PB6) // LCD Data Bus Bit 1 -#define AT91C_PB6_LCDD4 ((unsigned int) AT91C_PIO_PB6) // LCD Data Bus Bit 4 -#define AT91C_PIO_PB7 ((unsigned int) 1 << 7) // Pin Controlled by PB7 -#define AT91C_PB7_LCDD2 ((unsigned int) AT91C_PIO_PB7) // LCD Data Bus Bit 2 -#define AT91C_PB7_LCDD5 ((unsigned int) AT91C_PIO_PB7) // LCD Data Bus Bit 5 -#define AT91C_PIO_PB8 ((unsigned int) 1 << 8) // Pin Controlled by PB8 -#define AT91C_PB8_LCDD3 ((unsigned int) AT91C_PIO_PB8) // LCD Data Bus Bit 3 -#define AT91C_PB8_LCDD6 ((unsigned int) AT91C_PIO_PB8) // LCD Data Bus Bit 6 -#define AT91C_PIO_PB9 ((unsigned int) 1 << 9) // Pin Controlled by PB9 -#define AT91C_PB9_LCDD4 ((unsigned int) AT91C_PIO_PB9) // LCD Data Bus Bit 4 -#define AT91C_PB9_LCDD7 ((unsigned int) AT91C_PIO_PB9) // LCD Data Bus Bit 7 -#define AT91C_PIO_PC0 ((unsigned int) 1 << 0) // Pin Controlled by PC0 -#define AT91C_PC0_SMOE ((unsigned int) AT91C_PIO_PC0) // SmartMedia Output Enable -#define AT91C_PC0_NCS6 ((unsigned int) AT91C_PIO_PC0) // Chip Select 6 -#define AT91C_PIO_PC1 ((unsigned int) 1 << 1) // Pin Controlled by PC1 -#define AT91C_PC1_SMWE ((unsigned int) AT91C_PIO_PC1) // SmartMedia Write Enable -#define AT91C_PC1_NCS7 ((unsigned int) AT91C_PIO_PC1) // Chip Select 7 -#define AT91C_PIO_PC10 ((unsigned int) 1 << 10) // Pin Controlled by PC10 -#define AT91C_PC10_RTS0 ((unsigned int) AT91C_PIO_PC10) // USART0 Ready To Send -#define AT91C_PC10_SCK0 ((unsigned int) AT91C_PIO_PC10) // USART0 Serial Clock -#define AT91C_PIO_PC11 ((unsigned int) 1 << 11) // Pin Controlled by PC11 -#define AT91C_PC11_CTS0 ((unsigned int) AT91C_PIO_PC11) // USART0 Clear To Send -#define AT91C_PC11_FIQ ((unsigned int) AT91C_PIO_PC11) // AIC Fast Interrupt Input -#define AT91C_PIO_PC12 ((unsigned int) 1 << 12) // Pin Controlled by PC12 -#define AT91C_PC12_TXD1 ((unsigned int) AT91C_PIO_PC12) // USART1 Transmit Data -#define AT91C_PC12_NCS6 ((unsigned int) AT91C_PIO_PC12) // Chip Select 6 -#define AT91C_PIO_PC13 ((unsigned int) 1 << 13) // Pin Controlled by PC13 -#define AT91C_PC13_RXD1 ((unsigned int) AT91C_PIO_PC13) // USART1 Receive Data -#define AT91C_PC13_NCS7 ((unsigned int) AT91C_PIO_PC13) // Chip Select 7 -#define AT91C_PIO_PC14 ((unsigned int) 1 << 14) // Pin Controlled by PC14 -#define AT91C_PC14_TXD2 ((unsigned int) AT91C_PIO_PC14) // USART2 Transmit Data -#define AT91C_PC14_NPCS12 ((unsigned int) AT91C_PIO_PC14) // SPI1 Peripheral Chip Select 2 -#define AT91C_PIO_PC15 ((unsigned int) 1 << 15) // Pin Controlled by PC15 -#define AT91C_PC15_RXD2 ((unsigned int) AT91C_PIO_PC15) // USART2 Receive Data -#define AT91C_PC15_NPCS13 ((unsigned int) AT91C_PIO_PC15) // SPI1 Peripheral Chip Select 3 -#define AT91C_PIO_PC16 ((unsigned int) 1 << 16) // Pin Controlled by PC16 -#define AT91C_PC16_D16 ((unsigned int) AT91C_PIO_PC16) // Data Bus [16] -#define AT91C_PC16_TCLK0 ((unsigned int) AT91C_PIO_PC16) // Timer Counter 0 external clock input -#define AT91C_PIO_PC17 ((unsigned int) 1 << 17) // Pin Controlled by PC17 -#define AT91C_PC17_D17 ((unsigned int) AT91C_PIO_PC17) // Data Bus [17] -#define AT91C_PC17_TCLK1 ((unsigned int) AT91C_PIO_PC17) // Timer Counter 1 external clock input -#define AT91C_PIO_PC18 ((unsigned int) 1 << 18) // Pin Controlled by PC18 -#define AT91C_PC18_D18 ((unsigned int) AT91C_PIO_PC18) // Data Bus [18] -#define AT91C_PC18_TCLK2 ((unsigned int) AT91C_PIO_PC18) // Timer Counter 2 external clock input -#define AT91C_PIO_PC19 ((unsigned int) 1 << 19) // Pin Controlled by PC19 -#define AT91C_PC19_D19 ((unsigned int) AT91C_PIO_PC19) // Data Bus [19] -#define AT91C_PC19_TIOA0 ((unsigned int) AT91C_PIO_PC19) // Timer Counter 0 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PC2 ((unsigned int) 1 << 2) // Pin Controlled by PC2 -#define AT91C_PC2_NWAIT ((unsigned int) AT91C_PIO_PC2) // NWAIT -#define AT91C_PC2_IRQ0 ((unsigned int) AT91C_PIO_PC2) // Interrupt input 0 -#define AT91C_PIO_PC20 ((unsigned int) 1 << 20) // Pin Controlled by PC20 -#define AT91C_PC20_D20 ((unsigned int) AT91C_PIO_PC20) // Data Bus [20] -#define AT91C_PC20_TIOB0 ((unsigned int) AT91C_PIO_PC20) // Timer Counter 0 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PC21 ((unsigned int) 1 << 21) // Pin Controlled by PC21 -#define AT91C_PC21_D21 ((unsigned int) AT91C_PIO_PC21) // Data Bus [21] -#define AT91C_PC21_TIOA1 ((unsigned int) AT91C_PIO_PC21) // Timer Counter 1 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PC22 ((unsigned int) 1 << 22) // Pin Controlled by PC22 -#define AT91C_PC22_D22 ((unsigned int) AT91C_PIO_PC22) // Data Bus [22] -#define AT91C_PC22_TIOB1 ((unsigned int) AT91C_PIO_PC22) // Timer Counter 1 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PC23 ((unsigned int) 1 << 23) // Pin Controlled by PC23 -#define AT91C_PC23_D23 ((unsigned int) AT91C_PIO_PC23) // Data Bus [23] -#define AT91C_PC23_TIOA2 ((unsigned int) AT91C_PIO_PC23) // Timer Counter 2 Multipurpose Timer I/O Pin A -#define AT91C_PIO_PC24 ((unsigned int) 1 << 24) // Pin Controlled by PC24 -#define AT91C_PC24_D24 ((unsigned int) AT91C_PIO_PC24) // Data Bus [24] -#define AT91C_PC24_TIOB2 ((unsigned int) AT91C_PIO_PC24) // Timer Counter 2 Multipurpose Timer I/O Pin B -#define AT91C_PIO_PC25 ((unsigned int) 1 << 25) // Pin Controlled by PC25 -#define AT91C_PC25_D25 ((unsigned int) AT91C_PIO_PC25) // Data Bus [25] -#define AT91C_PC25_TF2 ((unsigned int) AT91C_PIO_PC25) // SSC2 Transmit Frame Sync -#define AT91C_PIO_PC26 ((unsigned int) 1 << 26) // Pin Controlled by PC26 -#define AT91C_PC26_D26 ((unsigned int) AT91C_PIO_PC26) // Data Bus [26] -#define AT91C_PC26_TK2 ((unsigned int) AT91C_PIO_PC26) // SSC2 Transmit Clock -#define AT91C_PIO_PC27 ((unsigned int) 1 << 27) // Pin Controlled by PC27 -#define AT91C_PC27_D27 ((unsigned int) AT91C_PIO_PC27) // Data Bus [27] -#define AT91C_PC27_TD2 ((unsigned int) AT91C_PIO_PC27) // SSC2 Transmit Data -#define AT91C_PIO_PC28 ((unsigned int) 1 << 28) // Pin Controlled by PC28 -#define AT91C_PC28_D28 ((unsigned int) AT91C_PIO_PC28) // Data Bus [28] -#define AT91C_PC28_RD2 ((unsigned int) AT91C_PIO_PC28) // SSC2 Receive Data -#define AT91C_PIO_PC29 ((unsigned int) 1 << 29) // Pin Controlled by PC29 -#define AT91C_PC29_D29 ((unsigned int) AT91C_PIO_PC29) // Data Bus [29] -#define AT91C_PC29_RK2 ((unsigned int) AT91C_PIO_PC29) // SSC2 Receive Clock -#define AT91C_PIO_PC3 ((unsigned int) 1 << 3) // Pin Controlled by PC3 -#define AT91C_PC3_A25_CFRNW ((unsigned int) AT91C_PIO_PC3) // Address Bus[25] / Compact Flash Read Not Write -#define AT91C_PIO_PC30 ((unsigned int) 1 << 30) // Pin Controlled by PC30 -#define AT91C_PC30_D30 ((unsigned int) AT91C_PIO_PC30) // Data Bus [30] -#define AT91C_PC30_RF2 ((unsigned int) AT91C_PIO_PC30) // SSC2 Receive Frame Sync -#define AT91C_PIO_PC31 ((unsigned int) 1 << 31) // Pin Controlled by PC31 -#define AT91C_PC31_D31 ((unsigned int) AT91C_PIO_PC31) // Data Bus [31] -#define AT91C_PC31_PCK1 ((unsigned int) AT91C_PIO_PC31) // PMC Programmable clock Output 1 -#define AT91C_PIO_PC4 ((unsigned int) 1 << 4) // Pin Controlled by PC4 -#define AT91C_PC4_NCS4_CFCS0 ((unsigned int) AT91C_PIO_PC4) // Chip Select 4 / CompactFlash Chip Select 0 -#define AT91C_PIO_PC5 ((unsigned int) 1 << 5) // Pin Controlled by PC5 -#define AT91C_PC5_NCS5_CFCS1 ((unsigned int) AT91C_PIO_PC5) // Chip Select 5 / CompactFlash Chip Select 1 -#define AT91C_PIO_PC6 ((unsigned int) 1 << 6) // Pin Controlled by PC6 -#define AT91C_PC6_CFCE1 ((unsigned int) AT91C_PIO_PC6) // CompactFlash Chip Enable 1 -#define AT91C_PIO_PC7 ((unsigned int) 1 << 7) // Pin Controlled by PC7 -#define AT91C_PC7_CFCE2 ((unsigned int) AT91C_PIO_PC7) // CompactFlash Chip Enable 2 -#define AT91C_PIO_PC8 ((unsigned int) 1 << 8) // Pin Controlled by PC8 -#define AT91C_PC8_TXD0 ((unsigned int) AT91C_PIO_PC8) // USART0 Transmit Data -#define AT91C_PC8_PCK2 ((unsigned int) AT91C_PIO_PC8) // PMC Programmable clock Output 2 -#define AT91C_PIO_PC9 ((unsigned int) 1 << 9) // Pin Controlled by PC9 -#define AT91C_PC9_RXD0 ((unsigned int) AT91C_PIO_PC9) // USART0 Receive Data -#define AT91C_PC9_PCK3 ((unsigned int) AT91C_PIO_PC9) // PMC Programmable clock Output 3 - - diff --git a/sys/arm/at91/at91_pio_sam9g20.h b/sys/arm/at91/at91_pio_sam9g20.h new file mode 100644 index 00000000000..85923306e12 --- /dev/null +++ b/sys/arm/at91/at91_pio_sam9g20.h @@ -0,0 +1,183 @@ +/* + * Theses defines come from an atmel file that says specifically that it + * has no copyright. + * + * These defines are also usable for the AT91SAM9260 which has pin multiplexing + * that is identical to the AT91SAM9G20. + */ + +/* $FreeBSD$ */ + +#ifndef ARM_AT91_AT91_PIO_SAM9G20_H +#define ARM_AT91_AT91_PIO_SAM9G20_H + +#include + + +// ***************************************************************************** +// PIO DEFINITIONS FOR AT91SAM9G20 +// ***************************************************************************** +#define AT91C_PA0_SPI0_MISO (AT91C_PIO_PA0) // SPI 0 Master In Slave +#define AT91C_PA0_MCDB0 (AT91C_PIO_PA0) // Multimedia Card B Data 0 +#define AT91C_PA1_SPI0_MOSI (AT91C_PIO_PA1) // SPI 0 Master Out Slave +#define AT91C_PA1_MCCDB (AT91C_PIO_PA1) // Multimedia Card B Command +#define AT91C_PA10_MCDA2 (AT91C_PIO_PA10) // Multimedia Card A Data 2 +#define AT91C_PA10_ETX2_0 (AT91C_PIO_PA10) // Ethernet MAC Transmit Data 2 +#define AT91C_PA11_MCDA3 (AT91C_PIO_PA11) // Multimedia Card A Data 3 +#define AT91C_PA11_ETX3_0 (AT91C_PIO_PA11) // Ethernet MAC Transmit Data 3 +#define AT91C_PA12_ETX0 (AT91C_PIO_PA12) // Ethernet MAC Transmit Data 0 +#define AT91C_PA13_ETX1 (AT91C_PIO_PA13) // Ethernet MAC Transmit Data 1 +#define AT91C_PA14_ERX0 (AT91C_PIO_PA14) // Ethernet MAC Receive Data 0 +#define AT91C_PA15_ERX1 (AT91C_PIO_PA15) // Ethernet MAC Receive Data 1 +#define AT91C_PA16_ETXEN (AT91C_PIO_PA16) // Ethernet MAC Transmit Enable +#define AT91C_PA17_ERXDV (AT91C_PIO_PA17) // Ethernet MAC Receive Data Valid +#define AT91C_PA18_ERXER (AT91C_PIO_PA18) // Ethernet MAC Receive Error +#define AT91C_PA19_ETXCK (AT91C_PIO_PA19) // Ethernet MAC Transmit Clock/Reference Clock +#define AT91C_PA2_SPI0_SPCK (AT91C_PIO_PA2) // SPI 0 Serial Clock +#define AT91C_PA20_EMDC (AT91C_PIO_PA20) // Ethernet MAC Management Data Clock +#define AT91C_PA21_EMDIO (AT91C_PIO_PA21) // Ethernet MAC Management Data Input/Output +#define AT91C_PA22_ADTRG (AT91C_PIO_PA22) // ADC Trigger +#define AT91C_PA22_ETXER (AT91C_PIO_PA22) // Ethernet MAC Transmikt Coding Error +#define AT91C_PA23_TWD (AT91C_PIO_PA23) // TWI Two-wire Serial Data +#define AT91C_PA23_ETX2_1 (AT91C_PIO_PA23) // Ethernet MAC Transmit Data 2 +#define AT91C_PA24_TWCK (AT91C_PIO_PA24) // TWI Two-wire Serial Clock +#define AT91C_PA24_ETX3_1 (AT91C_PIO_PA24) // Ethernet MAC Transmit Data 3 +#define AT91C_PA25_TCLK0 (AT91C_PIO_PA25) // Timer Counter 0 external clock input +#define AT91C_PA25_ERX2 (AT91C_PIO_PA25) // Ethernet MAC Receive Data 2 +#define AT91C_PA26_TIOA0 (AT91C_PIO_PA26) // Timer Counter 0 Multipurpose Timer I/O Pin A +#define AT91C_PA26_ERX3 (AT91C_PIO_PA26) // Ethernet MAC Receive Data 3 +#define AT91C_PA27_TIOA1 (AT91C_PIO_PA27) // Timer Counter 1 Multipurpose Timer I/O Pin A +#define AT91C_PA27_ERXCK (AT91C_PIO_PA27) // Ethernet MAC Receive Clock +#define AT91C_PA28_TIOA2 (AT91C_PIO_PA28) // Timer Counter 2 Multipurpose Timer I/O Pin A +#define AT91C_PA28_ECRS (AT91C_PIO_PA28) // Ethernet MAC Carrier Sense/Carrier Sense and Data Valid +#define AT91C_PA29_SCK1 (AT91C_PIO_PA29) // USART 1 Serial Clock +#define AT91C_PA29_ECOL (AT91C_PIO_PA29) // Ethernet MAC Collision Detected +#define AT91C_PA3_SPI0_NPCS0 (AT91C_PIO_PA3) // SPI 0 Peripheral Chip Select 0 +#define AT91C_PA3_MCDB3 (AT91C_PIO_PA3) // Multimedia Card B Data 3 +#define AT91C_PA30_SCK2 (AT91C_PIO_PA30) // USART 2 Serial Clock +#define AT91C_PA30_RXD4 (AT91C_PIO_PA30) // USART 4 Receive Data +#define AT91C_PA31_SCK0 (AT91C_PIO_PA31) // USART 0 Serial Clock +#define AT91C_PA31_TXD4 (AT91C_PIO_PA31) // USART 4 Transmit Data +#define AT91C_PA4_RTS2 (AT91C_PIO_PA4) // USART 2 Ready To Send +#define AT91C_PA4_MCDB2 (AT91C_PIO_PA4) // Multimedia Card B Data 2 +#define AT91C_PA5_CTS2 (AT91C_PIO_PA5) // USART 2 Clear To Send +#define AT91C_PA5_MCDB1 (AT91C_PIO_PA5) // Multimedia Card B Data 1 +#define AT91C_PA6_MCDA0 (AT91C_PIO_PA6) // Multimedia Card A Data 0 +#define AT91C_PA7_MCCDA (AT91C_PIO_PA7) // Multimedia Card A Command +#define AT91C_PA8_MCCK (AT91C_PIO_PA8) // Multimedia Card Clock +#define AT91C_PA9_MCDA1 (AT91C_PIO_PA9) // Multimedia Card A Data 1 +#define AT91C_PB0_SPI1_MISO (AT91C_PIO_PB0) // SPI 1 Master In Slave +#define AT91C_PB0_TIOA3 (AT91C_PIO_PB0) // Timer Counter 3 Multipurpose Timer I/O Pin A +#define AT91C_PB1_SPI1_MOSI (AT91C_PIO_PB1) // SPI 1 Master Out Slave +#define AT91C_PB1_TIOB3 (AT91C_PIO_PB1) // Timer Counter 3 Multipurpose Timer I/O Pin B +#define AT91C_PB10_TXD3 (AT91C_PIO_PB10) // USART 3 Transmit Data +#define AT91C_PB10_ISI_D8 (AT91C_PIO_PB10) // Image Sensor Data 8 +#define AT91C_PB11_RXD3 (AT91C_PIO_PB11) // USART 3 Receive Data +#define AT91C_PB11_ISI_D9 (AT91C_PIO_PB11) // Image Sensor Data 9 +#define AT91C_PB12_TXD5 (AT91C_PIO_PB12) // USART 5 Transmit Data +#define AT91C_PB12_ISI_D10 (AT91C_PIO_PB12) // Image Sensor Data 10 +#define AT91C_PB13_RXD5 (AT91C_PIO_PB13) // USART 5 Receive Data +#define AT91C_PB13_ISI_D11 (AT91C_PIO_PB13) // Image Sensor Data 11 +#define AT91C_PB14_DRXD (AT91C_PIO_PB14) // DBGU Debug Receive Data +#define AT91C_PB15_DTXD (AT91C_PIO_PB15) // DBGU Debug Transmit Data +#define AT91C_PB16_TK0 (AT91C_PIO_PB16) // SSC0 Transmit Clock +#define AT91C_PB16_TCLK3 (AT91C_PIO_PB16) // Timer Counter 3 external clock input +#define AT91C_PB17_TF0 (AT91C_PIO_PB17) // SSC0 Transmit Frame Sync +#define AT91C_PB17_TCLK4 (AT91C_PIO_PB17) // Timer Counter 4 external clock input +#define AT91C_PB18_TD0 (AT91C_PIO_PB18) // SSC0 Transmit data +#define AT91C_PB18_TIOB4 (AT91C_PIO_PB18) // Timer Counter 4 Multipurpose Timer I/O Pin B +#define AT91C_PB19_RD0 (AT91C_PIO_PB19) // SSC0 Receive Data +#define AT91C_PB19_TIOB5 (AT91C_PIO_PB19) // Timer Counter 5 Multipurpose Timer I/O Pin B +#define AT91C_PB2_SPI1_SPCK (AT91C_PIO_PB2) // SPI 1 Serial Clock +#define AT91C_PB2_TIOA4 (AT91C_PIO_PB2) // Timer Counter 4 Multipurpose Timer I/O Pin A +#define AT91C_PB20_RK0 (AT91C_PIO_PB20) // SSC0 Receive Clock +#define AT91C_PB20_ISI_D0 (AT91C_PIO_PB20) // Image Sensor Data 0 +#define AT91C_PB21_RF0 (AT91C_PIO_PB21) // SSC0 Receive Frame Sync +#define AT91C_PB21_ISI_D1 (AT91C_PIO_PB21) // Image Sensor Data 1 +#define AT91C_PB22_DSR0 (AT91C_PIO_PB22) // USART 0 Data Set ready +#define AT91C_PB22_ISI_D2 (AT91C_PIO_PB22) // Image Sensor Data 2 +#define AT91C_PB23_DCD0 (AT91C_PIO_PB23) // USART 0 Data Carrier Detect +#define AT91C_PB23_ISI_D3 (AT91C_PIO_PB23) // Image Sensor Data 3 +#define AT91C_PB24_DTR0 (AT91C_PIO_PB24) // USART 0 Data Terminal ready +#define AT91C_PB24_ISI_D4 (AT91C_PIO_PB24) // Image Sensor Data 4 +#define AT91C_PB25_RI0 (AT91C_PIO_PB25) // USART 0 Ring Indicator +#define AT91C_PB25_ISI_D5 (AT91C_PIO_PB25) // Image Sensor Data 5 +#define AT91C_PB26_RTS0 (AT91C_PIO_PB26) // USART 0 Ready To Send +#define AT91C_PB26_ISI_D6 (AT91C_PIO_PB26) // Image Sensor Data 6 +#define AT91C_PB27_CTS0 (AT91C_PIO_PB27) // USART 0 Clear To Send +#define AT91C_PB27_ISI_D7 (AT91C_PIO_PB27) // Image Sensor Data 7 +#define AT91C_PB28_RTS1 (AT91C_PIO_PB28) // USART 1 Ready To Send +#define AT91C_PB28_ISI_PCK (AT91C_PIO_PB28) // Image Sensor Data Clock +#define AT91C_PB29_CTS1 (AT91C_PIO_PB29) // USART 1 Clear To Send +#define AT91C_PB29_ISI_VSYNC (AT91C_PIO_PB29) // Image Sensor Vertical Synchro +#define AT91C_PB3_SPI1_NPCS0 (AT91C_PIO_PB3) // SPI 1 Peripheral Chip Select 0 +#define AT91C_PB3_TIOA5 (AT91C_PIO_PB3) // Timer Counter 5 Multipurpose Timer I/O Pin A +#define AT91C_PB30_PCK0_0 (AT91C_PIO_PB30) // PMC Programmable Clock Output 0 +#define AT91C_PB30_ISI_HSYNC (AT91C_PIO_PB30) // Image Sensor Horizontal Synchro +#define AT91C_PB31_PCK1_0 (AT91C_PIO_PB31) // PMC Programmable Clock Output 1 +#define AT91C_PB31_ISI_MCK (AT91C_PIO_PB31) // Image Sensor Reference Clock +#define AT91C_PB4_TXD0 (AT91C_PIO_PB4) // USART 0 Transmit Data +#define AT91C_PB5_RXD0 (AT91C_PIO_PB5) // USART 0 Receive Data +#define AT91C_PB6_TXD1 (AT91C_PIO_PB6) // USART 1 Transmit Data +#define AT91C_PB6_TCLK1 (AT91C_PIO_PB6) // Timer Counter 1 external clock input +#define AT91C_PB7_RXD1 (AT91C_PIO_PB7) // USART 1 Receive Data +#define AT91C_PB7_TCLK2 (AT91C_PIO_PB7) // Timer Counter 2 external clock input +#define AT91C_PB8_TXD2 (AT91C_PIO_PB8) // USART 2 Transmit Data +#define AT91C_PB9_RXD2 (AT91C_PIO_PB9) // USART 2 Receive Data +#define AT91C_PC0_AD0 (AT91C_PIO_PC0) // ADC Analog Input 0 +#define AT91C_PC0_SCK3 (AT91C_PIO_PC0) // USART 3 Serial Clock +#define AT91C_PC1_AD1 (AT91C_PIO_PC1) // ADC Analog Input 1 +#define AT91C_PC1_PCK0_1 (AT91C_PIO_PC1) // PMC Programmable Clock Output 0 +#define AT91C_PC10_A25_CFR NW (AT91C_PIO_PC10) // Address Bus[25] +#define AT91C_PC10_CTS3 (AT91C_PIO_PC10) // USART 3 Clear To Send +#define AT91C_PC11_NCS2 (AT91C_PIO_PC11) // Chip Select Line 2 +#define AT91C_PC11_SPI0_NPCS1 (AT91C_PIO_PC11) // SPI 0 Peripheral Chip Select 1 +#define AT91C_PC12_IRQ0 (AT91C_PIO_PC12) // External Interrupt 0 +#define AT91C_PC12_NCS7 (AT91C_PIO_PC12) // Chip Select Line 7 +#define AT91C_PC13_FIQ (AT91C_PIO_PC13) // AIC Fast Interrupt Input +#define AT91C_PC13_NCS6 (AT91C_PIO_PC13) // Chip Select Line 6 +#define AT91C_PC14_NCS3_NANDCS (AT91C_PIO_PC14) // Chip Select Line 3 +#define AT91C_PC14_IRQ2 (AT91C_PIO_PC14) // External Interrupt 2 +#define AT91C_PC15_NWAIT (AT91C_PIO_PC15) // External Wait Signal +#define AT91C_PC15_IRQ1 (AT91C_PIO_PC15) // External Interrupt 1 +#define AT91C_PC16_D16 (AT91C_PIO_PC16) // Data Bus[16] +#define AT91C_PC16_SPI0_NPCS2 (AT91C_PIO_PC16) // SPI 0 Peripheral Chip Select 2 +#define AT91C_PC17_D17 (AT91C_PIO_PC17) // Data Bus[17] +#define AT91C_PC17_SPI0_NPCS3 (AT91C_PIO_PC17) // SPI 0 Peripheral Chip Select 3 +#define AT91C_PC18_D18 (AT91C_PIO_PC18) // Data Bus[18] +#define AT91C_PC18_SPI1_NPCS1_1 (AT91C_PIO_PC18) // SPI 1 Peripheral Chip Select 1 +#define AT91C_PC19_D19 (AT91C_PIO_PC19) // Data Bus[19] +#define AT91C_PC19_SPI1_NPCS2_1 (AT91C_PIO_PC19) // SPI 1 Peripheral Chip Select 2 +#define AT91C_PC2_AD2 (AT91C_PIO_PC2) // ADC Analog Input 2 +#define AT91C_PC2_PCK1_1 (AT91C_PIO_PC2) // PMC Programmable Clock Output 1 +#define AT91C_PC20_D20 (AT91C_PIO_PC20) // Data Bus[20] +#define AT91C_PC20_SPI1_NPCS3_1 (AT91C_PIO_PC20) // SPI 1 Peripheral Chip Select 3 +#define AT91C_PC21_D21 (AT91C_PIO_PC21) // Data Bus[21] +#define AT91C_PC21_EF100 (AT91C_PIO_PC21) // Ethernet MAC Force 100 Mbits/sec +#define AT91C_PC22_D22 (AT91C_PIO_PC22) // Data Bus[22] +#define AT91C_PC22_TCLK5 (AT91C_PIO_PC22) // Timer Counter 5 external clock input +#define AT91C_PC23_D23 (AT91C_PIO_PC23) // Data Bus[23] +#define AT91C_PC24_D24 (AT91C_PIO_PC24) // Data Bus[24] +#define AT91C_PC25_D25 (AT91C_PIO_PC25) // Data Bus[25] +#define AT91C_PC26_D26 (AT91C_PIO_PC26) // Data Bus[26] +#define AT91C_PC27_D27 (AT91C_PIO_PC27) // Data Bus[27] +#define AT91C_PC28_D28 (AT91C_PIO_PC28) // Data Bus[28] +#define AT91C_PC29_D29 (AT91C_PIO_PC29) // Data Bus[29] +#define AT91C_PC3_AD3 (AT91C_PIO_PC3) // ADC Analog Input 3 +#define AT91C_PC3_SPI1_NPCS3_0 (AT91C_PIO_PC3) // SPI 1 Peripheral Chip Select 3 +#define AT91C_PC30_D30 (AT91C_PIO_PC30) // Data Bus[30] +#define AT91C_PC31_D31 (AT91C_PIO_PC31) // Data Bus[31] +#define AT91C_PC4_A23 (AT91C_PIO_PC4) // Address Bus[23] +#define AT91C_PC4_SPI1_NPCS2_0 (AT91C_PIO_PC4) // SPI 1 Peripheral Chip Select 2 +#define AT91C_PC5_A24 (AT91C_PIO_PC5) // Address Bus[24] +#define AT91C_PC5_SPI1_NPCS1_0 (AT91C_PIO_PC5) // SPI 1 Peripheral Chip Select 1 +#define AT91C_PC6_TIOB2 (AT91C_PIO_PC6) // Timer Counter 2 Multipurpose Timer I/O Pin B +#define AT91C_PC6_CFCE1 (AT91C_PIO_PC6) // Compact Flash Enable 1 +#define AT91C_PC7_TIOB1 (AT91C_PIO_PC7) // Timer Counter 1 Multipurpose Timer I/O Pin B +#define AT91C_PC7_CFCE2 (AT91C_PIO_PC7) // Compact Flash Enable 2 +#define AT91C_PC8_NCS4_CFCS0 (AT91C_PIO_PC8) // Chip Select Line 4 +#define AT91C_PC8_RTS3 (AT91C_PIO_PC8) // USART 3 Ready To Send +#define AT91C_PC9_NCS5_CFCS1 (AT91C_PIO_PC9) // Chip Select Line 5 +#define AT91C_PC9_TIOB0 (AT91C_PIO_PC9) // Timer Counter 0 Multipurpose Timer I/O Pin B + +#endif /* ARM_AT91_AT91_PIO_SAM9G20_H */ diff --git a/sys/arm/at91/at91_pioreg.h b/sys/arm/at91/at91_pioreg.h index ccb6d422dc5..e3f2ea3d489 100644 --- a/sys/arm/at91/at91_pioreg.h +++ b/sys/arm/at91/at91_pioreg.h @@ -66,4 +66,101 @@ #define PIO_OWSR 0xa8 /* PIO Output Write Status Register */ /* 0xac reserved */ +#define AT91C_PIO_PA0 ((unsigned int) 1 << 0) // Pin Controlled by PA0 +#define AT91C_PIO_PA1 ((unsigned int) 1 << 1) // Pin Controlled by PA1 +#define AT91C_PIO_PA2 ((unsigned int) 1 << 2) // Pin Controlled by PA2 +#define AT91C_PIO_PA3 ((unsigned int) 1 << 3) // Pin Controlled by PA3 +#define AT91C_PIO_PA4 ((unsigned int) 1 << 4) // Pin Controlled by PA4 +#define AT91C_PIO_PA5 ((unsigned int) 1 << 5) // Pin Controlled by PA5 +#define AT91C_PIO_PA6 ((unsigned int) 1 << 6) // Pin Controlled by PA6 +#define AT91C_PIO_PA7 ((unsigned int) 1 << 7) // Pin Controlled by PA7 +#define AT91C_PIO_PA8 ((unsigned int) 1 << 8) // Pin Controlled by PA8 +#define AT91C_PIO_PA9 ((unsigned int) 1 << 9) // Pin Controlled by PA9 +#define AT91C_PIO_PA10 ((unsigned int) 1 << 10) // Pin Controlled by PA10 +#define AT91C_PIO_PA11 ((unsigned int) 1 << 11) // Pin Controlled by PA11 +#define AT91C_PIO_PA12 ((unsigned int) 1 << 12) // Pin Controlled by PA12 +#define AT91C_PIO_PA13 ((unsigned int) 1 << 13) // Pin Controlled by PA13 +#define AT91C_PIO_PA14 ((unsigned int) 1 << 14) // Pin Controlled by PA14 +#define AT91C_PIO_PA15 ((unsigned int) 1 << 15) // Pin Controlled by PA15 +#define AT91C_PIO_PA16 ((unsigned int) 1 << 16) // Pin Controlled by PA16 +#define AT91C_PIO_PA17 ((unsigned int) 1 << 17) // Pin Controlled by PA17 +#define AT91C_PIO_PA18 ((unsigned int) 1 << 18) // Pin Controlled by PA18 +#define AT91C_PIO_PA19 ((unsigned int) 1 << 19) // Pin Controlled by PA19 +#define AT91C_PIO_PA20 ((unsigned int) 1 << 20) // Pin Controlled by PA20 +#define AT91C_PIO_PA21 ((unsigned int) 1 << 21) // Pin Controlled by PA21 +#define AT91C_PIO_PA22 ((unsigned int) 1 << 22) // Pin Controlled by PA22 +#define AT91C_PIO_PA23 ((unsigned int) 1 << 23) // Pin Controlled by PA23 +#define AT91C_PIO_PA24 ((unsigned int) 1 << 24) // Pin Controlled by PA24 +#define AT91C_PIO_PA25 ((unsigned int) 1 << 25) // Pin Controlled by PA25 +#define AT91C_PIO_PA26 ((unsigned int) 1 << 26) // Pin Controlled by PA26 +#define AT91C_PIO_PA27 ((unsigned int) 1 << 27) // Pin Controlled by PA27 +#define AT91C_PIO_PA28 ((unsigned int) 1 << 28) // Pin Controlled by PA28 +#define AT91C_PIO_PA29 ((unsigned int) 1 << 29) // Pin Controlled by PA29 +#define AT91C_PIO_PA30 ((unsigned int) 1 << 30) // Pin Controlled by PA30 +#define AT91C_PIO_PA31 ((unsigned int) 1 << 31) // Pin Controlled by PA31 +#define AT91C_PIO_PB0 ((unsigned int) 1 << 0) // Pin Controlled by PB0 +#define AT91C_PIO_PB1 ((unsigned int) 1 << 1) // Pin Controlled by PB1 +#define AT91C_PIO_PB2 ((unsigned int) 1 << 2) // Pin Controlled by PB2 +#define AT91C_PIO_PB3 ((unsigned int) 1 << 3) // Pin Controlled by PB3 +#define AT91C_PIO_PB4 ((unsigned int) 1 << 4) // Pin Controlled by PB4 +#define AT91C_PIO_PB5 ((unsigned int) 1 << 5) // Pin Controlled by PB5 +#define AT91C_PIO_PB6 ((unsigned int) 1 << 6) // Pin Controlled by PB6 +#define AT91C_PIO_PB7 ((unsigned int) 1 << 7) // Pin Controlled by PB7 +#define AT91C_PIO_PB8 ((unsigned int) 1 << 8) // Pin Controlled by PB8 +#define AT91C_PIO_PB9 ((unsigned int) 1 << 9) // Pin Controlled by PB9 +#define AT91C_PIO_PB10 ((unsigned int) 1 << 10) // Pin Controlled by PB10 +#define AT91C_PIO_PB11 ((unsigned int) 1 << 11) // Pin Controlled by PB11 +#define AT91C_PIO_PB12 ((unsigned int) 1 << 12) // Pin Controlled by PB12 +#define AT91C_PIO_PB13 ((unsigned int) 1 << 13) // Pin Controlled by PB13 +#define AT91C_PIO_PB14 ((unsigned int) 1 << 14) // Pin Controlled by PB14 +#define AT91C_PIO_PB15 ((unsigned int) 1 << 15) // Pin Controlled by PB15 +#define AT91C_PIO_PB16 ((unsigned int) 1 << 16) // Pin Controlled by PB16 +#define AT91C_PIO_PB17 ((unsigned int) 1 << 17) // Pin Controlled by PB17 +#define AT91C_PIO_PB18 ((unsigned int) 1 << 18) // Pin Controlled by PB18 +#define AT91C_PIO_PB19 ((unsigned int) 1 << 19) // Pin Controlled by PB19 +#define AT91C_PIO_PB20 ((unsigned int) 1 << 20) // Pin Controlled by PB20 +#define AT91C_PIO_PB21 ((unsigned int) 1 << 21) // Pin Controlled by PB21 +#define AT91C_PIO_PB22 ((unsigned int) 1 << 22) // Pin Controlled by PB22 +#define AT91C_PIO_PB23 ((unsigned int) 1 << 23) // Pin Controlled by PB23 +#define AT91C_PIO_PB24 ((unsigned int) 1 << 24) // Pin Controlled by PB24 +#define AT91C_PIO_PB25 ((unsigned int) 1 << 25) // Pin Controlled by PB25 +#define AT91C_PIO_PB26 ((unsigned int) 1 << 26) // Pin Controlled by PB26 +#define AT91C_PIO_PB27 ((unsigned int) 1 << 27) // Pin Controlled by PB27 +#define AT91C_PIO_PB28 ((unsigned int) 1 << 28) // Pin Controlled by PB28 +#define AT91C_PIO_PB29 ((unsigned int) 1 << 29) // Pin Controlled by PB29 +#define AT91C_PIO_PB30 ((unsigned int) 1 << 30) // Pin Controlled by PB30 +#define AT91C_PIO_PB31 ((unsigned int) 1 << 31) // Pin Controlled by PB31 +#define AT91C_PIO_PC0 ((unsigned int) 1 << 0) // Pin Controlled by PC0 +#define AT91C_PIO_PC1 ((unsigned int) 1 << 1) // Pin Controlled by PC1 +#define AT91C_PIO_PC2 ((unsigned int) 1 << 2) // Pin Controlled by PC2 +#define AT91C_PIO_PC3 ((unsigned int) 1 << 3) // Pin Controlled by PC3 +#define AT91C_PIO_PC4 ((unsigned int) 1 << 4) // Pin Controlled by PC4 +#define AT91C_PIO_PC5 ((unsigned int) 1 << 5) // Pin Controlled by PC5 +#define AT91C_PIO_PC6 ((unsigned int) 1 << 6) // Pin Controlled by PC6 +#define AT91C_PIO_PC7 ((unsigned int) 1 << 7) // Pin Controlled by PC7 +#define AT91C_PIO_PC8 ((unsigned int) 1 << 8) // Pin Controlled by PC8 +#define AT91C_PIO_PC9 ((unsigned int) 1 << 9) // Pin Controlled by PC9 +#define AT91C_PIO_PC10 ((unsigned int) 1 << 10) // Pin Controlled by PC10 +#define AT91C_PIO_PC11 ((unsigned int) 1 << 11) // Pin Controlled by PC11 +#define AT91C_PIO_PC12 ((unsigned int) 1 << 12) // Pin Controlled by PC12 +#define AT91C_PIO_PC13 ((unsigned int) 1 << 13) // Pin Controlled by PC13 +#define AT91C_PIO_PC14 ((unsigned int) 1 << 14) // Pin Controlled by PC14 +#define AT91C_PIO_PC15 ((unsigned int) 1 << 15) // Pin Controlled by PC15 +#define AT91C_PIO_PC16 ((unsigned int) 1 << 16) // Pin Controlled by PC16 +#define AT91C_PIO_PC17 ((unsigned int) 1 << 17) // Pin Controlled by PC17 +#define AT91C_PIO_PC18 ((unsigned int) 1 << 18) // Pin Controlled by PC18 +#define AT91C_PIO_PC19 ((unsigned int) 1 << 19) // Pin Controlled by PC19 +#define AT91C_PIO_PC20 ((unsigned int) 1 << 20) // Pin Controlled by PC20 +#define AT91C_PIO_PC21 ((unsigned int) 1 << 21) // Pin Controlled by PC21 +#define AT91C_PIO_PC22 ((unsigned int) 1 << 22) // Pin Controlled by PC22 +#define AT91C_PIO_PC23 ((unsigned int) 1 << 23) // Pin Controlled by PC23 +#define AT91C_PIO_PC24 ((unsigned int) 1 << 24) // Pin Controlled by PC24 +#define AT91C_PIO_PC25 ((unsigned int) 1 << 25) // Pin Controlled by PC25 +#define AT91C_PIO_PC26 ((unsigned int) 1 << 26) // Pin Controlled by PC26 +#define AT91C_PIO_PC27 ((unsigned int) 1 << 27) // Pin Controlled by PC27 +#define AT91C_PIO_PC28 ((unsigned int) 1 << 28) // Pin Controlled by PC28 +#define AT91C_PIO_PC29 ((unsigned int) 1 << 29) // Pin Controlled by PC29 +#define AT91C_PIO_PC30 ((unsigned int) 1 << 30) // Pin Controlled by PC30 +#define AT91C_PIO_PC31 ((unsigned int) 1 << 31) // Pin Controlled by PC31 + #endif /* ARM_AT91_AT91_PIOREG_H */ diff --git a/sys/arm/at91/at91_pit.c b/sys/arm/at91/at91_pit.c index 516b4d48f80..6a6680fc103 100644 --- a/sys/arm/at91/at91_pit.c +++ b/sys/arm/at91/at91_pit.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2010 Yohanes Nugroho. All rights reserved. + * Copyright (c) 2009 Gallon Sylvestre. All rights reserved. + * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,110 +25,117 @@ */ #include +__FBSDID("$FreeBSD$"); #include -#include +#include #include #include -#include -#include #include +#include +#include +#include #include #include #include #include #include -#include #include #include +#include #include #include -#include -#include -__FBSDID("$FreeBSD$"); +static struct pit_softc { + struct resource *mem_res; /* Memory resource */ + void *intrhand; /* Interrupt handle */ + device_t sc_dev; +} *sc; -static struct at91pit_softc { - bus_space_tag_t sc_st; - bus_space_handle_t sc_sh; - device_t sc_dev; -} *pit_softc; +static uint32_t timecount = 0; -#define RD4(off) \ - bus_space_read_4(pit_softc->sc_st, pit_softc->sc_sh, (off)) -#define WR4(off, val) \ - bus_space_write_4(pit_softc->sc_st, pit_softc->sc_sh, (off), (val)) +static inline uint32_t +RD4(struct pit_softc *sc, bus_size_t off) +{ + return (bus_read_4(sc->mem_res, off)); +} + +static inline void +WR4(struct pit_softc *sc, bus_size_t off, uint32_t val) +{ + bus_write_4(sc->mem_res, off, val); +} static unsigned at91pit_get_timecount(struct timecounter *tc); -static int clock_intr(void *arg); +static int pit_intr(void *arg); + +#ifndef PIT_PRESCALE +#define PIT_PRESCALE (16) +#endif static struct timecounter at91pit_timecounter = { at91pit_get_timecount, /* get_timecount */ NULL, /* no poll_pps */ - 0xffffffffu, /* counter mask */ - 0, /* frequency */ - "AT91SAM9261 timer", /* name */ + 0xffffffff, /* counter mask */ + 0 / PIT_PRESCALE, /* frequency */ + "AT91SAM9 timer", /* name */ 1000 /* quality */ }; - -uint32_t -at91_pit_base(void); - -uint32_t -at91_pit_size(void); - static int at91pit_probe(device_t dev) { - device_set_desc(dev, "PIT"); - return (0); -} -uint32_t -at91_pit_base(void) -{ - return (AT91SAM9G20_PIT_BASE); + if (at91_is_sam9()) { + device_set_desc(dev, "AT91SAM9 PIT"); + return (0); + } + return (ENXIO); } -uint32_t -at91_pit_size(void) -{ - return (AT91SAM9G20_PIT_SIZE); -} - -static int pit_rate; -static int pit_cycle; -static int pit_counter; - static int at91pit_attach(device_t dev) { - struct at91_softc *sc = device_get_softc(device_get_parent(dev)); - struct resource *irq; - int rid = 0; void *ih; + int rid, err = 0; + struct at91_softc *at91_sc; + struct resource *irq; - pit_softc = device_get_softc(dev); - pit_softc->sc_st = sc->sc_st; - pit_softc->sc_dev = dev; - if (bus_space_subregion(sc->sc_st, sc->sc_sh, at91_pit_base(), - at91_pit_size(), &pit_softc->sc_sh) != 0) - panic("couldn't subregion pit registers"); + at91_sc = device_get_softc(device_get_parent(dev)); + sc = device_get_softc(dev); + sc->sc_dev = dev; + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + + if (sc->mem_res == NULL) + panic("couldn't allocate register resources"); + + rid = 0; irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1, RF_ACTIVE | RF_SHAREABLE); - if (!irq) - panic("Unable to allocate IRQ for the system timer"); - else - bus_setup_intr(dev, irq, INTR_TYPE_CLK, - clock_intr, NULL, NULL, &ih); - + if (!irq) { + device_printf(dev, "could not allocate interrupt resources.\n"); + err = ENOMEM; + goto out; + } - device_printf(dev, "AT91SAM9x pit registered\n"); - return (0); + /* Activate the interrupt. */ + err = bus_setup_intr(dev, irq, INTR_TYPE_CLK, pit_intr, + NULL, NULL, &ih); + + at91pit_timecounter.tc_frequency = at91_master_clock / PIT_PRESCALE; + tc_init(&at91pit_timecounter); + + //Enable the PIT here. + WR4(sc, PIT_MR, + PIT_PIV(at91_master_clock / PIT_PRESCALE / hz) | + PIT_EN | PIT_IEN); +out: + return (err); } static device_method_t at91pit_methods[] = { @@ -139,7 +147,7 @@ static device_method_t at91pit_methods[] = { static driver_t at91pit_driver = { "at91_pit", at91pit_methods, - sizeof(struct at91pit_softc), + sizeof(struct pit_softc), }; static devclass_t at91pit_devclass; @@ -147,52 +155,58 @@ static devclass_t at91pit_devclass; DRIVER_MODULE(at91_pit, atmelarm, at91pit_driver, at91pit_devclass, 0, 0); static int -clock_intr(void *arg) +pit_intr(void *arg) { - struct trapframe *fp = arg; + uint32_t icnt; + + if (RD4(sc, PIT_SR) & PIT_PITS_DONE) { + icnt = RD4(sc, PIT_PIVR) >> 20; + + /* Just add in the overflows we just read */ + timecount += PIT_PIV(RD4(sc, PIT_MR)) * icnt; - if (RD4(PIT_SR) & PIT_PITS_DONE) { - uint32_t pivr = RD4(PIT_PIVR); - if (PIT_CNT(pivr)>1) { - printf("cnt = %d\n", PIT_CNT(pivr)); - } - pit_counter += pit_cycle; hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); return (FILTER_HANDLED); } return (FILTER_STRAY); } -static unsigned +static unsigned at91pit_get_timecount(struct timecounter *tc) { - return pit_counter; + uint32_t piir, icnt; + + piir = RD4(sc, PIT_PIIR); /* Current count | over flows */ + icnt = piir >> 20; /* Overflows */ + return (timecount + PIT_PIV(piir) + PIT_PIV(RD4(sc, PIT_MR)) * icnt); } -/*todo: review this*/ void -DELAY(int n) +DELAY(int us) { - u_int32_t start, end, cur; + int32_t cnt, last, piv; + uint64_t pit_freq; + const uint64_t mhz = 1E6; - start = RD4(PIT_PIIR); - n = (n * 1000) / (at91_master_clock / 12); - if (n <= 0) - n = 1; - end = (start + n); - cur = start; - if (start > end) { - while (cur >= start || cur < end) - cur = RD4(PIT_PIIR); - } else { - while (cur < end) - cur = RD4(PIT_PIIR); + last = PIT_PIV(RD4(sc, PIT_PIIR)); + + /* Max delay ~= 260s. @ 133Mhz */ + pit_freq = at91_master_clock / PIT_PRESCALE; + cnt = ((pit_freq * us) + (mhz -1)) / mhz; + cnt = (cnt <= 0) ? 1 : cnt; + + while (cnt > 0) { + piv = PIT_PIV(RD4(sc, PIT_PIIR)); + cnt -= piv - last ; + if (piv < last) + cnt -= PIT_PIV(~0u) - last; + last = piv; } } /* - * The 3 next functions must be implement with the futur PLL code. + * The 3 next functions must be implement with the future PLL code. */ void cpu_startprofclock(void) @@ -204,30 +218,7 @@ cpu_stopprofclock(void) { } -#define HZ 100 - void cpu_initclocks(void) { - struct at91_pmc_clock *master; - - master = at91_pmc_clock_ref("mck"); - pit_rate = master->hz / 16; - pit_cycle = (pit_rate + HZ/2) / HZ; - at91pit_timecounter.tc_frequency = pit_rate; - WR4(PIT_MR, 0); - - while (PIT_PIV(RD4(PIT_PIVR)) != 0); - - WR4(PIT_MR, (pit_cycle - 1) | PIT_IEN | PIT_EN); - tc_init(&at91pit_timecounter); -} - -void -cpu_reset(void) -{ - *(volatile int *)(AT91SAM9G20_BASE + AT91SAM9G20_RSTC_BASE + - RSTC_CR) = RSTC_PROCRST | RSTC_PERRST | RSTC_KEY; - while (1) - continue; } diff --git a/sys/arm/at91/at91_pmc.c b/sys/arm/at91/at91_pmc.c index 78d33a04058..03a7a6e8134 100644 --- a/sys/arm/at91/at91_pmc.c +++ b/sys/arm/at91/at91_pmc.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,14 +24,13 @@ * SUCH DAMAGE. */ -#include "opt_at91.h" - #include __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -44,8 +44,8 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include +#include +#include #include #include @@ -59,9 +59,13 @@ static struct at91_pmc_softc { uint32_t pllb_init; } *pmc_softc; +MALLOC_DECLARE(M_PMC); +MALLOC_DEFINE(M_PMC, "at91_pmc_clocks", "AT91 PMC Clock descriptors"); + static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int); static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int); static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int); +static void at91_pmc_clock_alias(const char *name, const char *alias); static struct at91_pmc_clock slck = { .name = "slck", // 32,768 Hz slow clock @@ -71,6 +75,10 @@ static struct at91_pmc_clock slck = { .primary = 1, }; +/* + * NOTE: Clocks for "ordinary peripheral" devices e.g. spi0, udp0, uhp0 etc. + * are now created automatically. Only "system" clocks need be defined here. + */ static struct at91_pmc_clock main_ck = { .name = "main", // Main clock .refcnt = 0, @@ -115,60 +123,20 @@ static struct at91_pmc_clock uhpck = { }; static struct at91_pmc_clock mck = { - .name = "mck", + .name = "mck", // Master (Peripheral) Clock .pmc_mask = PMC_IER_MCKRDY, .refcnt = 0, }; -#ifdef AT91SAM9G20 -#define IRQ_UDP AT91SAM9G20_IRQ_UDP -#define IRQ_UHP AT91SAM9G20_IRQ_UHP -#else -#define IRQ_UDP AT91RM92_IRQ_UDP -#define IRQ_UHP AT91RM92_IRQ_UHP -#endif /* AT91SAM9G20 */ - -static struct at91_pmc_clock udc_clk = { - .name = "udc_clk", - .parent = &mck, - .pmc_mask = 1 << IRQ_UDP, - .set_mode = &at91_pmc_set_periph_mode +static struct at91_pmc_clock cpu = { + .name = "cpu", // CPU Clock + .parent = &plla, + .pmc_mask = PMC_SCER_PCK, + .refcnt = 0, }; -static struct at91_pmc_clock ohci_clk = { - .name = "ohci_clk", - .parent = &mck, - .pmc_mask = 1 << IRQ_UHP, - .set_mode = &at91_pmc_set_periph_mode -}; - -#ifdef AT91SAM9G20 -static struct at91_pmc_clock macb_clk = { - .name = "macb_clk", - .parent = &mck, - - .pmc_mask = 1 << 21, - .set_mode = &at91_pmc_set_periph_mode -}; - -static struct at91_pmc_clock spi0_clk = { - .name = "spi0_clk", - .parent = &mck, - - .pmc_mask = 1 << 12, - .set_mode = &at91_pmc_set_periph_mode -}; - -static struct at91_pmc_clock spi1_clk = { - .name = "spi1_clk", - .parent = &mck, - .pmc_mask = 1 << 13, - .set_mode = &at91_pmc_set_periph_mode -}; - -#endif /* AT91SAM9G20 */ - -static struct at91_pmc_clock *const clock_list[] = { +/* "+32" or the automatic peripheral clocks */ +static struct at91_pmc_clock *clock_list[16+32] = { &slck, &main_ck, &plla, @@ -176,13 +144,7 @@ static struct at91_pmc_clock *const clock_list[] = { &udpck, &uhpck, &mck, - &udc_clk, -#ifdef AT91SAM9G20 - &macb_clk, - &spi0_clk, - &spi1_clk, -#endif /* AT91SAM9G20 */ - &ohci_clk + &cpu }; #if !defined(AT91C_MAIN_CLOCK) @@ -200,7 +162,7 @@ static const unsigned int at91_mainf_tbl[] = { static inline uint32_t RD4(struct at91_pmc_softc *sc, bus_size_t off) { - return bus_read_4(sc->mem_res, off); + return (bus_read_4(sc->mem_res, off)); } static inline void @@ -209,7 +171,7 @@ WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val) bus_write_4(sc->mem_res, off, val); } -static void +void at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on) { struct at91_pmc_softc *sc = pmc_softc; @@ -221,6 +183,15 @@ at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on) } else { value = 0; } + + /* Workaround RM9200 Errata #26 */ + if (at91_is_rm92() && + ((value ^ RD4(sc, CKGR_PLLBR)) & 0x03f0ff) != 0) { + WR4(sc, CKGR_PLLBR, value ^ 1); + while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on) + continue; + } + WR4(sc, CKGR_PLLBR, value); while ((RD4(sc, PMC_SR) & PMC_IER_LOCKB) != on) continue; @@ -254,15 +225,75 @@ at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on) continue; } +struct at91_pmc_clock * +at91_pmc_clock_add(const char *name, uint32_t irq, struct at91_pmc_clock *parent) +{ + struct at91_pmc_clock *clk; + int i, buflen; + + clk = malloc(sizeof(*clk), M_PMC, M_NOWAIT | M_ZERO); + if (clk == NULL) + goto err; + + buflen = strlen(name) + 1; + clk->name = malloc(buflen, M_PMC, M_NOWAIT); + if (clk->name == NULL) + goto err; + + strlcpy(clk->name, name, buflen); + clk->pmc_mask = 1 << irq; + clk->set_mode = &at91_pmc_set_periph_mode; + if (parent == NULL) + clk->parent = &mck; + else + clk->parent = parent; + + for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++) { + if (clock_list[i] == NULL) { + clock_list[i] = clk; + return (clk); + } + } +err: + if (clk != NULL) { + if (clk->name != NULL) + free(clk->name, M_PMC); + free(clk, M_PMC); + } + + panic("could not allocate pmc clock '%s'", name); + return (NULL); +} + +static void +at91_pmc_clock_alias(const char *name, const char *alias) +{ + struct at91_pmc_clock *clk, *alias_clk; + + clk = at91_pmc_clock_ref(name); + if (clk) + alias_clk = at91_pmc_clock_add(alias, 0, clk->parent); + + if (clk && alias_clk) { + alias_clk->hz = clk->hz; + alias_clk->pmc_mask = clk->pmc_mask; + alias_clk->set_mode = clk->set_mode; + } +} + struct at91_pmc_clock * at91_pmc_clock_ref(const char *name) { int i; - for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++) + for (i = 0; i < sizeof(clock_list) / sizeof(clock_list[0]); i++) { + if (clock_list[i] == NULL) + break; if (strcmp(name, clock_list[i]->name) == 0) return (clock_list[i]); + } + //printf("at91_pmc: Warning - did not find clock '%s'", name); return (NULL); } @@ -292,55 +323,53 @@ at91_pmc_clock_disable(struct at91_pmc_clock *clk) } static int -at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb) +at91_pmc_pll_rate(struct at91_pmc_clock *clk, uint32_t reg) { - uint32_t mul, div; + uint32_t mul, div, freq;; + + freq = clk->parent->hz; + div = (reg >> clk->pll_div_shift) & clk->pll_div_mask; + mul = (reg >> clk->pll_mul_shift) & clk->pll_mul_mask; + +// printf("pll = (%d / %d) * %d = %d\n", +// freq, div ,mul + 1, (freq/div) * (mul+1)); - div = reg & 0xff; -#ifdef AT91SAM9G20 - if (is_pllb) - mul = (reg >> 16) & 0x3f; - else - mul = (reg >> 16) & 0xff; -#else - mul = (reg >> 16) & 0x7ff; -#endif if (div != 0 && mul != 0) { freq /= div; freq *= mul + 1; } else { freq = 0; } -#ifndef AT91SAM9G20 - if (is_pllb && (reg & (1 << 28))) - freq >>= 1; -#endif + clk->hz = freq; + + return (freq); } static uint32_t -at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq) +at91_pmc_pll_calc(struct at91_pmc_clock *clk, uint32_t out_freq) { uint32_t i, div = 0, mul = 0, diff = 1 << 30; - unsigned ret = (out_freq > PMC_PLL_FAST_THRESH) ? 0xbe00 : 0x3e00; - if (out_freq > PMC_PLL_MAX_OUT_FREQ) + unsigned ret = 0x3e00; + + if (out_freq > clk->pll_max_out) goto fail; for (i = 1; i < 256; i++) { int32_t diff1; uint32_t input, mul1; - input = main_freq / i; - if (input < PMC_PLL_MIN_IN_FREQ) + input = clk->parent->hz / i; + if (input < clk->pll_min_in) break; - if (input > PMC_PLL_MAX_IN_FREQ) + if (input > clk->pll_max_in) continue; mul1 = out_freq / input; - if (mul1 > PMC_PLL_MULT_MAX) + if (mul1 > (clk->pll_mul_mask + 1)) continue; - if (mul1 < PMC_PLL_MULT_MIN) + if (mul1 == 0) break; diff1 = out_freq - input * mul1; @@ -356,53 +385,94 @@ at91_pmc_pll_calc(uint32_t main_freq, uint32_t out_freq) } if (diff > (out_freq >> PMC_PLL_SHIFT_TOL)) goto fail; - return ret | ((mul - 1) << 16) | div; + + if (clk->set_outb != NULL) + ret |= clk->set_outb(out_freq); + + return (ret | + ((mul - 1) << clk->pll_mul_shift) | + (div << clk->pll_div_shift)); fail: - return 0; + return (0); } static void at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock) { uint32_t mckr; - int freq; + uint32_t mdiv; + if (at91_is_sam9()) { + uhpck.pmc_mask = PMC_SCER_UHP_SAM9; + udpck.pmc_mask = PMC_SCER_UDP_SAM9; + } + mckr = RD4(sc, PMC_MCKR); sc->main_clock_hz = main_clock; main_ck.hz = main_clock; - plla.hz = at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0); + + at91_pmc_pll_rate(&plla, RD4(sc, CKGR_PLLAR)); + + if (at91_cpu_is(AT91_CPU_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2)) + plla.hz /= 2; /* * Initialize the usb clock. This sets up pllb, but disables the * actual clock. */ - sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000; - pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1); - WR4(sc, PMC_PCDR, (1 << IRQ_UHP) | (1 << IRQ_UDP)); - WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP); - WR4(sc, CKGR_PLLBR, 0); -#ifndef AT91SAM9G20 - WR4(sc, PMC_SCER, PMC_SCER_MCKUDP); + sc->pllb_init = at91_pmc_pll_calc(&pllb, 48000000 * 2) | 0x10000000; + at91_pmc_pll_rate(&pllb, sc->pllb_init); + +#if 0 + /* Turn off USB clocks */ + at91_pmc_set_periph_mode(&ohci_clk, 0); + at91_pmc_set_periph_mode(&udc_clk, 0); #endif + if (at91_is_rm92()) { + WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP); + WR4(sc, PMC_SCER, PMC_SCER_MCKUDP); + } else { + WR4(sc, PMC_SCDR, PMC_SCER_UHP_SAM9 | PMC_SCER_UDP_SAM9); + } + WR4(sc, CKGR_PLLBR, 0); + /* * MCK and PCU derive from one of the primary clocks. Initialize * this relationship. */ - mckr = RD4(sc, PMC_MCKR); mck.parent = clock_list[mckr & 0x3]; mck.parent->refcnt++; - freq = mck.parent->hz / (1 << ((mckr >> 2) & 3)); - mck.hz = freq / (1 + ((mckr >> 8) & 3)); + + cpu.hz = + mck.hz = mck.parent->hz / + (1 << ((mckr & PMC_MCKR_PRES_MASK) >> 2)); + + mdiv = (mckr & PMC_MCKR_MDIV_MASK) >> 8; + if (at91_is_sam9()) { + if (mdiv > 0) + mck.hz /= mdiv * 2; + } else + mck.hz /= (1 + mdiv); + + /* Only found on SAM9G20 */ + if (at91_cpu_is(AT91_CPU_SAM9G20)) + cpu.hz /= (mckr & PMC_MCKR_PDIV) ? 2 : 1; + + at91_master_clock = mck.hz; device_printf(sc->dev, "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n", sc->main_clock_hz, - at91_pmc_pll_rate(main_clock, RD4(sc, CKGR_PLLAR), 0) / 1000000, - freq / 1000000, mck.hz / 1000000); + plla.hz / 1000000, + cpu.hz / 1000000, mck.hz / 1000000); + + /* Turn off "Progamable" clocks */ WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 | PMC_SCER_PCK3); + /* XXX kludge, turn on all peripherals */ WR4(sc, PMC_PCER, 0xffffffff); + /* Disable all interrupts for PMC */ WR4(sc, PMC_IDR, 0xffffffff); } @@ -482,7 +552,7 @@ at91_pmc_attach(device_t dev) pmc_softc = device_get_softc(dev); pmc_softc->dev = dev; if ((err = at91_pmc_activate(dev)) != 0) - return err; + return (err); /* * Configure main clock frequency. @@ -493,6 +563,11 @@ at91_pmc_attach(device_t dev) mainf = AT91C_MAIN_CLOCK; #endif at91_pmc_init_clock(pmc_softc, mainf); + + /* These clocks refrenced by "special" names */ + at91_pmc_clock_alias("ohci0", "ohci_clk"); + at91_pmc_clock_alias("udp0", "udp_clk"); + return (0); } diff --git a/sys/arm/at91/at91_pmcreg.h b/sys/arm/at91/at91_pmcreg.h index 54de9f45537..eaf08c605d3 100644 --- a/sys/arm/at91/at91_pmcreg.h +++ b/sys/arm/at91/at91_pmcreg.h @@ -58,21 +58,6 @@ #define PMC_SR 0x68 /* Status Register */ #define PMC_IMR 0x6c /* Interrupt Mask Register */ -#ifdef AT91SAM9G20 -/* PMC Specific AT91SAM9G20 */ - -/* PMC System Clock Enable Register */ -/* PMC System Clock Disable Register */ -/* PMC System Clock StatusRegister */ -#define PMC_SCER_UHP (1UL << 6) /* UHP: USB Host Port Clock Enable */ -#define PMC_SCER_UDP (1UL << 7) /* UDP: USB Device Port Clock Enable */ -#define PMC_SCER_PCK0 (1UL << 8) /* PCK0: Programmable Clock out en */ -#define PMC_SCER_PCK1 (1UL << 9) /* PCK1: Programmable Clock out en */ -#define PMC_SCER_PCK2 (1UL << 10) /* PCK2: Programmable Clock out en */ -#define PMC_SCER_PCK3 (1UL << 11) /* PCK3: Programmable Clock out en */ - -#else - /* PMC System Clock Enable Register */ /* PMC System Clock Disable Register */ /* PMC System Clock StatusRegister */ @@ -81,11 +66,12 @@ #define PMC_SCER_MCKUDP (1UL << 2) /* MCKUDP: Master disable susp/res */ #define PMC_SCER_UHP (1UL << 4) /* UHP: USB Host Port Clock Enable */ #define PMC_SCER_PCK0 (1UL << 8) /* PCK0: Programmable Clock out en */ -#define PMC_SCER_PCK1 (1UL << 10) /* PCK1: Programmable Clock out en */ -#define PMC_SCER_PCK2 (1UL << 11) /* PCK2: Programmable Clock out en */ -#define PMC_SCER_PCK3 (1UL << 12) /* PCK3: Programmable Clock out en */ +#define PMC_SCER_PCK1 (1UL << 9) /* PCK1: Programmable Clock out en */ +#define PMC_SCER_PCK2 (1UL << 10) /* PCK2: Programmable Clock out en */ +#define PMC_SCER_PCK3 (1UL << 11) /* PCK3: Programmable Clock out en */ +#define PMC_SCER_UHP_SAM9 (1UL << 6) /* UHP: USB Host Port Clock Enable */ +#define PMC_SCER_UDP_SAM9 (1UL << 7) /* UDP: USB Device Port Clock Enable */ -#endif /* AT91SAM9G20 */ /* PMC Peripheral Clock Enable Register */ /* PMC Peripheral Clock Disable Register */ /* PMC Peripheral Clock Status Register */ @@ -100,6 +86,13 @@ #define CKGR_MCFR_MAINRDY (1UL << 16) /* Main Clock Ready */ #define CKGR_MCFR_MAINF_MASK 0xfffful /* Main Clock Frequency */ +/* PMC Clock Generator Master Clock Register */ +#define PMC_MCKR_PDIV (1 << 12) /* SAM9G20 Only */ +#define PMC_MCKR_PLLADIV2 (1 << 12) /* SAM9G45 Only */ +#define PMC_MCKR_CSS_MASK (3 << 0) +#define PMC_MCKR_MDIV_MASK (3 << 8) +#define PMC_MCKR_PRES_MASK (7 << 2) + /* PMC Interrupt Enable Register */ /* PMC Interrupt Disable Register */ /* PMC Status Register */ diff --git a/sys/arm/at91/at91_pmcvar.h b/sys/arm/at91/at91_pmcvar.h index a4ebba7f3b3..22255d698a1 100644 --- a/sys/arm/at91/at91_pmcvar.h +++ b/sys/arm/at91/at91_pmcvar.h @@ -30,7 +30,7 @@ struct at91_pmc_clock { - const char *name; + char *name; uint32_t hz; struct at91_pmc_clock *parent; uint32_t pmc_mask; @@ -40,8 +40,23 @@ struct at91_pmc_clock unsigned primary:1; unsigned pll:1; unsigned programmable:1; + + /* PLL Params */ + uint32_t pll_min_in; + uint32_t pll_max_in; + uint32_t pll_min_out; + uint32_t pll_max_out; + + uint32_t pll_div_shift; + uint32_t pll_div_mask; + uint32_t pll_mul_shift; + uint32_t pll_mul_mask; + + uint32_t (*set_outb)(int); }; +struct at91_pmc_clock * at91_pmc_clock_add(const char *name, uint32_t irq, + struct at91_pmc_clock *parent); struct at91_pmc_clock *at91_pmc_clock_ref(const char *name); void at91_pmc_clock_deref(struct at91_pmc_clock *); void at91_pmc_clock_enable(struct at91_pmc_clock *); diff --git a/sys/arm/at91/at91_reset.S b/sys/arm/at91/at91_reset.S new file mode 100644 index 00000000000..e3b1d007256 --- /dev/null +++ b/sys/arm/at91/at91_reset.S @@ -0,0 +1,57 @@ +#include +#include +#include +__FBSDID("$FreeBSD$"); + +#define SDRAM_TR (AT91SAM9G20_BASE + \ + AT91SAM9G20_SDRAMC_BASE + AT91SAM9G20_SDRAMC_TR) +#define SDRAM_LPR (AT91SAM9G20_BASE + \ + AT91SAM9G20_SDRAMC_BASE + AT91SAM9G20_SDRAMC_LPR) +#define RSTC_RCR (AT91SAM9G20_BASE + \ + AT91SAM9G20_RSTC_BASE + RST_CR) + +/* + * From AT91SAM9G20 Datasheet errata 44:3.5: + * + * When User Reset occurs durring SDRAM read acces, eh SDRAM clock is turned + * off while data are ready to be read on the data bus. The SDRAM maintains + * the data until the clock restarts. + * + * If the User reset is programed to assert a general reset, the data + * If the User reset is programed to assert a general reset, the data + * maintained by the SDRAM leads to a data bus conflict and adversly affects + * the boot memories connected to the EBI: + * + NAND Flash boot functionality, if the system boots out of internal ROM. + * + NOR Flash boot, if the system boots on an external memory connected to + * the EBI CS0. + * + * Assembly code is mandatory for the following sequnce as ARM + * instructions need to be piplined. + * + */ + +ENTRY(cpu_reset_sam9g20) + + /* Disable IRQs */ + mrs r0, cpsr + orr r0, r0, #0x80 + msr cpsr_c, r0 + + /* Change Refresh to block all data access */ + ldr r0, =SDRAM_TR + ldr r1, =1 + str r1, [r0] + + /* Prepare power down command */ + ldr r0, =SDRAM_LPR + ldr r1, =2 + + /* Prepare proc_reset and periph reset */ + ldr r2, =RSTC_RCR + ldr r3, =0xA5000005 + + /* perform power down command */ + str r1, [r0] + + /* Perfom proc_reset and periph reset (in the ARM pipeline) */ + str r3, [r2] diff --git a/sys/arm/at91/at91_rst.c b/sys/arm/at91/at91_rst.c new file mode 100644 index 00000000000..fe484666136 --- /dev/null +++ b/sys/arm/at91/at91_rst.c @@ -0,0 +1,215 @@ +/*- + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define RST_TIMEOUT (5) /* Seconds to hold NRST for hard reset */ +#define RST_TICK (20) /* sample NRST at hz/RST_TICK intervals */ + +static int rst_intr(void *arg); + +static struct rst_softc { + struct resource *mem_res; /* Memory resource */ + struct resource *irq_res; /* IRQ resource */ + void *intrhand; /* Interrupt handle */ + struct callout tick_ch; /* Tick callout */ + device_t sc_dev; + u_int shutdown; /* Shutdown in progress */ +} *rst_sc; + +static inline uint32_t +RD4(struct rst_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->mem_res, off)); +} + +static inline void +WR4(struct rst_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->mem_res, off, val); +} + +static int +at91_rst_probe(device_t dev) +{ + + if (at91_is_sam9()) { + device_set_desc(dev, "AT91SAM9 Reset Controller"); + return (0); + } + return (ENXIO); +} + +static int +at91_rst_attach(device_t dev) +{ + struct rst_softc *sc; + const char *cause; + int rid, err; + + rst_sc = sc = device_get_softc(dev); + sc->sc_dev = dev; + + callout_init(&sc->tick_ch, 0); + + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "could not allocate memory resources.\n"); + err = ENOMEM; + goto out; + } + rid = 0; + sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (sc->irq_res == NULL) { + device_printf(dev, "could not allocate interrupt resources.\n"); + err = ENOMEM; + goto out; + } + + /* Activate the interrupt. */ + err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + rst_intr, NULL, sc, &sc->intrhand); + if (err) + device_printf(dev, "could not establish interrupt handler.\n"); + + WR4(rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY); + + switch (RD4(sc, RST_SR) & RST_SR_RST_MASK) { + case RST_SR_RST_POW: + cause = "Power On"; + break; + case RST_SR_RST_WAKE: + cause = "Wake Up"; + break; + case RST_SR_RST_WDT: + cause = "Watchdog"; + break; + case RST_SR_RST_SOFT: + cause = "Software Request"; + break; + case RST_SR_RST_USR: + cause = "External (User)"; + break; + default: + cause = "Unknown"; + break; + } + + device_printf(dev, "Reset cause: %s.\n", cause); + /* cpu_reset_addr = cpu_reset; */ + +out: + return (err); +} + +static void +rst_tick(void *argp) +{ + struct rst_softc *sc = argp; + + if (sc->shutdown++ >= RST_TIMEOUT * RST_TICK) { + /* User released the button in morre than RST_TIMEOUT */ + cpu_reset(); + } else if ((RD4(sc, RST_SR) & RST_SR_NRSTL)) { + /* User released the button in less than RST_TIMEOUT */ + sc->shutdown = 0; + device_printf(sc->sc_dev, "shutting down...\n"); + shutdown_nice(0); + } else { + callout_reset(&sc->tick_ch, hz/RST_TICK, rst_tick, sc); + } +} + +static int +rst_intr(void *argp) +{ + struct rst_softc *sc = argp; + + if (RD4(sc, RST_SR) & RST_SR_URSTS) { + if (sc->shutdown == 0) + callout_reset(&sc->tick_ch, hz/RST_TICK, rst_tick, sc); + return (FILTER_HANDLED); + } + return (FILTER_STRAY); +} + +static device_method_t at91_rst_methods[] = { + DEVMETHOD(device_probe, at91_rst_probe), + DEVMETHOD(device_attach, at91_rst_attach), + {0,0}, +}; + +static driver_t at91_rst_driver = { + "at91_rst", + at91_rst_methods, + sizeof(struct rst_softc), +}; + +static devclass_t at91_rst_devclass; + +DRIVER_MODULE(at91_rst, atmelarm, at91_rst_driver, at91_rst_devclass, 0, 0); + +void cpu_reset_sam9g20(void) __attribute__((weak)); +void cpu_reset_sam9g20(void) {} + +void +cpu_reset(void) +{ + + if (rst_sc) { + + cpu_reset_sam9g20(); /* May be null */ + + WR4(rst_sc, RST_MR, + RST_MR_ERSTL(0xd) | RST_MR_URSTEN | RST_MR_KEY); + + WR4(rst_sc, RST_CR, + RST_CR_PROCRST | + RST_CR_PERRST | + RST_CR_EXTRST | + RST_CR_KEY); + } + + for(;;) ; +} diff --git a/sys/arm/at91/at91_rstreg.h b/sys/arm/at91/at91_rstreg.h new file mode 100644 index 00000000000..f075b2cf53e --- /dev/null +++ b/sys/arm/at91/at91_rstreg.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2009 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef ARM_AT91_AT91RSTREG_H +#define ARM_AT91_AT91RSTREG_H + +#define RST_CR 0x0 /* Control Register */ +#define RST_SR 0x4 /* Status Register */ +#define RST_MR 0x8 /* Mode Register */ + +/* RST_CR */ +#define RST_CR_PROCRST (1<<0) +#define RST_CR_PERRST (1<<2) +#define RST_CR_EXTRST (1<<3) +#define RST_CR_KEY (0xa5<<24) + +/* RST_SR */ +#define RST_SR_SRCMP (1<<17) /* Software Reset in progress */ +#define RST_SR_NRSTL (1<<16) /* NRST pin level at MCK */ +#define RST_SR_URSTS (1<<0) /* NRST pin has been active */ + +#define RST_SR_RST_POW (0<<8) /* General (Power On) reset */ +#define RST_SR_RST_WAKE (1<<8) /* Wake-up reset */ +#define RST_SR_RST_WDT (2<<8) /* Watchdog reset */ +#define RST_SR_RST_SOFT (3<<8) /* Software reset */ +#define RST_SR_RST_USR (4<<8) /* User (External) reset */ +#define RST_SR_RST_MASK (7<<8) /* User (External) reset */ + +/* RST_MR */ +#define RST_MR_URSTEN (1<<0) /* User reset enable */ +#define RST_MR_URSIEN (1<<4) /* User interrupt enable */ +#define RST_MR_ERSTL(x) ((x)<<8) /* External reset length */ +#define RST_MR_KEY (0xa5<<24) + +#endif /* ARM_AT91_AT91RSTREG_H */ diff --git a/sys/arm/at91/at91_twi.c b/sys/arm/at91/at91_twi.c index 33ef8c0a143..fdd377a5529 100644 --- a/sys/arm/at91/at91_twi.c +++ b/sys/arm/at91/at91_twi.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -338,7 +337,7 @@ at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) err = EINVAL; goto out; } - if (len == 1) + if (len == 1 && msgs[i].flags & IIC_M_RD) WR4(sc, TWI_CR, TWI_CR_START | TWI_CR_STOP); else WR4(sc, TWI_CR, TWI_CR_START); @@ -348,7 +347,7 @@ at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) if ((sr = RD4(sc, TWI_SR)) & TWI_SR_RXRDY) { len--; *buf++ = RD4(sc, TWI_RHR) & 0xff; - if (len == 0 && msgs[i].len != 1) + if (len == 1) WR4(sc, TWI_CR, TWI_CR_STOP); } } @@ -358,8 +357,6 @@ at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) } } else { while (len--) { - if (len == 0 && msgs[i].len != 1) - WR4(sc, TWI_CR, TWI_CR_STOP); if ((err = at91_twi_wait(sc, TWI_SR_TXRDY))) goto out; WR4(sc, TWI_THR, *buf++); diff --git a/sys/arm/at91/at91_twireg.h b/sys/arm/at91/at91_twireg.h index 6cca1016278..7d61a4a9e47 100644 --- a/sys/arm/at91/at91_twireg.h +++ b/sys/arm/at91/at91_twireg.h @@ -63,7 +63,10 @@ #define TWI_CWGR_CKDIV(x) ((x) << 16) /* Clock Divider */ #define TWI_CWGR_CHDIV(x) ((x) << 8) /* Clock High Divider */ #define TWI_CWGR_CLDIV(x) ((x) << 0) /* Clock Low Divider */ -#define TWI_CWGR_DIV(rate) ((at91_master_clock /(4*(rate))) - 2) +#define TWI_CWGR_DIV(rate) \ + (at91_is_sam9() ? \ + ((at91_master_clock /(4*(rate))) - 3) : \ + ((at91_master_clock /(4*(rate))) - 2)) /* TWI_SR */ /* TWI_IER */ diff --git a/sys/arm/at91/at91_wdt.c b/sys/arm/at91/at91_wdt.c new file mode 100644 index 00000000000..6ae01efcbfe --- /dev/null +++ b/sys/arm/at91/at91_wdt.c @@ -0,0 +1,222 @@ +/*- + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The sam9 watchdog hardware can be programed only once. So we set the hardware + * watchdog to 16s in wdt_attach and only reset it in the wdt_tick + * handler. The watchdog is halted in processor debug mode. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +struct wdt_softc { + struct mtx sc_mtx; + device_t sc_dev; + struct resource *mem_res; + struct callout tick_ch; + eventhandler_tag sc_wet; + void *intrhand; + u_int cmd; + u_int interval; +}; + +static inline uint32_t +RD4(struct wdt_softc *sc, bus_size_t off) +{ + return (bus_read_4(sc->mem_res, off)); +} + +static inline void +WR4(struct wdt_softc *sc, bus_size_t off, uint32_t val) +{ + bus_write_4(sc->mem_res, off, val); +} + +static int +wdt_intr(void *argp) +{ + struct wdt_softc *sc = argp; + + + if (RD4(sc, WDT_SR) & (WDT_WDUNF | WDT_WDERR)) { +#if defined(KDB) && !defined(KDB_UNATTENDED) + kdb_backtrace(); + kdb_enter(KDB_WHY_WATCHDOG, "watchdog timeout"); +#else + panic("watchdog timeout"); +#endif + } + return (FILTER_STRAY); +} + +/* User interface, see watchdog(9) */ +static void +wdt_watchdog(void *argp, u_int cmd, int *error) +{ + struct wdt_softc *sc = argp; + u_int interval; + + mtx_lock(&sc->sc_mtx); + + *error = 0; + sc->cmd = 0; + interval = cmd & WD_INTERVAL; + if (interval > WD_TO_16SEC) + *error = EOPNOTSUPP; + else if (interval > 0) + sc->cmd = interval | WD_ACTIVE; + + /* We cannot turn of our watchdog so if user + * fails to turn us on go to passive mode. */ + if ((sc->cmd & WD_ACTIVE) == 0) + sc->cmd = WD_PASSIVE; + + mtx_unlock(&sc->sc_mtx); +} + +/* This routine is called no matter what state the user sets the + * watchdog mode to. Called at a rate that is slightly less than + * half the hardware timeout. */ +static void +wdt_tick(void *argp) +{ + struct wdt_softc *sc = argp; + + mtx_assert(&sc->sc_mtx, MA_OWNED); + if (sc->cmd & (WD_ACTIVE | WD_PASSIVE)) + WR4(sc, WDT_CR, WDT_KEY|WDT_WDRSTT); + + sc->cmd &= WD_PASSIVE; + callout_reset(&sc->tick_ch, sc->interval, wdt_tick, sc); +} + +static int +wdt_probe(device_t dev) +{ + + if (at91_is_sam9()) { + device_set_desc(dev, "WDT"); + return (0); + } + return (ENXIO); +} + +static int +wdt_attach(device_t dev) +{ + static struct wdt_softc *sc; + struct resource *irq; + uint32_t wdt_mr; + int rid, err; + + sc = device_get_softc(dev); + sc->cmd = WD_PASSIVE; + sc->sc_dev = dev; + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "at91_wdt", MTX_DEF); + callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); + + rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + + if (sc->mem_res == NULL) + panic("couldn't allocate wdt register resources"); + + wdt_mr = RD4(sc, WDT_MR); + if ((wdt_mr & WDT_WDRSTEN) == 0) + device_printf(dev, "Watchdog disabled! (Boot ROM?)\n"); + else { +#ifdef WDT_RESET + /* Rude, full reset of whole system on watch dog timeout */ + WR4(sc, WDT_MR, WDT_WDDBGHLT | WDT_WDD(0xC00)| + WDT_WDRSTEN| WDT_WDV(0xFFF)); +#else + /* Generate stack trace and panic on watchdog timeout*/ + WR4(sc, WDT_MR, WDT_WDDBGHLT | WDT_WDD(0xC00)| + WDT_WDFIEN| WDT_WDV(0xFFF)); +#endif + /* This may have been set by Boot ROM so register value + * may not be what we just requested since this is a + * write once register. */ + wdt_mr = RD4(sc, WDT_MR); + if (wdt_mr & WDT_WDFIEN) { + rid = 0; + irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (!irq) + panic("could not allocate interrupt.\n"); + + err = bus_setup_intr(dev, irq, INTR_TYPE_CLK, wdt_intr, + NULL, sc, &sc->intrhand); + } + + /* interval * hz */ + sc->interval = (((wdt_mr & WDT_WDV(~0)) + 1) * WDT_DIV) / + (WDT_CLOCK/hz); + + device_printf(dev, "watchdog timeout: %d seconds\n", + sc->interval/hz); + + /* Slightly less than 1/2 of watchdog hardware timeout */ + sc->interval = (sc->interval/2) - (sc->interval/20); + callout_reset(&sc->tick_ch, sc->interval, wdt_tick, sc); + + /* Register us as a watchdog */ + sc->sc_wet = EVENTHANDLER_REGISTER(watchdog_list, + wdt_watchdog, sc, 0); + } + return (0); +} + +static device_method_t wdt_methods[] = { + DEVMETHOD(device_probe, wdt_probe), + DEVMETHOD(device_attach, wdt_attach), + {0,0}, +}; + +static driver_t wdt_driver = { + "at91_wdt", + wdt_methods, + sizeof(struct wdt_softc), +}; + +static devclass_t wdt_devclass; + +DRIVER_MODULE(at91_wdt, atmelarm, wdt_driver, wdt_devclass, 0, 0); diff --git a/sys/arm/at91/at91_wdtreg.h b/sys/arm/at91/at91_wdtreg.h new file mode 100644 index 00000000000..56e8f1b30a3 --- /dev/null +++ b/sys/arm/at91/at91_wdtreg.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2005 Gallon Sylvestre. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $FreeBSD$ + */ + +#ifndef ARM_AT91_AT91WDTREG_H +#define ARM_AT91_AT91WDTREG_H + +#ifndef WDT_CLOCK +#define WDT_CLOCK (32768) +#endif +#define WDT_DIV (128) /* Clock is slow clock / 128 */ + +#define WDT_CR 0x0 /* Control Register */ +#define WDT_MR 0x4 /* Mode Register */ +#define WDT_SR 0x8 /* Status Register */ + +/* WDT_CR */ +#define WDT_KEY (0xa5<<24) +#define WDT_WDRSTT 0x1 + +/* WDT_MR */ +#define WDT_WDV(x) (x & 0xfff) /* counter value*/ +#define WDT_WDFIEN (1<<12) /* enable interrupt */ +#define WDT_WDRSTEN (1<<13) /* enable reset */ +#define WDT_WDRPROC (1<<14) /* processor reset */ +#define WDT_WDDIS (1<<15) /* disable */ +#define WDT_WDD(x) ((x & 0xfff) << 16) /* delta value */ +#define WDT_WDDBGHLT (1<<28) /* halt in debug */ +#define WDT_WDIDLEHLT (1<<29) /* halt in idle */ + +/* WDT_SR */ +#define WDT_WDUNF 0x1 +#define WDT_WDERR 0x2 + +#endif /* ARM_AT91_AT91WDTREG_H */ diff --git a/sys/arm/at91/at91reg.h b/sys/arm/at91/at91reg.h new file mode 100644 index 00000000000..03e31cb90f8 --- /dev/null +++ b/sys/arm/at91/at91reg.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2009 Greg Ansley 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $FreeBSD$ + */ + +#ifndef _AT91REG_H_ +#define _AT91REG_H_ + +#include "opt_at91.h" + +/* Where builtin peripherals start in KVM */ +#define AT91_BASE 0xd0000000 + +/* A few things that we count on being the same + * throught the whole family of SOCs */ + +/* SYSC System Controler */ +/* System Registers */ +#define AT91_SYS_BASE 0xffff000 +#define AT91_SYS_SIZE 0x1000 + +#if defined(AT91SAM9G45) || defined(AT91SAM9263) +#define AT91_DBGU_BASE 0xfffee00 +#else +#define AT91_DBGU_BASE 0xffff200 +#endif +#define AT91_DBGU_SIZE 0x200 +#define DBGU_C1R (64) /* Chip ID1 Register */ +#define DBGU_C2R (68) /* Chip ID2 Register */ +#define DBGU_FNTR (72) /* Force NTRST Register */ + +#define AT91_CPU_VERSION_MASK 0x0000001f +#define AT91_CPU_RM9200 0x09290780 +#define AT91_CPU_SAM9260 0x019803a0 +#define AT91_CPU_SAM9261 0x019703a0 +#define AT91_CPU_SAM9263 0x019607a0 +#define AT91_CPU_SAM9G10 0x819903a0 +#define AT91_CPU_SAM9G20 0x019905a0 +#define AT91_CPU_SAM9G45 0x819b05a0 + +#define AT91_ARCH(chipid) ((chipid >> 20) & 0xff) +#define AT91_CPU(chipid) (chipid & ~AT91_CPU_VERSION_MASK) +#define AT91_ARCH_SAM9 (0x19) +#define AT91_ARCH_RM92 (0x92) + +#endif /* _AT91REG_H_ */ diff --git a/sys/arm/at91/at91rm9200.c b/sys/arm/at91/at91rm9200.c new file mode 100644 index 00000000000..27faaff21c1 --- /dev/null +++ b/sys/arm/at91/at91rm9200.c @@ -0,0 +1,330 @@ +/*- + * Copyright (c) 2005 Olivier Houchard. All rights reserved. + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#define _ARM32_BUS_DMA_PRIVATE +#include + +#include +#include +#include +#include +#include + +struct at91rm92_softc { + device_t dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + bus_space_handle_t sc_sys_sh; + bus_space_handle_t sc_aic_sh; + bus_space_handle_t sc_dbg_sh; + bus_space_handle_t sc_matrix_sh; +}; +/* + * Standard priority levels for the system. 0 is lowest and 7 is highest. + * These values are the ones Atmel uses for its Linux port, which differ + * a little form the ones that are in the standard distribution. Also, + * the ones marked with 'TWEEK' are different based on experience. + */ +static const int at91_irq_prio[32] = +{ + 7, /* Advanced Interrupt Controller (FIQ) */ + 7, /* System Peripherals */ + 1, /* Parallel IO Controller A */ + 1, /* Parallel IO Controller B */ + 1, /* Parallel IO Controller C */ + 1, /* Parallel IO Controller D */ + 5, /* USART 0 */ + 5, /* USART 1 */ + 5, /* USART 2 */ + 5, /* USART 3 */ + 0, /* Multimedia Card Interface */ + 2, /* USB Device Port */ + 4, /* Two-Wire Interface */ /* TWEEK */ + 5, /* Serial Peripheral Interface */ + 4, /* Serial Synchronous Controller 0 */ + 6, /* Serial Synchronous Controller 1 */ /* TWEEK */ + 4, /* Serial Synchronous Controller 2 */ + 0, /* Timer Counter 0 */ + 6, /* Timer Counter 1 */ /* TWEEK */ + 0, /* Timer Counter 2 */ + 0, /* Timer Counter 3 */ + 0, /* Timer Counter 4 */ + 0, /* Timer Counter 5 */ + 2, /* USB Host port */ + 3, /* Ethernet MAC */ + 0, /* Advanced Interrupt Controller (IRQ0) */ + 0, /* Advanced Interrupt Controller (IRQ1) */ + 0, /* Advanced Interrupt Controller (IRQ2) */ + 0, /* Advanced Interrupt Controller (IRQ3) */ + 0, /* Advanced Interrupt Controller (IRQ4) */ + 0, /* Advanced Interrupt Controller (IRQ5) */ + 0 /* Advanced Interrupt Controller (IRQ6) */ +}; + +#define DEVICE(_name, _id, _unit) \ + { \ + _name, _unit, \ + AT91RM92_ ## _id ##_BASE, \ + AT91RM92_ ## _id ## _SIZE, \ + AT91RM92_IRQ_ ## _id \ + } + +static const struct cpu_devs at91_devs[] = +{ + DEVICE("at91_pmc", PMC, 0), + DEVICE("at91_st", ST, 0), + DEVICE("at91_pio", PIOA, 0), + DEVICE("at91_pio", PIOB, 1), + DEVICE("at91_pio", PIOC, 2), + DEVICE("at91_pio", PIOD, 3), + DEVICE("at91_rtc", RTC, 0), + + DEVICE("at91_mci", MCI, 0), + DEVICE("at91_twi", TWI, 0), + DEVICE("at91_udp", UDP, 0), + DEVICE("ate", EMAC, 0), + DEVICE("at91_ssc", SSC0, 0), + DEVICE("at91_ssc", SSC1, 1), + DEVICE("at91_ssc", SSC2, 2), + DEVICE("spi", SPI, 0), + +#ifndef SKYEYE_WORKAROUNDS + DEVICE("uart", DBGU, 0), + DEVICE("uart", USART0, 1), + DEVICE("uart", USART1, 2), + DEVICE("uart", USART2, 3), + DEVICE("uart", USART3, 4), +#else + DEVICE("uart", USART0, 0), +#endif + DEVICE("at91_aic", AIC, 0), + DEVICE("at91_mc", MC, 0), + DEVICE("at91_tc", TC0, 0), + DEVICE("at91_tc", TC1, 1), + DEVICE("ohci", OHCI, 0), + DEVICE("af91_cfata", CF, 0), + { 0, 0, 0, 0, 0 } +}; + +static void +at91_add_child(device_t dev, int prio, const char *name, int unit, + bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) +{ + device_t kid; + struct at91_ivar *ivar; + + kid = device_add_child_ordered(dev, prio, name, unit); + if (kid == NULL) { + printf("Can't add child %s%d ordered\n", name, unit); + return; + } + ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ivar == NULL) { + device_delete_child(dev, kid); + printf("Can't add alloc ivar\n"); + return; + } + device_set_ivars(kid, ivar); + resource_list_init(&ivar->resources); + if (irq0 != -1) { + bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); + if (irq0 != AT91RM92_IRQ_SYSTEM) + at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); + } + if (irq1 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); + if (irq2 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); + if (addr != 0 && addr < AT91RM92_BASE) + addr += AT91RM92_BASE; + if (addr != 0) + bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); +} + +static void +at91_cpu_add_builtin_children(device_t dev) +{ + int i; + const struct cpu_devs *walker; + + for (i = 1, walker = at91_devs; walker->name; i++, walker++) { + at91_add_child(dev, i, walker->name, walker->unit, + walker->mem_base, walker->mem_len, walker->irq0, + walker->irq1, walker->irq2); + } +} + +static uint32_t +at91_pll_outb(int freq) +{ + + if (freq > 155000000) + return (0x0000); + else + return (0x8000); +} + +static void +at91_identify(driver_t *drv, device_t parent) +{ + + if (at91_cpu_is(AT91_CPU_RM9200)) { + at91_add_child(parent, 0, "at91rm920", 0, 0, 0, -1, 0, 0); + at91_cpu_add_builtin_children(parent); + } +} + +static int +at91_probe(device_t dev) +{ + + if (at91_cpu_is(AT91_CPU_RM9200)) { + device_set_desc(dev, "AT91RM9200"); + return (0); + } + return (ENXIO); +} + +static int +at91_attach(device_t dev) +{ + struct at91_pmc_clock *clk; + struct at91rm92_softc *sc = device_get_softc(dev); + int i; + + struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); + + sc->sc_st = at91sc->sc_st; + sc->sc_sh = at91sc->sc_sh; + sc->dev = dev; + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_SYS_BASE, + AT91RM92_SYS_SIZE, &sc->sc_sys_sh) != 0) + panic("Enable to map system registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_DBGU_BASE, + AT91RM92_DBGU_SIZE, &sc->sc_dbg_sh) != 0) + panic("Enable to map DBGU registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_AIC_BASE, + AT91RM92_AIC_SIZE, &sc->sc_aic_sh) != 0) + panic("Enable to map system registers"); + + /* XXX Hack to tell atmelarm about the AIC */ + at91sc->sc_aic_sh = sc->sc_aic_sh; + at91sc->sc_irq_system = AT91RM92_IRQ_SYSTEM; + + for (i = 0; i < 32; i++) { + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + + i * 4, i); + /* Priority. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, + at91_irq_prio[i]); + if (i < 8) + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, + 1); + } + + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); + /* No debug. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); + + /* Disable all interrupts for RTC (0xe24 == RTC_IDR) */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff); + + /* Disable all interrupts for the SDRAM controller */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff); + + /* Disable all interrupts for DBGU */ + bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); + + /* Update USB device port clock info */ + clk = at91_pmc_clock_ref("udpck"); + clk->pmc_mask = PMC_SCER_UDP; + at91_pmc_clock_deref(clk); + + /* Update USB host port clock info */ + clk = at91_pmc_clock_ref("uhpck"); + clk->pmc_mask = PMC_SCER_UHP; + at91_pmc_clock_deref(clk); + + /* Each SOC has different PLL contraints */ + clk = at91_pmc_clock_ref("plla"); + clk->pll_min_in = RM9200_PLL_A_MIN_IN_FREQ; /* 1 MHz */ + clk->pll_max_in = RM9200_PLL_A_MAX_IN_FREQ; /* 32 MHz */ + clk->pll_min_out = RM9200_PLL_A_MIN_OUT_FREQ; /* 80 MHz */ + clk->pll_max_out = RM9200_PLL_A_MAX_OUT_FREQ; /* 180 MHz */ + clk->pll_mul_shift = RM9200_PLL_A_MUL_SHIFT; + clk->pll_mul_mask = RM9200_PLL_A_MUL_MASK; + clk->pll_div_shift = RM9200_PLL_A_DIV_SHIFT; + clk->pll_div_mask = RM9200_PLL_A_DIV_MASK; + clk->set_outb = at91_pll_outb; + at91_pmc_clock_deref(clk); + + clk = at91_pmc_clock_ref("pllb"); + clk->pll_min_in = RM9200_PLL_B_MIN_IN_FREQ; /* 100 KHz */ + clk->pll_max_in = RM9200_PLL_B_MAX_IN_FREQ; /* 32 MHz */ + clk->pll_min_out = RM9200_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ + clk->pll_max_out = RM9200_PLL_B_MAX_OUT_FREQ; /* 240 MHz */ + clk->pll_mul_shift = RM9200_PLL_B_MUL_SHIFT; + clk->pll_mul_mask = RM9200_PLL_B_MUL_MASK; + clk->pll_div_shift = RM9200_PLL_B_DIV_SHIFT; + clk->pll_div_mask = RM9200_PLL_B_DIV_MASK; + clk->set_outb = at91_pll_outb; + at91_pmc_clock_deref(clk); + + return (0); +} + +static device_method_t at91_methods[] = { + DEVMETHOD(device_probe, at91_probe), + DEVMETHOD(device_attach, at91_attach), + DEVMETHOD(device_identify, at91_identify), + {0, 0}, +}; + +static driver_t at91rm92_driver = { + "at91rm920", + at91_methods, + sizeof(struct at91rm92_softc), +}; + +static devclass_t at91rm92_devclass; + +DRIVER_MODULE(at91rm920, atmelarm, at91rm92_driver, at91rm92_devclass, 0, 0); diff --git a/sys/arm/at91/at91rm92reg.h b/sys/arm/at91/at91rm92reg.h index b7ca8053ca8..8241646a3dd 100644 --- a/sys/arm/at91/at91rm92reg.h +++ b/sys/arm/at91/at91rm92reg.h @@ -27,6 +27,33 @@ #ifndef AT91RM92REG_H_ #define AT91RM92REG_H_ + +/* Chip Specific limits */ +#define RM9200_PLL_A_MIN_IN_FREQ 1000000 /* 1 MHz */ +#define RM9200_PLL_A_MAX_IN_FREQ 32000000 /* 32 MHz */ +#define RM9200_PLL_A_MIN_OUT_FREQ 80000000 /* 80 MHz */ +#define RM9200_PLL_A_MAX_OUT_FREQ 180000000 /* 180 MHz */ +#define RM9200_PLL_A_MUL_SHIFT 16 +#define RM9200_PLL_A_MUL_MASK 0x7FF +#define RM9200_PLL_A_DIV_SHIFT 0 +#define RM9200_PLL_A_DIV_MASK 0xFF + +/* + * PLL B input frequency spec sheet says it must be between 1MHz and 32MHz, + * but it works down as low as 100kHz, a frequency necessary for some + * output frequencies to work. + * + * PLL Max output frequency is 240MHz. The errata says 180MHz is the max + * for some revisions of this part. Be more permissive and optimistic. + */ +#define RM9200_PLL_B_MIN_IN_FREQ 100000 /* 100 KHz */ +#define RM9200_PLL_B_MAX_IN_FREQ 32000000 /* 32 MHz */ +#define RM9200_PLL_B_MIN_OUT_FREQ 30000000 /* 30 MHz */ +#define RM9200_PLL_B_MAX_OUT_FREQ 240000000 /* 240 MHz */ +#define RM9200_PLL_B_MUL_SHIFT 16 +#define RM9200_PLL_B_MUL_MASK 0x7FF +#define RM9200_PLL_B_DIV_SHIFT 0 +#define RM9200_PLL_B_DIV_MASK 0xFF /* * Memory map, from datasheet : * 0x00000000 - 0x0ffffffff : Internal Memories @@ -45,20 +72,26 @@ #define AT91RM92_BASE 0xd0000000 /* Usart */ +#define AT91RM92_USART_SIZE 0x4000 #define AT91RM92_USART0_BASE 0xffc0000 #define AT91RM92_USART0_PDC 0xffc0100 +#define AT91RM92_USART0_SIZE AT91RM92_USART_SIZE #define AT91RM92_USART1_BASE 0xffc4000 #define AT91RM92_USART1_PDC 0xffc4100 +#define AT91RM92_USART1_SIZE AT91RM92_USART_SIZE #define AT91RM92_USART2_BASE 0xffc8000 #define AT91RM92_USART2_PDC 0xffc8100 +#define AT91RM92_USART2_SIZE AT91RM92_USART_SIZE #define AT91RM92_USART3_BASE 0xffcc000 #define AT91RM92_USART3_PDC 0xffcc100 -#define AT91RM92_USART_SIZE 0x4000 +#define AT91RM92_USART3_SIZE AT91RM92_USART_SIZE /* System Registers */ #define AT91RM92_SYS_BASE 0xffff000 #define AT91RM92_SYS_SIZE 0x1000 + +#if 0 /* Interrupt Controller */ #define IC_SMR (0) /* Source mode register */ #define IC_SVR (128) /* Source vector register */ @@ -79,13 +112,6 @@ #define IC_FFDR (324) /* Fast forcing disable register */ #define IC_FFSR (328) /* Fast forcing status register */ -/* DBGU */ - -#define DBGU 0x200 -#define DBGU_SIZE 0x200 -#define DBGU_C1R (0x200 + 64) /* Chip ID1 Register */ -#define DBGU_C2R (0x200 + 68) /* Chip ID2 Register */ -#define DBGU_FNTR (0x200 + 72) /* Force NTRST Register */ #define PIOA_PER (0x400) /* PIO Enable Register */ #define PIOA_PDR (0x400 + 4) /* PIO Disable Register */ @@ -204,14 +230,19 @@ #define PIOD_OWDR (0xa00 + 164) /* Output write disable register */ #define PIOD_OWSR (0xa00 + 168) /* Output write status register */ +#endif /* * PIO */ -#define AT91RM92_PIOA_BASE 0xffff400 #define AT91RM92_PIO_SIZE 0x200 +#define AT91RM92_PIOA_BASE 0xffff400 +#define AT91RM92_PIOA_SIZE AT91RM92_PIO_SIZE #define AT91RM92_PIOB_BASE 0xffff600 +#define AT91RM92_PIOB_SIZE AT91RM92_PIO_SIZE #define AT91RM92_PIOC_BASE 0xffff800 +#define AT91RM92_PIOC_SIZE AT91RM92_PIO_SIZE #define AT91RM92_PIOD_BASE 0xffffa00 +#define AT91RM92_PIOD_SIZE AT91RM92_PIO_SIZE /* * PMC @@ -271,21 +302,40 @@ #define AT91RM92_IRQ_SSC0 14 #define AT91RM92_IRQ_SSC1 15 #define AT91RM92_IRQ_SSC2 16 -#define AT91RM92_IRQ_TC0 17 -#define AT91RM92_IRQ_TC1 18 -#define AT91RM92_IRQ_TC2 19 -#define AT91RM92_IRQ_TC3 20 -#define AT91RM92_IRQ_TC4 21 -#define AT91RM92_IRQ_TC5 22 +#define AT91RM92_IRQ_TC0 17,18,19 +#define AT91RM92_IRQ_TC0C0 17 +#define AT91RM92_IRQ_TC0C1 18 +#define AT91RM92_IRQ_TC0C2 19 +#define AT91RM92_IRQ_TC1 20,21,22 +#define AT91RM92_IRQ_TC1C1 20 +#define AT91RM92_IRQ_TC1C2 21 +#define AT91RM92_IRQ_TC1C3 22 #define AT91RM92_IRQ_UHP 23 #define AT91RM92_IRQ_EMAC 24 -#define AT91RM92_IRQ_AIC_BASE 25 +#define AT91RM92_IRQ_AIC_IRQ0 25 +#define AT91RM92_IRQ_AIC_IRQ1 26 +#define AT91RM92_IRQ_AIC_IRQ2 27 +#define AT91RM92_IRQ_AIC_IRQ3 28 +#define AT91RM92_IRQ_AIC_IRQ4 29 +#define AT91RM92_IRQ_AIC_IRQ5 30 +#define AT91RM92_IRQ_AIC_IRQ6 31 + +/* Alias */ +#define AT91RM92_IRQ_DBGU AT91RM92_IRQ_SYSTEM +#define AT91RM92_IRQ_PMC AT91RM92_IRQ_SYSTEM +#define AT91RM92_IRQ_ST AT91RM92_IRQ_SYSTEM +#define AT91RM92_IRQ_RTC AT91RM92_IRQ_SYSTEM +#define AT91RM92_IRQ_MC AT91RM92_IRQ_SYSTEM +#define AT91RM92_IRQ_OHCI AT91RM92_IRQ_UHP +#define AT91RM92_IRQ_AIC -1 +#define AT91RM92_IRQ_CF -1 /* Timer */ #define AT91RM92_AIC_BASE 0xffff000 #define AT91RM92_AIC_SIZE 0x200 +/* DBGU */ #define AT91RM92_DBGU_BASE 0xffff200 #define AT91RM92_DBGU_SIZE 0x200 @@ -302,16 +352,18 @@ #define AT91RM92_SPI_SIZE 0x4000 #define AT91RM92_SPI_PDC 0xffe0100 +#define AT91RM92_SSC_SIZE 0x4000 #define AT91RM92_SSC0_BASE 0xffd0000 #define AT91RM92_SSC0_PDC 0xffd0100 +#define AT91RM92_SSC0_SIZE AT91RM92_SSC_SIZE #define AT91RM92_SSC1_BASE 0xffd4000 #define AT91RM92_SSC1_PDC 0xffd4100 +#define AT91RM92_SSC1_SIZE AT91RM92_SSC_SIZE #define AT91RM92_SSC2_BASE 0xffd8000 #define AT91RM92_SSC2_PDC 0xffd8100 - -#define AT91RM92_SSC_SIZE 0x4000 +#define AT91RM92_SSC2_SIZE AT91RM92_SSC_SIZE #define AT91RM92_EMAC_BASE 0xffbc000 #define AT91RM92_EMAC_SIZE 0x4000 @@ -326,17 +378,23 @@ #define AT91RM92_UDP_BASE 0xffb0000 #define AT91RM92_UDP_SIZE 0x4000 -#define AT91RM92_TC0_BASE 0xffa0000 #define AT91RM92_TC_SIZE 0x4000 +#define AT91RM92_TC0_BASE 0xffa0000 +#define AT91RM92_TC0_SIZE AT91RM92_TC_SIZE #define AT91RM92_TC0C0_BASE 0xffa0000 #define AT91RM92_TC0C1_BASE 0xffa0040 #define AT91RM92_TC0C2_BASE 0xffa0080 #define AT91RM92_TC1_BASE 0xffa4000 +#define AT91RM92_TC1_SIZE AT91RM92_TC_SIZE #define AT91RM92_TC1C0_BASE 0xffa4000 #define AT91RM92_TC1C1_BASE 0xffa4040 #define AT91RM92_TC1C2_BASE 0xffa4080 +/* XXX Needs to be carfully coordinated with + * other * soc's so phyical and vm address + * mapping are unique. XXX + */ #define AT91RM92_OHCI_BASE 0xdfe00000 #define AT91RM92_OHCI_PA_BASE 0x00300000 #define AT91RM92_OHCI_SIZE 0x00100000 diff --git a/sys/arm/at91/at91sam9.c b/sys/arm/at91/at91sam9.c deleted file mode 100644 index a6510ea5eea..00000000000 --- a/sys/arm/at91/at91sam9.c +++ /dev/null @@ -1,717 +0,0 @@ -/*- - * Copyright (c) 2005 Olivier Houchard. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define _ARM32_BUS_DMA_PRIVATE -#include -#include -#include -#include -#include - -static struct at91_softc *at91_softc; - -static void at91_eoi(void *); - -uint32_t at91_master_clock = AT91C_MASTER_CLOCK; - -static int -at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, - bus_space_handle_t *bshp) -{ - vm_paddr_t pa, endpa; - - pa = trunc_page(bpa); - if (pa >= 0xfff00000) { - *bshp = pa - 0xf0000000 + 0xd0000000; - return (0); - } - if (pa >= 0xdff00000) - return (0); - endpa = round_page(bpa + size); - - *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa); - - return (0); -} - -static void -at91_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) -{ - vm_offset_t va, endva; - - va = trunc_page((vm_offset_t)t); - endva = va + round_page(size); - - /* Free the kernel virtual mapping. */ - kmem_free(kernel_map, va, endva - va); -} - -static int -at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, - bus_size_t size, bus_space_handle_t *nbshp) -{ - - *nbshp = bsh + offset; - return (0); -} - -static void -at91_barrier(void *t, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, - int a) -{ -} - -bs_protos(generic); -bs_protos(generic_armv4); - -struct bus_space at91_bs_tag = { - /* cookie */ - (void *) 0, - - /* mapping/unmapping */ - at91_bs_map, - at91_bs_unmap, - at91_bs_subregion, - - /* allocation/deallocation */ - NULL, - NULL, - - /* barrier */ - at91_barrier, - - /* read (single) */ - generic_bs_r_1, - generic_armv4_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple */ - generic_bs_rm_1, - generic_armv4_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region */ - generic_bs_rr_1, - generic_armv4_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) */ - generic_bs_w_1, - generic_armv4_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple */ - generic_bs_wm_1, - generic_armv4_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region */ - NULL, - generic_armv4_bs_wr_2, - generic_bs_wr_4, - NULL, - - /* set multiple */ - NULL, - NULL, - NULL, - NULL, - - /* set region */ - NULL, - generic_armv4_bs_sr_2, - generic_bs_sr_4, - NULL, - - /* copy */ - NULL, - generic_armv4_bs_c_2, - NULL, - NULL, - - /* read (single) stream */ - generic_bs_r_1, - generic_armv4_bs_r_2, - generic_bs_r_4, - NULL, - - /* read multiple stream */ - generic_bs_rm_1, - generic_armv4_bs_rm_2, - generic_bs_rm_4, - NULL, - - /* read region stream */ - generic_bs_rr_1, - generic_armv4_bs_rr_2, - generic_bs_rr_4, - NULL, - - /* write (single) stream */ - generic_bs_w_1, - generic_armv4_bs_w_2, - generic_bs_w_4, - NULL, - - /* write multiple stream */ - generic_bs_wm_1, - generic_armv4_bs_wm_2, - generic_bs_wm_4, - NULL, - - /* write region stream */ - NULL, - generic_armv4_bs_wr_2, - generic_bs_wr_4, - NULL, -}; - -static int -at91_probe(device_t dev) -{ - device_set_desc(dev, "AT91 device bus"); - arm_post_filter = at91_eoi; - return (0); -} - -static void -at91_identify(driver_t *drv, device_t parent) -{ - - BUS_ADD_CHILD(parent, 0, "atmelarm", 0); -} - -struct arm32_dma_range * -bus_dma_get_range(void) -{ - - return (NULL); -} - -int -bus_dma_get_range_nb(void) -{ - return (0); -} - -extern void irq_entry(void); - -static void -at91_add_child(device_t dev, int prio, const char *name, int unit, - bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) -{ - device_t kid; - struct at91_ivar *ivar; - - kid = device_add_child_ordered(dev, prio, name, unit); - if (kid == NULL) { - printf("Can't add child %s%d ordered\n", name, unit); - return; - } - ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); - if (ivar == NULL) { - device_delete_child(dev, kid); - printf("Can't add alloc ivar\n"); - return; - } - device_set_ivars(kid, ivar); - resource_list_init(&ivar->resources); - if (irq0 != -1) - bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); - if (irq1 != 0) - bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); - if (irq2 != 0) - bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); - if (addr != 0) - bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); -} - -struct cpu_devs -{ - const char *name; - int unit; - bus_addr_t mem_base; - bus_size_t mem_len; - int irq0; - int irq1; - int irq2; -}; - -struct cpu_devs at91sam9_devs[] = -{ - { - "at91_pit", 0, - AT91SAM9G20_BASE + AT91SAM9G20_PIT_BASE, AT91SAM9G20_PIT_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "at91_wdt", 0, - AT91SAM9G20_BASE + AT91SAM9G20_WDT_BASE, AT91SAM9G20_WDT_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "at91_pmc", 0, - AT91SAM9G20_BASE + AT91SAM9G20_PMC_BASE, AT91SAM9G20_PMC_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "at91_pio", 0, - AT91SAM9G20_BASE + AT91SAM9G20_PIOA_BASE, AT91SAM9G20_PIO_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "at91_pio", 1, - AT91SAM9G20_BASE + AT91SAM9G20_PIOB_BASE, AT91SAM9G20_PIO_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "at91_pio", 2, - AT91SAM9G20_BASE + AT91SAM9G20_PIOC_BASE, AT91SAM9G20_PIO_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "uart", 0, - AT91SAM9G20_BASE + AT91SAM9G20_DBGU_BASE, AT91SAM9G20_DBGU_SIZE, - AT91SAM9G20_IRQ_SYSTEM - }, - { - "uart", 1, - AT91SAM9G20_BASE + AT91SAM9G20_USART0_BASE, AT91SAM9G20_USART_SIZE, - AT91SAM9G20_IRQ_USART0 - }, - { - "uart", 2, - AT91SAM9G20_BASE + AT91SAM9G20_USART1_BASE, AT91SAM9G20_USART_SIZE, - AT91SAM9G20_IRQ_USART1 - }, - { - "uart", 3, - AT91SAM9G20_BASE + AT91SAM9G20_USART2_BASE, AT91SAM9G20_USART_SIZE, - AT91SAM9G20_IRQ_USART2 - }, - { - "spi", 0, - AT91SAM9G20_BASE + AT91SAM9G20_SPI0_BASE, AT91SAM9G20_SPI0_SIZE, - AT91SAM9G20_IRQ_SPI0 - }, - { - "spi", 1, - AT91SAM9G20_BASE + AT91SAM9G20_SPI1_BASE, AT91SAM9G20_SPI1_SIZE, - AT91SAM9G20_IRQ_SPI1 - }, - { - "ohci", 0, - AT91SAM9G20_OHCI_BASE, AT91SAM9G20_OHCI_SIZE, - AT91SAM9G20_IRQ_UHP - }, - { - "macb", 0, - AT91SAM9G20_BASE + AT91SAM9G20_EMAC_BASE, AT91SAM9G20_EMAC_SIZE, - AT91SAM9G20_IRQ_EMAC - }, - { - "nand", 0, - AT91SAM9G20_NAND_BASE, AT91SAM9G20_NAND_SIZE, - -1 - }, - { 0, 0, 0, 0, 0 } -}; - -static void -at91_cpu_add_builtin_children(device_t dev, struct at91_softc *sc) -{ - int i; - struct cpu_devs *walker; - - // XXX should look at the device id in the DBGU register and - // XXX based on the CPU load in these devices - for (i = 0, walker = at91sam9_devs; walker->name; i++, walker++) { - at91_add_child(dev, i, walker->name, walker->unit, - walker->mem_base, walker->mem_len, walker->irq0, - walker->irq1, walker->irq2); - } -} - -#define NORMDEV 50 - -/* - * Standard priority levels for the system. 0 is lowest and 7 is highest. - * These values are the ones Atmel uses for its Linux port - */ -static int irq_prio[32] = -{ - 7, /* Advanced Interrupt Controller */ - 7, /* System Peripherals */ - 1, /* Parallel IO Controller A */ - 1, /* Parallel IO Controller B */ - 1, /* Parallel IO Controller C */ - 0, /* Analog-to-Digital Converter */ - 5, /* USART 0 */ - 5, /* USART 1 */ - 5, /* USART 2 */ - 0, /* Multimedia Card Interface */ - 2, /* USB Device Port */ - 6, /* Two-Wire Interface */ - 5, /* Serial Peripheral Interface 0 */ - 5, /* Serial Peripheral Interface 1 */ - 5, /* Serial Synchronous Controller */ - 0, - 0, - 0, /* Timer Counter 0 */ - 0, /* Timer Counter 1 */ - 0, /* Timer Counter 2 */ - 2, /* USB Host port */ - 3, /* Ethernet */ - 0, /* Image Sensor Interface */ - 5, /* USART 3 */ - 5, /* USART 4 */ - 5, /* USART 5 */ - 0, /* Timer Counter 3 */ - 0, /* Timer Counter 4 */ - 0, /* Timer Counter 5 */ - 0, /* Advanced Interrupt Controller */ - 0, /* Advanced Interrupt Controller */ - 0, /* Advanced Interrupt Controller */ -}; - -static int -at91_attach(device_t dev) -{ - struct at91_softc *sc = device_get_softc(dev); - int i; - - at91_softc = sc; - sc->sc_st = &at91_bs_tag; - sc->sc_sh = AT91SAM9G20_BASE; - sc->dev = dev; - if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE, - AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0) - panic("Enable to map IRQ registers"); - sc->sc_irq_rman.rm_type = RMAN_ARRAY; - sc->sc_irq_rman.rm_descr = "AT91 IRQs"; - sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "AT91 Memory"; - if (rman_init(&sc->sc_irq_rman) != 0 || - rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) - panic("at91_attach: failed to set up IRQ rman"); - if (rman_init(&sc->sc_mem_rman) != 0 || - rman_manage_region(&sc->sc_mem_rman, 0xdff00000ul, - 0xdffffffful) != 0) - panic("at91_attach: failed to set up memory rman"); - if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_OHCI_BASE, - AT91SAM9G20_OHCI_BASE + AT91SAM9G20_OHCI_SIZE - 1) != 0) - panic("at91_attach: failed to set up ohci memory"); - - if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_NAND_BASE, - AT91SAM9G20_NAND_BASE + AT91SAM9G20_NAND_SIZE - 1) != 0) - panic("at91_attach: failed to set up ohci memory"); - - -#if 0 - if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_CF_BASE, - AT91SAM9G20_CF_BASE + AT91SAM9G20_CF_SIZE - 1) != 0) - panic("at91_attach: failed to set up CompactFlash ATA memory"); -#endif - - for (i = 0; i < 32; i++) { - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SVR + - i * 4, i); - /* Priority. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SMR + i * 4, - irq_prio[i]); - if (i < 8) - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_EOICR, - 1); - } - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SPU, 32); - /* No debug. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_DCR, 0); - /* Disable and clear all interrupts. */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IDCR, 0xffffffff); - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_ICCR, 0xffffffff); - - /* XXX */ - /* Disable all interrupts for RTC (0xe24 == RTC_IDR) */ - //bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff); - - /* DIsable all interrupts for DBGU */ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x120c, 0xffffffff); - /* Disable all interrupts for the SDRAM controller */ - //bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff); - - - i = bus_space_read_4(sc->sc_st, - sc->sc_sys_sh, AT91SAM9G20_EBICSA); - - /*activate NAND*/ - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, AT91SAM9G20_EBICSA, - i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); - - - at91_cpu_add_builtin_children(dev, sc); - - bus_generic_probe(dev); - bus_generic_attach(dev); - enable_interrupts(I32_bit | F32_bit); - return (0); -} - -static struct resource * -at91_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - struct at91_softc *sc = device_get_softc(dev); - struct resource_list_entry *rle; - struct at91_ivar *ivar = device_get_ivars(child); - struct resource_list *rl = &ivar->resources; - - if (device_get_parent(child) != dev) - return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, - type, rid, start, end, count, flags)); - - rle = resource_list_find(rl, type, *rid); - if (rle == NULL) - return (NULL); - if (rle->res) - panic("Resource rid %d type %d already in use", *rid, type); - if (start == 0UL && end == ~0UL) { - start = rle->start; - count = ulmax(count, rle->count); - end = ulmax(rle->end, start + count - 1); - } - switch (type) - { - case SYS_RES_IRQ: - rle->res = rman_reserve_resource(&sc->sc_irq_rman, - start, end, count, flags, child); - break; - case SYS_RES_MEMORY: - - rle->res = rman_reserve_resource(&sc->sc_mem_rman, - start, end, count, flags, child); - if (rle->res != NULL) { - rman_set_bustag(rle->res, &at91_bs_tag); - rman_set_bushandle(rle->res, start); - } - break; - } - if (rle->res) { - rle->start = rman_get_start(rle->res); - rle->end = rman_get_end(rle->res); - rle->count = count; - rman_set_rid(rle->res, *rid); - } - return (rle->res); -} - -static struct resource_list * -at91_get_resource_list(device_t dev, device_t child) -{ - struct at91_ivar *ivar; - - ivar = device_get_ivars(child); - return (&(ivar->resources)); -} - -static int -at91_release_resource(device_t dev, device_t child, int type, - int rid, struct resource *r) -{ - struct resource_list *rl; - struct resource_list_entry *rle; - - rl = at91_get_resource_list(dev, child); - if (rl == NULL) - return (EINVAL); - rle = resource_list_find(rl, type, rid); - if (rle == NULL) - return (EINVAL); - rman_release_resource(r); - rle->res = NULL; - return (0); -} - -static int -at91_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t *filt, - driver_intr_t *intr, void *arg, void **cookiep) -{ - struct at91_softc *sc = device_get_softc(dev); - - if (rman_get_start(ires) == AT91SAM9G20_IRQ_SYSTEM && filt == NULL) - panic("All system interrupt ISRs must be FILTER"); - BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, - intr, arg, cookiep); - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IECR, - 1 << rman_get_start(ires)); - return (0); -} - -static int -at91_teardown_intr(device_t dev, device_t child, struct resource *res, - void *cookie) -{ - struct at91_softc *sc = device_get_softc(dev); - - bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IDCR, - 1 << rman_get_start(res)); - return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); -} - -static int -at91_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ -#if 0 - u_long p; - int error; - - if (type == SYS_RES_MEMORY) { - error = bus_space_map(rman_get_bustag(r), - rman_get_bushandle(r), rman_get_size(r), 0, &p); - if (error) - return (error); - rman_set_bushandle(r, p); - } -#endif - return (rman_activate_resource(r)); -} - -static int -at91_print_child(device_t dev, device_t child) -{ - struct at91_ivar *ivars; - struct resource_list *rl; - int retval = 0; - - ivars = device_get_ivars(child); - rl = &ivars->resources; - - retval += bus_print_child_header(dev, child); - - retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); - retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); - retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); - if (device_get_flags(dev)) - retval += printf(" flags %#x", device_get_flags(dev)); - - retval += bus_print_child_footer(dev, child); - - return (retval); -} - -void -arm_mask_irq(uintptr_t nb) -{ - - bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, 0x1000 + IC_IDCR, 1 << nb); - -} - -int -arm_get_next_irq(int last __unused) -{ - int status; - int irq; - - irq = bus_space_read_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, 0x1000 + IC_IVR); - status = bus_space_read_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, 0x1000 + IC_ISR); - if (status == 0) { - bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, 0x1000 + IC_EOICR, 1); - return (-1); - } - return (irq); -} - -void -arm_unmask_irq(uintptr_t nb) -{ - - bus_space_write_4(at91_softc->sc_st, - at91_softc->sc_sys_sh, 0x1000 + IC_IECR, 1 << nb); - bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, - 0x1000 + IC_EOICR, 0); - -} - -static void -at91_eoi(void *unused) -{ - bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, - 0x1000 + IC_EOICR, 0); -} - -static device_method_t at91_methods[] = { - DEVMETHOD(device_probe, at91_probe), - DEVMETHOD(device_attach, at91_attach), - DEVMETHOD(device_identify, at91_identify), - - DEVMETHOD(bus_alloc_resource, at91_alloc_resource), - DEVMETHOD(bus_setup_intr, at91_setup_intr), - DEVMETHOD(bus_teardown_intr, at91_teardown_intr), - DEVMETHOD(bus_activate_resource, at91_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_get_resource_list,at91_get_resource_list), - DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), - DEVMETHOD(bus_release_resource, at91_release_resource), - DEVMETHOD(bus_print_child, at91_print_child), - - {0, 0}, -}; - -static driver_t at91_driver = { - "atmelarm", - at91_methods, - sizeof(struct at91_softc), -}; -static devclass_t at91_devclass; - -DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0); diff --git a/sys/arm/at91/at91sam9260.c b/sys/arm/at91/at91sam9260.c new file mode 100644 index 00000000000..2e14cf3d8ad --- /dev/null +++ b/sys/arm/at91/at91sam9260.c @@ -0,0 +1,343 @@ +/*- + * Copyright (c) 2005 Olivier Houchard. All rights reserved. + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#define _ARM32_BUS_DMA_PRIVATE +#include + +#include +#include +#include +#include +#include + +struct at91sam9_softc { + device_t dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + bus_space_handle_t sc_sys_sh; + bus_space_handle_t sc_aic_sh; + bus_space_handle_t sc_dbg_sh; + bus_space_handle_t sc_matrix_sh; +}; + +/* + * Standard priority levels for the system. 0 is lowest and 7 is highest. + * These values are the ones Atmel uses for its Linux port + */ +static const int at91_irq_prio[32] = +{ + 7, /* Advanced Interrupt Controller */ + 7, /* System Peripherals */ + 1, /* Parallel IO Controller A */ + 1, /* Parallel IO Controller B */ + 1, /* Parallel IO Controller C */ + 0, /* Analog-to-Digital Converter */ + 5, /* USART 0 */ + 5, /* USART 1 */ + 5, /* USART 2 */ + 0, /* Multimedia Card Interface */ + 2, /* USB Device Port */ + 6, /* Two-Wire Interface */ + 5, /* Serial Peripheral Interface 0 */ + 5, /* Serial Peripheral Interface 1 */ + 5, /* Serial Synchronous Controller */ + 0, /* (reserved) */ + 0, /* (reserved) */ + 0, /* Timer Counter 0 */ + 0, /* Timer Counter 1 */ + 0, /* Timer Counter 2 */ + 2, /* USB Host port */ + 3, /* Ethernet */ + 0, /* Image Sensor Interface */ + 5, /* USART 3 */ + 5, /* USART 4 */ + 5, /* USART 5 */ + 0, /* Timer Counter 3 */ + 0, /* Timer Counter 4 */ + 0, /* Timer Counter 5 */ + 0, /* Advanced Interrupt Controller IRQ0 */ + 0, /* Advanced Interrupt Controller IRQ1 */ + 0, /* Advanced Interrupt Controller IRQ2 */ +}; + +#define DEVICE(_name, _id, _unit) \ + { \ + _name, _unit, \ + AT91SAM9260_ ## _id ##_BASE, \ + AT91SAM9260_ ## _id ## _SIZE, \ + AT91SAM9260_IRQ_ ## _id \ + } + +static const struct cpu_devs at91_devs[] = +{ + DEVICE("at91_pmc", PMC, 0), + DEVICE("at91_wdt", WDT, 0), + DEVICE("at91_rst", RSTC, 0), + DEVICE("at91_pit", PIT, 0), + DEVICE("at91_pio", PIOA, 0), + DEVICE("at91_pio", PIOB, 1), + DEVICE("at91_pio", PIOC, 2), + DEVICE("at91_twi", TWI, 0), + DEVICE("at91_mci", MCI, 0), + DEVICE("uart", DBGU, 0), + DEVICE("uart", USART0, 1), + DEVICE("uart", USART1, 2), + DEVICE("uart", USART2, 3), + DEVICE("uart", USART3, 4), + DEVICE("uart", USART4, 5), + DEVICE("uart", USART5, 6), + DEVICE("spi", SPI0, 0), + DEVICE("spi", SPI1, 1), + DEVICE("ate", EMAC, 0), + DEVICE("macb", EMAC, 0), + DEVICE("nand", NAND, 0), + DEVICE("ohci", OHCI, 0), + { 0, 0, 0, 0, 0 } +}; + +static void +at91_add_child(device_t dev, int prio, const char *name, int unit, + bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) +{ + device_t kid; + struct at91_ivar *ivar; + + kid = device_add_child_ordered(dev, prio, name, unit); + if (kid == NULL) { + printf("Can't add child %s%d ordered\n", name, unit); + return; + } + ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ivar == NULL) { + device_delete_child(dev, kid); + printf("Can't add alloc ivar\n"); + return; + } + device_set_ivars(kid, ivar); + resource_list_init(&ivar->resources); + if (irq0 != -1) { + bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); + if (irq0 != AT91SAM9260_IRQ_SYSTEM) + at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); + } + if (irq1 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); + if (irq2 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); + if (addr != 0 && addr < AT91SAM9260_BASE) + addr += AT91SAM9260_BASE; + if (addr != 0) + bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); +} + +static void +at91_cpu_add_builtin_children(device_t dev) +{ + int i; + const struct cpu_devs *walker; + + for (i = 1, walker = at91_devs; walker->name; i++, walker++) { + at91_add_child(dev, i, walker->name, walker->unit, + walker->mem_base, walker->mem_len, walker->irq0, + walker->irq1, walker->irq2); + } +} + +static uint32_t +at91_pll_outa(int freq) +{ + + if (freq > 195000000) + return (0x20000000); + else + return (0x20008000); +} + +static uint32_t +at91_pll_outb(int freq) +{ + return (0x4000); +} + +static void +at91_identify(driver_t *drv, device_t parent) +{ + + if (at91_cpu_is(AT91_CPU_SAM9260)) { + at91_add_child(parent, 0, "at91sam9260", 0, 0, 0, -1, 0, 0); + at91_cpu_add_builtin_children(parent); + } +} + +static int +at91_probe(device_t dev) +{ + + if (at91_cpu_is(AT91_CPU_SAM9260)) { + device_set_desc(dev, "AT91SAM9260"); + return (0); + } + return (ENXIO); +} + +static int +at91_attach(device_t dev) +{ + struct at91_pmc_clock *clk; + struct at91sam9_softc *sc = device_get_softc(dev); + int i; + + struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); + + sc->sc_st = at91sc->sc_st; + sc->sc_sh = at91sc->sc_sh; + sc->dev = dev; + + /* + * XXX These values work for the RM9200, SAM926[01], and SAM9260 + * will have to fix this when we want to support anything else. XXX + */ + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_SYS_BASE, + AT91SAM9260_SYS_SIZE, &sc->sc_sys_sh) != 0) + panic("Enable to map system registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_DBGU_BASE, + AT91SAM9260_DBGU_SIZE, &sc->sc_dbg_sh) != 0) + panic("Enable to map DBGU registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9260_AIC_BASE, + AT91SAM9260_AIC_SIZE, &sc->sc_aic_sh) != 0) + panic("Enable to map system registers"); + + /* XXX Hack to tell atmelarm about the AIC */ + at91sc->sc_aic_sh = sc->sc_aic_sh; + at91sc->sc_irq_system = AT91SAM9260_IRQ_SYSTEM; + + for (i = 0; i < 32; i++) { + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + + i * 4, i); + /* Priority. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, + at91_irq_prio[i]); + if (i < 8) + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, + 1); + } + + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); + /* No debug. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); + + /* Disable all interrupts for DBGU */ + bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, + AT91SAM9260_MATRIX_BASE, AT91SAM9260_MATRIX_SIZE, + &sc->sc_matrix_sh) != 0) + panic("Enable to map matrix registers"); + + /* activate NAND*/ + i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, + AT91SAM9260_EBICSA); + bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, + AT91SAM9260_EBICSA, + i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); + + + /* Update USB device port clock info */ + clk = at91_pmc_clock_ref("udpck"); + clk->pmc_mask = PMC_SCER_UDP_SAM9; + at91_pmc_clock_deref(clk); + + /* Update USB host port clock info */ + clk = at91_pmc_clock_ref("uhpck"); + clk->pmc_mask = PMC_SCER_UHP_SAM9; + at91_pmc_clock_deref(clk); + + /* Each SOC has different PLL contraints */ + clk = at91_pmc_clock_ref("plla"); + clk->pll_min_in = SAM9260_PLL_A_MIN_IN_FREQ; /* 1 MHz */ + clk->pll_max_in = SAM9260_PLL_A_MAX_IN_FREQ; /* 32 MHz */ + clk->pll_min_out = SAM9260_PLL_A_MIN_OUT_FREQ; /* 80 MHz */ + clk->pll_max_out = SAM9260_PLL_A_MAX_OUT_FREQ; /* 240 MHz */ + clk->pll_mul_shift = SAM9260_PLL_A_MUL_SHIFT; + clk->pll_mul_mask = SAM9260_PLL_A_MUL_MASK; + clk->pll_div_shift = SAM9260_PLL_A_DIV_SHIFT; + clk->pll_div_mask = SAM9260_PLL_A_DIV_MASK; + clk->set_outb = at91_pll_outa; + at91_pmc_clock_deref(clk); + + /* + * Fudge MAX pll in frequence down below 3.0 Mhz to ensure + * PMC alogrithm choose the divisor that causes the input clock + * to be near the optimal 2 Mhz per datasheet. We know + * we are going to be using this for the USB clock at 96 Mhz. + * Causes no extra frequency deviation for all recomended crystal values. + */ + clk = at91_pmc_clock_ref("pllb"); + clk->pll_min_in = SAM9260_PLL_B_MIN_IN_FREQ; /* 1 MHz */ + clk->pll_max_in = SAM9260_PLL_B_MAX_IN_FREQ; /* 5 MHz */ + clk->pll_max_in = 2999999; /* ~3 MHz */ + clk->pll_min_out = SAM9260_PLL_B_MIN_OUT_FREQ; /* 70 MHz */ + clk->pll_max_out = SAM9260_PLL_B_MAX_OUT_FREQ; /* 130 MHz */ + clk->pll_mul_shift = SAM9260_PLL_B_MUL_SHIFT; + clk->pll_mul_mask = SAM9260_PLL_B_MUL_MASK; + clk->pll_div_shift = SAM9260_PLL_B_DIV_SHIFT; + clk->pll_div_mask = SAM9260_PLL_B_DIV_MASK; + clk->set_outb = at91_pll_outb; + at91_pmc_clock_deref(clk); + return (0); +} + +static device_method_t at91sam9260_methods[] = { + DEVMETHOD(device_probe, at91_probe), + DEVMETHOD(device_attach, at91_attach), + DEVMETHOD(device_identify, at91_identify), + {0, 0}, +}; + +static driver_t at91sam9260_driver = { + "at91sam9260", + at91sam9260_methods, + sizeof(struct at91sam9_softc), +}; + +static devclass_t at91sam9260_devclass; + +DRIVER_MODULE(at91sam9260, atmelarm, at91sam9260_driver, at91sam9260_devclass, 0, 0); diff --git a/sys/arm/at91/at91sam9260reg.h b/sys/arm/at91/at91sam9260reg.h new file mode 100644 index 00000000000..c790c2cf9e4 --- /dev/null +++ b/sys/arm/at91/at91sam9260reg.h @@ -0,0 +1,310 @@ +/*- + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef AT91SAM9260REG_H_ +#define AT91SAM9260REG_H_ + +#ifndef AT91SAM9260_MASTER_CLOCK +#define AT91SAM9260_MASTER_CLOCK ((18432000 * 43)/6) +#endif + +/* Chip Specific limits */ +#define SAM9260_PLL_A_MIN_IN_FREQ 1000000 /* 1 Mhz */ +#define SAM9260_PLL_A_MAX_IN_FREQ 32000000 /* 32 Mhz */ +#define SAM9260_PLL_A_MIN_OUT_FREQ 80000000 /* 80 Mhz */ +#define SAM9260_PLL_A_MAX_OUT_FREQ 240000000 /* 240 Mhz */ +#define SAM9260_PLL_A_MUL_SHIFT 16 +#define SAM9260_PLL_A_MUL_MASK 0x3FF +#define SAM9260_PLL_A_DIV_SHIFT 0 +#define SAM9260_PLL_A_DIV_MASK 0xFF + +#define SAM9260_PLL_B_MIN_IN_FREQ 1000000 /* 1 Mhz */ +#define SAM9260_PLL_B_MAX_IN_FREQ 5000000 /* 5 Mhz */ +#define SAM9260_PLL_B_MIN_OUT_FREQ 70000000 /* 70 Mhz */ +#define SAM9260_PLL_B_MAX_OUT_FREQ 130000000 /* 130 Mhz */ +#define SAM9260_PLL_B_MUL_SHIFT 16 +#define SAM9260_PLL_B_MUL_MASK 0x3FF +#define SAM9260_PLL_B_DIV_SHIFT 0 +#define SAM9260_PLL_B_DIV_MASK 0xFF + +/* + * Memory map, from datasheet : + * 0x00000000 - 0x0ffffffff : Internal Memories + * 0x10000000 - 0x1ffffffff : Chip Select 0 + * 0x20000000 - 0x2ffffffff : Chip Select 1 + * 0x30000000 - 0x3ffffffff : Chip Select 2 + * 0x40000000 - 0x4ffffffff : Chip Select 3 + * 0x50000000 - 0x5ffffffff : Chip Select 4 + * 0x60000000 - 0x6ffffffff : Chip Select 5 + * 0x70000000 - 0x7ffffffff : Chip Select 6 + * 0x80000000 - 0x8ffffffff : Chip Select 7 + * 0x90000000 - 0xeffffffff : Undefined (Abort) + * 0xf0000000 - 0xfffffffff : Peripherals + */ + +#define AT91_CHIPSELECT_0 0x10000000 +#define AT91_CHIPSELECT_1 0x20000000 +#define AT91_CHIPSELECT_2 0x30000000 +#define AT91_CHIPSELECT_3 0x40000000 +#define AT91_CHIPSELECT_4 0x50000000 +#define AT91_CHIPSELECT_5 0x60000000 +#define AT91_CHIPSELECT_6 0x70000000 +#define AT91_CHIPSELECT_7 0x80000000 + + +#define AT91SAM9260_BASE 0xd0000000 + + +#define AT91SAM9260_EMAC_BASE 0xffc4000 +#define AT91SAM9260_EMAC_SIZE 0x4000 + +#define AT91SAM9260_RSTC_BASE 0xffffd00 +#define AT91SAM9260_RSTC_SIZE 0x10 + +#define RSTC_CR 0 +#define RSTC_PROCRST (1 << 0) +#define RSTC_PERRST (1 << 2) +#define RSTC_KEY (0xa5 << 24) + +/* USART*/ + +#define AT91SAM9260_USART_SIZE 0x4000 +#define AT91SAM9260_USART0_BASE 0xffb0000 +#define AT91SAM9260_USART0_PDC 0xffb0100 +#define AT91SAM9260_USART0_SIZE AT91SAM9260_USART_SIZE +#define AT91SAM9260_USART1_BASE 0xffb4000 +#define AT91SAM9260_USART1_PDC 0xffb4100 +#define AT91SAM9260_USART1_SIZE AT91SAM9260_USART_SIZE +#define AT91SAM9260_USART2_BASE 0xffb8000 +#define AT91SAM9260_USART2_PDC 0xffb8100 +#define AT91SAM9260_USART2_SIZE AT91SAM9260_USART_SIZE +#define AT91SAM9260_USART3_BASE 0xffd0000 +#define AT91SAM9260_USART3_PDC 0xffd0100 +#define AT91SAM9260_USART3_SIZE AT91SAM9260_USART_SIZE +#define AT91SAM9260_USART4_BASE 0xffd4000 +#define AT91SAM9260_USART4_PDC 0xffd4100 +#define AT91SAM9260_USART4_SIZE AT91SAM9260_USART_SIZE +#define AT91SAM9260_USART5_BASE 0xffd8000 +#define AT91SAM9260_USART5_PDC 0xffd8100 +#define AT91SAM9260_USART5_SIZE AT91SAM9260_USART_SIZE + +/*TC*/ +#define AT91SAM9260_TC0_BASE 0xffa0000 +#define AT91SAM9260_TC0_SIZE 0x4000 +#define AT91SAM9260_TC0C0_BASE 0xffa0000 +#define AT91SAM9260_TC0C1_BASE 0xffa0040 +#define AT91SAM9260_TC0C2_BASE 0xffa0080 + +#define AT91SAM9260_TC1_BASE 0xffdc000 +#define AT91SAM9260_TC1_SIZE 0x4000 + +/*SPI*/ + +#define AT91SAM9260_SPI0_BASE 0xffc8000 + +#define AT91SAM9260_SPI0_SIZE 0x4000 +#define AT91SAM9260_IRQ_SPI0 12 + +#define AT91SAM9260_SPI1_BASE 0xffcc000 +#define AT91SAM9260_SPI1_SIZE 0x4000 +#define AT91SAM9260_IRQ_SPI1 13 + +/* System Registers */ +#define AT91SAM9260_SYS_BASE 0xffff000 +#define AT91SAM9260_SYS_SIZE 0x1000 + +#define AT91SAM9260_MATRIX_BASE 0xfffee00 +#define AT91SAM9260_MATRIX_SIZE 0x1000 +#define AT91SAM9260_EBICSA 0x011C + +#define AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA (1 << 3) + +#define AT91SAM9260_DBGU_BASE 0xffff200 +#define AT91SAM9260_DBGU_SIZE 0x200 + +/* + * PIO + */ +#define AT91SAM9260_PIOA_BASE 0xffff400 +#define AT91SAM9260_PIOA_SIZE 0x200 +#define AT91SAM9260_PIOB_BASE 0xffff600 +#define AT91SAM9260_PIOB_SIZE 0x200 +#define AT91SAM9260_PIOC_BASE 0xffff800 +#define AT91SAM9260_PIOC_SIZE 0x200 + +#define AT91RM92_PMC_BASE 0xffffc00 +#define AT91RM92_PMC_SIZE 0x100 +/* IRQs : */ +/* + * 0: AIC + * 1: System peripheral (System timer, RTC, DBGU) + * 2: PIO Controller A + * 3: PIO Controller B + * 4: PIO Controller C + * 5: ADC + * 6: USART 0 + * 7: USART 1 + * 8: USART 2 + * 9: MMC Interface + * 10: USB device port + * 11: Two-wirte interface + * 12: SPI 0 + * 13: SPI 1 + * 14: SSC + * 15: - (reserved) + * 16: - (reserved) + * 17: Timer Counter 0 + * 18: Timer Counter 1 + * 19: Timer Counter 2 + * 20: USB Host port + * 21: EMAC + * 22: ISI + * 23: USART 3 + * 24: USART 4 + * 25: USART 2 + * 26: Timer Counter 3 + * 27: Timer Counter 4 + * 28: Timer Counter 5 + * 29: AIC IRQ0 + * 30: AIC IRQ1 + * 31: AIC IRQ2 + */ + +#define AT91SAM9260_IRQ_SYSTEM 1 +#define AT91SAM9260_IRQ_PIOA 2 +#define AT91SAM9260_IRQ_PIOB 3 +#define AT91SAM9260_IRQ_PIOC 4 +#define AT91SAM9260_IRQ_USART0 6 +#define AT91SAM9260_IRQ_USART1 7 +#define AT91SAM9260_IRQ_USART2 8 +#define AT91SAM9260_IRQ_MCI 9 +#define AT91SAM9260_IRQ_UDP 10 +#define AT91SAM9260_IRQ_TWI 11 +#define AT91SAM9260_IRQ_SPI0 12 +#define AT91SAM9260_IRQ_SPI1 13 +#define AT91SAM9260_IRQ_SSC0 14 +#define AT91SAM9260_IRQ_SSC1 15 +#define AT91SAM9260_IRQ_SSC2 16 +#define AT91SAM9260_IRQ_TC0 17 +#define AT91SAM9260_IRQ_TC1 18 +#define AT91SAM9260_IRQ_TC2 19 +#define AT91SAM9260_IRQ_UHP 20 +#define AT91SAM9260_IRQ_EMAC 21 +#define AT91SAM9260_IRQ_USART3 23 +#define AT91SAM9260_IRQ_USART4 24 +#define AT91SAM9260_IRQ_USART5 25 +#define AT91SAM9260_IRQ_AICBASE 29 + +/* Alias */ +#define AT91SAM9260_IRQ_DBGU AT91SAM9260_IRQ_SYSTEM +#define AT91SAM9260_IRQ_PMC AT91SAM9260_IRQ_SYSTEM +#define AT91SAM9260_IRQ_WDT AT91SAM9260_IRQ_SYSTEM +#define AT91SAM9260_IRQ_PIT AT91SAM9260_IRQ_SYSTEM +#define AT91SAM9260_IRQ_RSTC AT91SAM9260_IRQ_SYSTEM +#define AT91SAM9260_IRQ_OHCI AT91SAM9260_IRQ_UHP +#define AT91SAM9260_IRQ_NAND (-1) + +#define AT91SAM9260_AIC_BASE 0xffff000 +#define AT91SAM9260_AIC_SIZE 0x200 + +/* Timer */ + +#define AT91SAM9260_WDT_BASE 0xffffd40 +#define AT91SAM9260_WDT_SIZE 0x10 + +#define AT91SAM9260_PIT_BASE 0xffffd30 +#define AT91SAM9260_PIT_SIZE 10 + +#define AT91SAM9260_SMC_BASE 0xfffec00 +#define AT91SAM9260_SMC_SIZE 0x200 + +#define AT91SAM9260_PMC_BASE 0xffffc00 +#define AT91SAM9260_PMC_SIZE 0x100 + +#define AT91SAM9260_UDP_BASE 0xffa4000 +#define AT91SAM9260_UDP_SIZE 0x4000 + +#define AT91SAM9260_MCI_BASE 0xffa8000 +#define AT91SAM9260_MCI_SIZE 0x4000 + +#define AT91SAM9260_TWI_BASE 0xffaC000 +#define AT91SAM9260_TWI_SIZE 0x4000 + +/* XXX Needs to be carfully coordinated with + * other * soc's so phyical and vm address + * mapping are unique. XXX + */ +#define AT91SAM9260_OHCI_BASE 0xdfc00000 +#define AT91SAM9260_OHCI_PA_BASE 0x00500000 +#define AT91SAM9260_OHCI_SIZE 0x00100000 + +#define AT91SAM9260_NAND_BASE 0xe0000000 +#define AT91SAM9260_NAND_PA_BASE 0x40000000 +#define AT91SAM9260_NAND_SIZE 0x10000000 + + +/* SDRAMC */ +#define AT91SAM9260_SDRAMC_BASE 0xfffea00 +#define AT91SAM9260_SDRAMC_MR 0x00 +#define AT91SAM9260_SDRAMC_MR_MODE_NORMAL 0 +#define AT91SAM9260_SDRAMC_MR_MODE_NOP 1 +#define AT91SAM9260_SDRAMC_MR_MODE_PRECHARGE 2 +#define AT91SAM9260_SDRAMC_MR_MODE_LOAD_MODE_REGISTER 3 +#define AT91SAM9260_SDRAMC_MR_MODE_REFRESH 4 +#define AT91SAM9260_SDRAMC_TR 0x04 +#define AT91SAM9260_SDRAMC_CR 0x08 +#define AT91SAM9260_SDRAMC_CR_NC_8 0x0 +#define AT91SAM9260_SDRAMC_CR_NC_9 0x1 +#define AT91SAM9260_SDRAMC_CR_NC_10 0x2 +#define AT91SAM9260_SDRAMC_CR_NC_11 0x3 +#define AT91SAM9260_SDRAMC_CR_NC_MASK 0x00000003 +#define AT91SAM9260_SDRAMC_CR_NR_11 0x0 +#define AT91SAM9260_SDRAMC_CR_NR_12 0x4 +#define AT91SAM9260_SDRAMC_CR_NR_13 0x8 +#define AT91SAM9260_SDRAMC_CR_NR_RES 0xc +#define AT91SAM9260_SDRAMC_CR_NR_MASK 0x0000000c +#define AT91SAM9260_SDRAMC_CR_NB_2 0x00 +#define AT91SAM9260_SDRAMC_CR_NB_4 0x10 +#define AT91SAM9260_SDRAMC_CR_DBW_16 0x80 +#define AT91SAM9260_SDRAMC_CR_NB_MASK 0x00000010 +#define AT91SAM9260_SDRAMC_CR_NCAS_MASK 0x00000060 +#define AT91SAM9260_SDRAMC_CR_TWR_MASK 0x00000780 +#define AT91SAM9260_SDRAMC_CR_TRC_MASK 0x00007800 +#define AT91SAM9260_SDRAMC_CR_TRP_MASK 0x00078000 +#define AT91SAM9260_SDRAMC_CR_TRCD_MASK 0x00780000 +#define AT91SAM9260_SDRAMC_CR_TRAS_MASK 0x07800000 +#define AT91SAM9260_SDRAMC_CR_TXSR_MASK 0x78000000 +#define AT91SAM9260_SDRAMC_HSR 0x0c +#define AT91SAM9260_SDRAMC_LPR 0x10 +#define AT91SAM9260_SDRAMC_IER 0x14 +#define AT91SAM9260_SDRAMC_IDR 0x18 +#define AT91SAM9260_SDRAMC_IMR 0x1c +#define AT91SAM9260_SDRAMC_ISR 0x20 +#define AT91SAM9260_SDRAMC_MDR 0x24 + +#endif /* AT91SAM9260REG_H_*/ + diff --git a/sys/arm/at91/at91sam9_machdep.c b/sys/arm/at91/at91sam9_machdep.c deleted file mode 100644 index c3e56133a68..00000000000 --- a/sys/arm/at91/at91sam9_machdep.c +++ /dev/null @@ -1,420 +0,0 @@ -/*- - * Copyright (c) 1994-1998 Mark Brinicombe. - * Copyright (c) 1994 Brini. - * All rights reserved. - * - * This code is derived from software written for Brini by Mark Brinicombe - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Brini. - * 4. The name of the company nor the name of the author may be used to - * endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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. - * - * RiscBSD kernel project - * - * machdep.c - * - * Machine dependant functions for kernel setup - * - * This file needs a lot of work. - * - * Created : 17/09/94 - */ - -#include "opt_msgbuf.h" - -#include -__FBSDID("$FreeBSD$"); - -#define _ARM32_BUS_DMA_PRIVATE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ -#define KERNEL_PT_KERN 1 -#define KERNEL_PT_KERN_NUM 22 -#define KERNEL_PT_AFKERNEL KERNEL_PT_KERN + KERNEL_PT_KERN_NUM /* L2 table for mapping after kernel */ -#define KERNEL_PT_AFKERNEL_NUM 5 - -/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */ -#define NUM_KERNEL_PTS (KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM) - -/* Define various stack sizes in pages */ -#define IRQ_STACK_SIZE 1 -#define ABT_STACK_SIZE 1 -#define UND_STACK_SIZE 1 - -extern u_int data_abort_handler_address; -extern u_int prefetch_abort_handler_address; -extern u_int undefined_handler_address; - -struct pv_addr kernel_pt_table[NUM_KERNEL_PTS]; - -extern void *_end; - -extern int *end; - -struct pcpu __pcpu; -struct pcpu *pcpup = &__pcpu; - -/* Physical and virtual addresses for some global pages */ - -vm_paddr_t phys_avail[10]; -vm_paddr_t dump_avail[4]; -vm_offset_t physical_pages; - -struct pv_addr systempage; -struct pv_addr msgbufpv; -struct pv_addr irqstack; -struct pv_addr undstack; -struct pv_addr abtstack; -struct pv_addr kernelstack; - -static void *boot_arg1; -static void *boot_arg2; - -static struct trapframe proc0_tf; - -/* Static device mappings. */ -static const struct pmap_devmap at91sam9_devmap[] = { - /* - * Map the on-board devices VA == PA so that we can access them - * with the MMU on or off. - */ - { - /* - * This at least maps the interrupt controller, the UART - * and the timer. Other devices should use newbus to - * map their memory anyway. - */ - 0xdff00000, - 0xfff00000, - 0x100000, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* - * We can't just map the OHCI registers VA == PA, because - * AT91RM92_OHCI_BASE belongs to the userland address space. - * We could just choose a different virtual address, but a better - * solution would probably be to just use pmap_mapdev() to allocate - * KVA, as we don't need the OHCI controller before the vm - * initialization is done. However, the AT91 resource allocation - * system doesn't know how to use pmap_mapdev() yet. - */ - { - /* - * Add the ohci controller, and anything else that might be - * on this chip select for a VA/PA mapping. - */ - AT91SAM9G20_OHCI_BASE, - AT91SAM9G20_OHCI_PA_BASE, - AT91SAM9G20_OHCI_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - { - AT91SAM9G20_NAND_BASE, - AT91SAM9G20_NAND_PA_BASE, - AT91SAM9G20_NAND_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - { - 0, - 0, - 0, - 0, - 0, - } -}; - -long -at91_ramsize(void) -{ -#if 0 - uint32_t *SDRAMC = (uint32_t *)(AT91SAM9G20_BASE + AT91SAM9G20_SDRAMC_BASE); - uint32_t cr, mr; - int banks, rows, cols, bw; - - cr = SDRAMC[AT91SAM9G20_SDRAMC_CR / 4]; - mr = SDRAMC[AT91SAM9G20_SDRAMC_MR / 4]; - bw = (mr & AT91SAM9G20_SDRAMC_MR_DBW_16) ? 1 : 2; - banks = (cr & AT91SAM9G20_SDRAMC_CR_NB_4) ? 2 : 1; - rows = ((cr & AT91SAM9G20_SDRAMC_CR_NR_MASK) >> 2) + 11; - cols = (cr & AT91SAM9G20_SDRAMC_CR_NC_MASK) + 8; - return (1 << (cols + rows + banks + bw)); -#endif - return 64*1024*1024; -} - -void * -initarm(void *arg, void *arg2) -{ - struct pv_addr kernel_l1pt; - struct pv_addr dpcpu; - int loop, i; - u_int l1pagetable; - vm_offset_t freemempos; - vm_offset_t afterkern; - uint32_t memsize; - vm_offset_t lastaddr; - - boot_arg1 = arg; - boot_arg2 = arg2; - - - set_cpufuncs(); - lastaddr = fake_preload_metadata(); - pcpu_init(pcpup, 0, sizeof(struct pcpu)); - PCPU_SET(curthread, &thread0); - - freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK; - /* Define a macro to simplify memory allocation */ -#define valloc_pages(var, np) \ - alloc_pages((var).pv_va, (np)); \ - (var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR); - -#define alloc_pages(var, np) \ - (var) = freemempos; \ - freemempos += (np * PAGE_SIZE); \ - memset((char *)(var), 0, ((np) * PAGE_SIZE)); - - while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) - freemempos += PAGE_SIZE; - valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); - for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { - if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { - valloc_pages(kernel_pt_table[loop], - L2_TABLE_SIZE / PAGE_SIZE); - } else { - kernel_pt_table[loop].pv_va = freemempos - - (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * - L2_TABLE_SIZE_REAL; - kernel_pt_table[loop].pv_pa = - kernel_pt_table[loop].pv_va - KERNVIRTADDR + - KERNPHYSADDR; - } - i++; - } - /* - * Allocate a page for the system page mapped to V0x00000000 - * This page will just contain the system vectors and can be - * shared by all processes. - */ - valloc_pages(systempage, 1); - - /* Allocate dynamic per-cpu area. */ - valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); - dpcpu_init((void *)dpcpu.pv_va, 0); - - /* Allocate stacks for all modes */ - valloc_pages(irqstack, IRQ_STACK_SIZE); - valloc_pages(abtstack, ABT_STACK_SIZE); - valloc_pages(undstack, UND_STACK_SIZE); - valloc_pages(kernelstack, KSTACK_PAGES); - valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE); - - /* - * Now we start construction of the L1 page table - * We start by mapping the L2 page tables into the L1. - * This means that we can replace L1 mappings later on if necessary - */ - l1pagetable = kernel_l1pt.pv_va; - - /* Map the L2 pages tables in the L1 page table */ - pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH, - &kernel_pt_table[KERNEL_PT_SYS]); - for (i = 0; i < KERNEL_PT_KERN_NUM; i++) - pmap_link_l2pt(l1pagetable, KERNBASE + i * L1_S_SIZE, - &kernel_pt_table[KERNEL_PT_KERN + i]); - pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR, - (((uint32_t)lastaddr - KERNBASE) + PAGE_SIZE) & ~(PAGE_SIZE - 1), - VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - afterkern = round_page((lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - 1)); - for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { - pmap_link_l2pt(l1pagetable, afterkern + i * L1_S_SIZE, - &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); - } - - /* Map the vector page. */ - pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, - VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - - /* Map the DPCPU pages */ - pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa, DPCPU_SIZE, - VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - - /* Map the stack pages */ - pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, - IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, - ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, - UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, - KSTACK_PAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - - pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, - L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); - pmap_map_chunk(l1pagetable, msgbufpv.pv_va, msgbufpv.pv_pa, - MSGBUF_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - - for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { - pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, - kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, - VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); - } - - pmap_devmap_bootstrap(l1pagetable, at91sam9_devmap); - cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); - setttb(kernel_l1pt.pv_pa); - cpu_tlb_flushID(); - cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); - cninit(); - memsize = board_init(); - physmem = memsize / PAGE_SIZE; - - /* - * Pages were allocated during the secondary bootstrap for the - * stacks for different CPU modes. - * We must now set the r13 registers in the different CPU modes to - * point to these stacks. - * Since the ARM stacks use STMFD etc. we must set r13 to the top end - * of the stack memory. - */ - cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE); - set_stackptr(PSR_IRQ32_MODE, - irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); - set_stackptr(PSR_ABT32_MODE, - abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); - set_stackptr(PSR_UND32_MODE, - undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); - - /* - * We must now clean the cache again.... - * Cleaning may be done by reading new data to displace any - * dirty data in the cache. This will have happened in setttb() - * but since we are boot strapping the addresses used for the read - * may have just been remapped and thus the cache could be out - * of sync. A re-clean after the switch will cure this. - * After booting there are no gross relocations of the kernel thus - * this problem will not occur after initarm(). - */ - cpu_idcache_wbinv_all(); - - /* Set stack for exception handlers */ - - data_abort_handler_address = (u_int)data_abort_handler; - prefetch_abort_handler_address = (u_int)prefetch_abort_handler; - undefined_handler_address = (u_int)undefinedinstruction_bounce; - undefined_init(); - - proc_linkup0(&proc0, &thread0); - thread0.td_kstack = kernelstack.pv_va; - thread0.td_pcb = (struct pcb *) - (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; - thread0.td_pcb->pcb_flags = 0; - thread0.td_frame = &proc0_tf; - pcpup->pc_curpcb = thread0.td_pcb; - - arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); - - pmap_curmaxkvaddr = afterkern + L1_S_SIZE * (KERNEL_PT_KERN_NUM - 1); - - /* - * ARM_USE_SMALL_ALLOC uses dump_avail, so it must be filled before - * calling pmap_bootstrap. - */ - dump_avail[0] = PHYSADDR; - dump_avail[1] = PHYSADDR + memsize; - dump_avail[2] = 0; - dump_avail[3] = 0; - - pmap_bootstrap(freemempos, - KERNVIRTADDR + 3 * memsize, - &kernel_l1pt); - msgbufp = (void*)msgbufpv.pv_va; - msgbufinit(msgbufp, MSGBUF_SIZE); - mutex_init(); - - i = 0; -#if PHYSADDR != KERNPHYSADDR - phys_avail[i++] = PHYSADDR; - phys_avail[i++] = KERNPHYSADDR; -#endif - phys_avail[i++] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR; - phys_avail[i++] = PHYSADDR + memsize; - phys_avail[i++] = 0; - phys_avail[i++] = 0; - /* Do basic tuning, hz etc */ - init_param1(); - init_param2(physmem); - kdb_init(); - return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - - sizeof(struct pcb))); -} diff --git a/sys/arm/at91/at91sam9g20.c b/sys/arm/at91/at91sam9g20.c new file mode 100644 index 00000000000..61d9ac4e609 --- /dev/null +++ b/sys/arm/at91/at91sam9g20.c @@ -0,0 +1,343 @@ +/*- + * Copyright (c) 2005 Olivier Houchard. All rights reserved. + * Copyright (c) 2010 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#define _ARM32_BUS_DMA_PRIVATE +#include + +#include +#include +#include +#include +#include + +struct at91sam9_softc { + device_t dev; + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + bus_space_handle_t sc_sys_sh; + bus_space_handle_t sc_aic_sh; + bus_space_handle_t sc_dbg_sh; + bus_space_handle_t sc_matrix_sh; +}; + +/* + * Standard priority levels for the system. 0 is lowest and 7 is highest. + * These values are the ones Atmel uses for its Linux port + */ +static const int at91_irq_prio[32] = +{ + 7, /* Advanced Interrupt Controller */ + 7, /* System Peripherals */ + 1, /* Parallel IO Controller A */ + 1, /* Parallel IO Controller B */ + 1, /* Parallel IO Controller C */ + 0, /* Analog-to-Digital Converter */ + 5, /* USART 0 */ + 5, /* USART 1 */ + 5, /* USART 2 */ + 0, /* Multimedia Card Interface */ + 2, /* USB Device Port */ + 6, /* Two-Wire Interface */ + 5, /* Serial Peripheral Interface 0 */ + 5, /* Serial Peripheral Interface 1 */ + 5, /* Serial Synchronous Controller */ + 0, /* (reserved) */ + 0, /* (reserved) */ + 0, /* Timer Counter 0 */ + 0, /* Timer Counter 1 */ + 0, /* Timer Counter 2 */ + 2, /* USB Host port */ + 3, /* Ethernet */ + 0, /* Image Sensor Interface */ + 5, /* USART 3 */ + 5, /* USART 4 */ + 5, /* USART 5 */ + 0, /* Timer Counter 3 */ + 0, /* Timer Counter 4 */ + 0, /* Timer Counter 5 */ + 0, /* Advanced Interrupt Controller IRQ0 */ + 0, /* Advanced Interrupt Controller IRQ1 */ + 0, /* Advanced Interrupt Controller IRQ2 */ +}; + +#define DEVICE(_name, _id, _unit) \ + { \ + _name, _unit, \ + AT91SAM9G20_ ## _id ##_BASE, \ + AT91SAM9G20_ ## _id ## _SIZE, \ + AT91SAM9G20_IRQ_ ## _id \ + } + +static const struct cpu_devs at91_devs[] = +{ + DEVICE("at91_pmc", PMC, 0), + DEVICE("at91_wdt", WDT, 0), + DEVICE("at91_rst", RSTC, 0), + DEVICE("at91_pit", PIT, 0), + DEVICE("at91_pio", PIOA, 0), + DEVICE("at91_pio", PIOB, 1), + DEVICE("at91_pio", PIOC, 2), + DEVICE("at91_twi", TWI, 0), + DEVICE("at91_mci", MCI, 0), + DEVICE("uart", DBGU, 0), + DEVICE("uart", USART0, 1), + DEVICE("uart", USART1, 2), + DEVICE("uart", USART2, 3), + DEVICE("uart", USART3, 4), + DEVICE("uart", USART4, 5), + DEVICE("uart", USART5, 6), + DEVICE("spi", SPI0, 0), + DEVICE("spi", SPI1, 1), + DEVICE("ate", EMAC, 0), + DEVICE("macb", EMAC, 0), + DEVICE("nand", NAND, 0), + DEVICE("ohci", OHCI, 0), + { 0, 0, 0, 0, 0 } +}; + +static void +at91_add_child(device_t dev, int prio, const char *name, int unit, + bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) +{ + device_t kid; + struct at91_ivar *ivar; + + kid = device_add_child_ordered(dev, prio, name, unit); + if (kid == NULL) { + printf("Can't add child %s%d ordered\n", name, unit); + return; + } + ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ivar == NULL) { + device_delete_child(dev, kid); + printf("Can't add alloc ivar\n"); + return; + } + device_set_ivars(kid, ivar); + resource_list_init(&ivar->resources); + if (irq0 != -1) { + bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); + if (irq0 != AT91SAM9G20_IRQ_SYSTEM) + at91_pmc_clock_add(device_get_nameunit(kid), irq0, 0); + } + if (irq1 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); + if (irq2 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); + if (addr != 0 && addr < AT91SAM9G20_BASE) + addr += AT91SAM9G20_BASE; + if (addr != 0) + bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); +} + +static void +at91_cpu_add_builtin_children(device_t dev) +{ + int i; + const struct cpu_devs *walker; + + for (i = 1, walker = at91_devs; walker->name; i++, walker++) { + at91_add_child(dev, i, walker->name, walker->unit, + walker->mem_base, walker->mem_len, walker->irq0, + walker->irq1, walker->irq2); + } +} + +static uint32_t +at91_pll_outa(int freq) +{ + + switch (freq / 10000000) { + case 747 ... 801: return ((1 << 29) | (0 << 14)); + case 697 ... 746: return ((1 << 29) | (1 << 14)); + case 647 ... 696: return ((1 << 29) | (2 << 14)); + case 597 ... 646: return ((1 << 29) | (3 << 14)); + case 547 ... 596: return ((1 << 29) | (1 << 14)); + case 497 ... 546: return ((1 << 29) | (2 << 14)); + case 447 ... 496: return ((1 << 29) | (3 << 14)); + case 397 ... 446: return ((1 << 29) | (4 << 14)); + default: return (1 << 29); + } +} + +static uint32_t +at91_pll_outb(int freq) +{ + + return (0); +} + +static void +at91_identify(driver_t *drv, device_t parent) +{ + + if (at91_cpu_is(AT91_CPU_SAM9G20)) { + at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0); + at91_cpu_add_builtin_children(parent); + } +} + +static int +at91_probe(device_t dev) +{ + + if (at91_cpu_is(AT91_CPU_SAM9G20)) { + device_set_desc(dev, "AT91SAM9G20"); + return (0); + } + return (ENXIO); +} + +static int +at91_attach(device_t dev) +{ + struct at91_pmc_clock *clk; + struct at91sam9_softc *sc = device_get_softc(dev); + int i; + + struct at91_softc *at91sc = device_get_softc(device_get_parent(dev)); + + sc->sc_st = at91sc->sc_st; + sc->sc_sh = at91sc->sc_sh; + sc->dev = dev; + + /* + * XXX These values work for the RM9200, SAM926[01], and SAM9G20 + * will have to fix this when we want to support anything else. XXX + */ + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE, + AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0) + panic("Enable to map system registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_DBGU_BASE, + AT91SAM9G20_DBGU_SIZE, &sc->sc_dbg_sh) != 0) + panic("Enable to map DBGU registers"); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_AIC_BASE, + AT91SAM9G20_AIC_SIZE, &sc->sc_aic_sh) != 0) + panic("Enable to map system registers"); + + /* XXX Hack to tell atmelarm about the AIC */ + at91sc->sc_aic_sh = sc->sc_aic_sh; + at91sc->sc_irq_system = AT91SAM9G20_IRQ_SYSTEM; + + for (i = 0; i < 32; i++) { + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR + + i * 4, i); + /* Priority. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4, + at91_irq_prio[i]); + if (i < 8) + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR, + 1); + } + + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32); + /* No debug. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0); + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff); + bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff); + + /* Disable all interrupts for DBGU */ + bus_space_write_4(sc->sc_st, sc->sc_dbg_sh, 0x0c, 0xffffffff); + + if (bus_space_subregion(sc->sc_st, sc->sc_sh, + AT91SAM9G20_MATRIX_BASE, AT91SAM9G20_MATRIX_SIZE, + &sc->sc_matrix_sh) != 0) + panic("Enable to map matrix registers"); + + /* activate NAND*/ + i = bus_space_read_4(sc->sc_st, sc->sc_matrix_sh, + AT91SAM9G20_EBICSA); + bus_space_write_4(sc->sc_st, sc->sc_matrix_sh, + AT91SAM9G20_EBICSA, + i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); + + + /* Update USB device port clock info */ + clk = at91_pmc_clock_ref("udpck"); + clk->pmc_mask = PMC_SCER_UDP_SAM9; + at91_pmc_clock_deref(clk); + + /* Update USB host port clock info */ + clk = at91_pmc_clock_ref("uhpck"); + clk->pmc_mask = PMC_SCER_UHP_SAM9; + at91_pmc_clock_deref(clk); + + /* Each SOC has different PLL contraints */ + clk = at91_pmc_clock_ref("plla"); + clk->pll_min_in = SAM9G20_PLL_A_MIN_IN_FREQ; /* 2 MHz */ + clk->pll_max_in = SAM9G20_PLL_A_MAX_IN_FREQ; /* 32 MHz */ + clk->pll_min_out = SAM9G20_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ + clk->pll_max_out = SAM9G20_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ + clk->pll_mul_shift = SAM9G20_PLL_A_MUL_SHIFT; + clk->pll_mul_mask = SAM9G20_PLL_A_MUL_MASK; + clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT; + clk->pll_div_mask = SAM9G20_PLL_A_DIV_MASK; + clk->set_outb = at91_pll_outa; + at91_pmc_clock_deref(clk); + + clk = at91_pmc_clock_ref("pllb"); + clk->pll_min_in = SAM9G20_PLL_B_MIN_IN_FREQ; /* 2 MHz */ + clk->pll_max_in = SAM9G20_PLL_B_MAX_IN_FREQ; /* 32 MHz */ + clk->pll_min_out = SAM9G20_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ + clk->pll_max_out = SAM9G20_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ + clk->pll_mul_shift = SAM9G20_PLL_B_MUL_SHIFT; + clk->pll_mul_mask = SAM9G20_PLL_B_MUL_MASK; + clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT; + clk->pll_div_mask = SAM9G20_PLL_B_DIV_MASK; + clk->set_outb = at91_pll_outb; + at91_pmc_clock_deref(clk); + return (0); +} + +static device_method_t at91_methods[] = { + DEVMETHOD(device_probe, at91_probe), + DEVMETHOD(device_attach, at91_attach), + DEVMETHOD(device_identify, at91_identify), + {0, 0}, +}; + +static driver_t at91sam9_driver = { + "at91sam", + at91_methods, + sizeof(struct at91sam9_softc), +}; + +static devclass_t at91sam9_devclass; + +DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0); diff --git a/sys/arm/at91/at91sam9g20reg.h b/sys/arm/at91/at91sam9g20reg.h index 9194b112ad3..71683e91c46 100644 --- a/sys/arm/at91/at91sam9g20reg.h +++ b/sys/arm/at91/at91sam9g20reg.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. + * Copyright (c) 2010 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,6 +29,29 @@ #ifndef AT91SAM9G20REG_H_ #define AT91SAM9G20REG_H_ +#ifndef AT91SAM9G20_MASTER_CLOCK +#define AT91SAM9G20_MASTER_CLOCK ((18432000 * 43)/6) +#endif + +/* Chip Specific limits */ +#define SAM9G20_PLL_A_MIN_IN_FREQ 2000000 /* 2 Mhz */ +#define SAM9G20_PLL_A_MAX_IN_FREQ 32000000 /* 32 Mhz */ +#define SAM9G20_PLL_A_MIN_OUT_FREQ 400000000 /* 400 Mhz */ +#define SAM9G20_PLL_A_MAX_OUT_FREQ 800000000 /* 800 Mhz */ +#define SAM9G20_PLL_A_MUL_SHIFT 16 +#define SAM9G20_PLL_A_MUL_MASK 0xFF +#define SAM9G20_PLL_A_DIV_SHIFT 0 +#define SAM9G20_PLL_A_DIV_MASK 0xFF + +#define SAM9G20_PLL_B_MIN_IN_FREQ 2000000 /* 2 Mhz */ +#define SAM9G20_PLL_B_MAX_IN_FREQ 32000000 /* 32 Mhz */ +#define SAM9G20_PLL_B_MIN_OUT_FREQ 30000000 /* 30 Mhz */ +#define SAM9G20_PLL_B_MAX_OUT_FREQ 100000000 /* 100 Mhz */ +#define SAM9G20_PLL_B_MUL_SHIFT 16 +#define SAM9G20_PLL_B_MUL_MASK 0x3F +#define SAM9G20_PLL_B_DIV_SHIFT 0 +#define SAM9G20_PLL_B_DIV_MASK 0xFF + /* * Memory map, from datasheet : * 0x00000000 - 0x0ffffffff : Internal Memories @@ -56,11 +80,11 @@ #define AT91SAM9G20_BASE 0xd0000000 -#define AT91SAM9G20_IRQ_EMAC 21 #define AT91SAM9G20_EMAC_BASE 0xffc4000 #define AT91SAM9G20_EMAC_SIZE 0x4000 #define AT91SAM9G20_RSTC_BASE 0xffffd00 +#define AT91SAM9G20_RSTC_SIZE 0x10 #define RSTC_CR 0 #define RSTC_PROCRST (1 << 0) @@ -69,13 +93,25 @@ /* USART*/ +#define AT91SAM9G20_USART_SIZE 0x4000 #define AT91SAM9G20_USART0_BASE 0xffb0000 #define AT91SAM9G20_USART0_PDC 0xffb0100 +#define AT91SAM9G20_USART0_SIZE AT91SAM9G20_USART_SIZE #define AT91SAM9G20_USART1_BASE 0xffb4000 #define AT91SAM9G20_USART1_PDC 0xffb4100 +#define AT91SAM9G20_USART1_SIZE AT91SAM9G20_USART_SIZE #define AT91SAM9G20_USART2_BASE 0xffb8000 #define AT91SAM9G20_USART2_PDC 0xffb8100 -#define AT91SAM9G20_USART_SIZE 0x4000 +#define AT91SAM9G20_USART2_SIZE AT91SAM9G20_USART_SIZE +#define AT91SAM9G20_USART3_BASE 0xffd0000 +#define AT91SAM9G20_USART3_PDC 0xffd0100 +#define AT91SAM9G20_USART3_SIZE AT91SAM9G20_USART_SIZE +#define AT91SAM9G20_USART4_BASE 0xffd4000 +#define AT91SAM9G20_USART4_PDC 0xffd4100 +#define AT91SAM9G20_USART4_SIZE AT91SAM9G20_USART_SIZE +#define AT91SAM9G20_USART5_BASE 0xffd8000 +#define AT91SAM9G20_USART5_PDC 0xffd8100 +#define AT91SAM9G20_USART5_SIZE AT91SAM9G20_USART_SIZE /*TC*/ #define AT91SAM9G20_TC0_BASE 0xffa0000 @@ -99,28 +135,27 @@ #define AT91SAM9G20_IRQ_SPI1 13 /* System Registers */ -#define AT91SAM9G20_SYS_BASE 0xfffe000 -#define AT91SAM9G20_SYS_SIZE 0x2000 +#define AT91SAM9G20_SYS_BASE 0xffff000 +#define AT91SAM9G20_SYS_SIZE 0x1000 -#define AT91SAM9G20_MATRIX (0xe00) - -#define AT91SAM9G20_EBICSA (AT91SAM9G20_MATRIX + 0x011C) +#define AT91SAM9G20_MATRIX_BASE 0xfffee00 +#define AT91SAM9G20_MATRIX_SIZE 0x1000 +#define AT91SAM9G20_EBICSA 0x011C #define AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA (1 << 3) -#define DBGU 0x200 -#define DBGU_SIZE 0x200 -#define DBGU_C1R (0x200 + 64) /* Chip ID1 Register */ -#define DBGU_C2R (0x200 + 68) /* Chip ID2 Register */ -#define DBGU_FNTR (0x200 + 72) /* Force NTRST Register */ +#define AT91SAM9G20_DBGU_BASE 0xffff200 +#define AT91SAM9G20_DBGU_SIZE 0x200 /* * PIO */ #define AT91SAM9G20_PIOA_BASE 0xffff400 -#define AT91SAM9G20_PIO_SIZE 0x200 +#define AT91SAM9G20_PIOA_SIZE 0x200 #define AT91SAM9G20_PIOB_BASE 0xffff600 +#define AT91SAM9G20_PIOB_SIZE 0x200 #define AT91SAM9G20_PIOC_BASE 0xffff800 +#define AT91SAM9G20_PIOC_SIZE 0x200 #define AT91RM92_PMC_BASE 0xffffc00 #define AT91RM92_PMC_SIZE 0x100 @@ -131,27 +166,33 @@ * 2: PIO Controller A * 3: PIO Controller B * 4: PIO Controller C - * 5: - + * 5: ADC * 6: USART 0 * 7: USART 1 * 8: USART 2 * 9: MMC Interface * 10: USB device port * 11: Two-wirte interface - * 12: SPI - * 13: SPI + * 12: SPI 0 + * 13: SPI 1 * 14: SSC - * 15: SSC - * 16: SSC + * 15: - (reserved) + * 16: - (reserved) * 17: Timer Counter 0 * 18: Timer Counter 1 * 19: Timer Counter 2 * 20: USB Host port * 21: EMAC - * 22-28: - - * 29: AIC - * 30: AIC - * 31: AIC + * 22: ISI + * 23: USART 3 + * 24: USART 4 + * 25: USART 2 + * 26: Timer Counter 3 + * 27: Timer Counter 4 + * 28: Timer Counter 5 + * 29: AIC IRQ0 + * 30: AIC IRQ1 + * 31: AIC IRQ2 */ #define AT91SAM9G20_IRQ_SYSTEM 1 @@ -173,12 +214,25 @@ #define AT91SAM9G20_IRQ_TC1 18 #define AT91SAM9G20_IRQ_TC2 19 #define AT91SAM9G20_IRQ_UHP 20 +#define AT91SAM9G20_IRQ_EMAC 21 +#define AT91SAM9G20_IRQ_USART3 23 +#define AT91SAM9G20_IRQ_USART4 24 +#define AT91SAM9G20_IRQ_USART5 25 #define AT91SAM9G20_IRQ_AICBASE 29 -/* Timer */ +/* Alias */ +#define AT91SAM9G20_IRQ_DBGU AT91SAM9G20_IRQ_SYSTEM +#define AT91SAM9G20_IRQ_PMC AT91SAM9G20_IRQ_SYSTEM +#define AT91SAM9G20_IRQ_WDT AT91SAM9G20_IRQ_SYSTEM +#define AT91SAM9G20_IRQ_PIT AT91SAM9G20_IRQ_SYSTEM +#define AT91SAM9G20_IRQ_RSTC AT91SAM9G20_IRQ_SYSTEM +#define AT91SAM9G20_IRQ_OHCI AT91SAM9G20_IRQ_UHP +#define AT91SAM9G20_IRQ_NAND (-1) -#define AT91SAM9G20_DBGU_BASE 0xffff200 -#define AT91SAM9G20_DBGU_SIZE 0x200 +#define AT91SAM9G20_AIC_BASE 0xffff000 +#define AT91SAM9G20_AIC_SIZE 0x200 + +/* Timer */ #define AT91SAM9G20_WDT_BASE 0xffffd40 #define AT91SAM9G20_WDT_SIZE 0x10 @@ -195,22 +249,24 @@ #define AT91SAM9G20_UDP_BASE 0xffa4000 #define AT91SAM9G20_UDP_SIZE 0x4000 -#define AT91SAM9G20_OHCI_BASE 0xdfe00000 -#define AT91SAM9G20_OHCI_PA_BASE 0x00500000 -#define AT91SAM9G20_OHCI_SIZE 0x00100000 +#define AT91SAM9G20_MCI_BASE 0xffa8000 +#define AT91SAM9G20_MCI_SIZE 0x4000 +#define AT91SAM9G20_TWI_BASE 0xffaC000 +#define AT91SAM9G20_TWI_SIZE 0x4000 -//#define AT91SAM9G20_NAND_BASE 0xdf100000 +/* XXX Needs to be carfully coordinated with + * other * soc's so phyical and vm address + * mapping are unique. XXX + */ +#define AT91SAM9G20_OHCI_BASE 0xdfc00000 +#define AT91SAM9G20_OHCI_PA_BASE 0x00500000 +#define AT91SAM9G20_OHCI_SIZE 0x00100000 -//#define AT91SAM9G20_NAND_BASE 0x40000000 +#define AT91SAM9G20_NAND_BASE 0xe0000000 +#define AT91SAM9G20_NAND_PA_BASE 0x40000000 +#define AT91SAM9G20_NAND_SIZE 0x10000000 -#define AT91SAM9G20_NAND_BASE 0xe0000000 - -#define AT91SAM9G20_NAND_PA_BASE 0x40000000 -#define AT91SAM9G20_NAND_SIZE 0x10000000 -//#define AT91SAM9G20_NAND_SIZE 0x00900000 - -//#define AT91SAM9G20_OHCI_SIZE 0x0004000 /* SDRAMC */ #define AT91SAM9G20_SDRAMC_BASE 0xfffea00 @@ -234,6 +290,7 @@ #define AT91SAM9G20_SDRAMC_CR_NR_MASK 0x0000000c #define AT91SAM9G20_SDRAMC_CR_NB_2 0x00 #define AT91SAM9G20_SDRAMC_CR_NB_4 0x10 +#define AT91SAM9G20_SDRAMC_CR_DBW_16 0x80 #define AT91SAM9G20_SDRAMC_CR_NB_MASK 0x00000010 #define AT91SAM9G20_SDRAMC_CR_NCAS_MASK 0x00000060 #define AT91SAM9G20_SDRAMC_CR_TWR_MASK 0x00000780 diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h index 3f82dd76392..94e759a79a8 100644 --- a/sys/arm/at91/at91var.h +++ b/sys/arm/at91/at91var.h @@ -28,21 +28,62 @@ #ifndef _AT91VAR_H_ #define _AT91VAR_H_ +#include #include +#include + struct at91_softc { device_t dev; bus_space_tag_t sc_st; bus_space_handle_t sc_sh; - bus_space_handle_t sc_sys_sh; + bus_space_handle_t sc_aic_sh; struct rman sc_irq_rman; struct rman sc_mem_rman; + uint32_t sc_irq_system; }; struct at91_ivar { struct resource_list resources; }; +struct cpu_devs +{ + const char *name; + int unit; + bus_addr_t mem_base; + bus_size_t mem_len; + int irq0; + int irq1; + int irq2; + const char *parent_clk; +}; + +extern uint32_t at91_chip_id; + +static inline int at91_is_rm92(void); +static inline int at91_is_sam9(void) ; +static inline int at91_cpu_is(u_int cpu); + +static inline int +at91_is_rm92(void) +{ + return (AT91_ARCH(at91_chip_id) == AT91_ARCH_RM92); +} + +static inline int +at91_is_sam9(void) +{ + return (AT91_ARCH(at91_chip_id) == AT91_ARCH_SAM9); +} + +static inline int +at91_cpu_is(u_int cpu) +{ + return (AT91_CPU(at91_chip_id) == cpu); +} + +extern uint32_t at91_irq_system; extern uint32_t at91_master_clock; #endif /* _AT91VAR_H_ */ diff --git a/sys/arm/at91/board_hl201.c b/sys/arm/at91/board_hl201.c index b4a0b59f3c8..f4497ec4b2b 100644 --- a/sys/arm/at91/board_hl201.c +++ b/sys/arm/at91/board_hl201.c @@ -32,11 +32,36 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include long board_init(void) { + /* Setup Ethernet Pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, 1<<7, 0); + + at91_pio_gpio_input(AT91SAM9G20_PIOA_BASE, 1<<7); + at91_pio_gpio_set_deglitch(AT91SAM9G20_PIOA_BASE, 1<<7, 1); + + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA19, 0); /* ETXCK_EREFCK */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA17, 0); /* ERXDV */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA14, 0); /* ERX0 */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA15, 0); /* ERX1 */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA18, 0); /* ERXER */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA16, 0); /* ETXEN */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA12, 0); /* ETX0 */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA13, 0); /* ETX1 */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA21, 0); /* EMDIO */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA20, 0); /* EMDC */ + + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA28, 0); /* ECRS */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA29, 0); /* ECOL */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA25, 0); /* ERX2 */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA26, 0); /* ERX3 */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA27, 0); /* ERXCK */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA23, 0); /* ETX2 */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA24, 0); /* ETX3 */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA22, 0); /* ETXER */ return (at91_ramsize()); } diff --git a/sys/arm/at91/board_kb920x.c b/sys/arm/at91/board_kb920x.c index f1a24394f54..e79879d6d66 100644 --- a/sys/arm/at91/board_kb920x.c +++ b/sys/arm/at91/board_kb920x.c @@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -59,5 +60,13 @@ board_init(void) at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PB21_RXD1, 0); at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PB20_TXD1, 1); + /* MMC/SD Interface */ + at91_pio_use_periph_a(AT91RM92_PIOA_BASE,AT91C_PA27_MCCK, 0); + at91_pio_use_periph_a(AT91RM92_PIOA_BASE,AT91C_PA28_MCCDA, 1); + at91_pio_use_periph_a(AT91RM92_PIOA_BASE,AT91C_PA29_MCDA0, 1); + at91_pio_use_periph_b(AT91RM92_PIOB_BASE,AT91C_PB3_MCDA1, 1); + at91_pio_use_periph_b(AT91RM92_PIOB_BASE,AT91C_PB4_MCDA2, 1); + at91_pio_use_periph_b(AT91RM92_PIOB_BASE,AT91C_PB5_MCDA3, 1); + return (at91_ramsize()); } diff --git a/sys/arm/at91/board_qila9g20.c b/sys/arm/at91/board_qila9g20.c new file mode 100644 index 00000000000..eee7d89dc27 --- /dev/null +++ b/sys/arm/at91/board_qila9g20.c @@ -0,0 +1,105 @@ +/*- + * Copyright (c) 2009 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Calao Systems QIL-9G20-Cxx + * http://www.calao-systems.com + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include + +#include +#include +#include +#include +#include +#include +//#include + +#define AT91SAM9G20_LED_BASE AT91SAM9G20_PIOA_BASE +#define AT91SAM9G20_LED_SIZE AT91SAM9G20_PIO_SIZE +#define AT91SAM9G20_IRQ_LED AT91SAM9G20_IRQ_PIOA + +long +board_init(void) +{ + + //at91_led_create("power", 0, 9, 0); + + /* PIOB's A periph: Turn USART 0's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB14_DRXD, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB15_DTXD, 1); + + /* PIOB's A periph: Turn USART 0's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB4_TXD0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB5_RXD0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB22_DSR0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB23_DCD0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB24_DTR0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB25_RI0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB26_RTS0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB27_CTS0, 0); + + /* PIOB's A periph: Turn USART 1's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB6_TXD1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB7_RXD1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB28_RTS1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB29_CTS1, 0); + + /* TWI Two-wire Serial Data */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA23_TWD, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA24_TWCK, 1); + + /* Multimedia Card */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA6_MCDA0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA7_MCCDA, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA8_MCCK, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA9_MCDA1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA10_MCDA2, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA11_MCDA3, 1); + + /* SPI0 to DataFlash */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PA0_SPI0_MISO, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PA1_SPI0_MOSI, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PA2_SPI0_SPCK, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PA3_SPI0_NPCS0, 0); + + /* EMAC */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA19_ETXCK, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA21_EMDIO, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA20_EMDC, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA17_ERXDV, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA16_ETXEN, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA12_ETX0 , 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA13_ETX1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA14_ERX0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA15_ERX1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA18_ERXER, 0); + + + return (at91_ramsize()); +} diff --git a/sys/arm/at91/board_sam9g20ek.c b/sys/arm/at91/board_sam9g20ek.c new file mode 100644 index 00000000000..a79a509e845 --- /dev/null +++ b/sys/arm/at91/board_sam9g20ek.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2009 Greg Ansley. 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This board file can be used for both: + * Atmel AT91SAM9260-B Development Card and + * Atmel AT91SAM9G20-EK Rev. B Development Card + * + * Since the AT91SAM9260 and AT91SAM9G20 have identical memory maps and + * pin configurations we can use the same file for both. + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include + +#include +#include +#include +#include +#include +#include +//#include + +long +board_init(void) +{ + /* PIOB's A periph: Turn USART 0's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB14_DRXD, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB15_DTXD, 1); + + /* PIOB's A periph: Turn USART 0's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB4_TXD0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB5_RXD0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB22_DSR0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB23_DCD0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB24_DTR0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB25_RI0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB26_RTS0, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB27_CTS0, 0); + + /* PIOB's A periph: Turn USART 1's TX/RX pins */ + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB6_TXD1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB7_RXD1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB28_RTS1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOB_BASE, AT91C_PB29_CTS1, 0); + + /* TWI Two-wire Serial Data */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA23_TWD, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA24_TWCK, 1); + +#if 1 + /* + * Turn off Clock to DataFlash, conflicts with MCI clock. + */ + at91_pio_use_gpio(AT91SAM9G20_PIOA_BASE,AT91C_PIO_PA2); + at91_pio_gpio_input(AT91SAM9G20_PIOA_BASE,AT91C_PIO_PA2); + + /* Turn off chip select to DataFlash */ + at91_pio_gpio_output(AT91SAM9G20_PIOC_BASE,AT91C_PIO_PC11, 0); + at91_pio_gpio_set(AT91SAM9G20_PIOC_BASE,AT91C_PIO_PC11); + at91_pio_use_gpio(AT91SAM9G20_PIOC_BASE,AT91C_PIO_PC11); + + /* Multimedia Card */ + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA0_MCDB0, 1); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA1_MCCDB, 1); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA3_MCDB3, 1); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA4_MCDB2, 1); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA5_MCDB1, 1); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA8_MCCK, 1); + at91_pio_use_gpio(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC9); +#else + /* SPI0 to DataFlash */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA2, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC11,0); + + at91_pio_gpio_input(AT91SAM9G20_PIOA_BASE,AT91C_PIO_PA8); + at91_pio_use_gpio(AT91SAM9G20_PIOA_BASE,AT91C_PIO_PA8); +#endif + + /* EMAC */ + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA12_ETX0 , 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA13_ETX1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA14_ERX0, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA15_ERX1, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA16_ETXEN, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA17_ERXDV, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA18_ERXER, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA19_ETXCK, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA20_EMDC, 0); + at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE,AT91C_PA21_EMDIO, 0); + + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA10_ETX2_0, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA11_ETX3_0, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA22_ETXER, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA25_ERX2, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA26_ERX3, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA27_ERXCK, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA28_ECRS, 0); + at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE,AT91C_PA29_ECOL, 0); + + return (at91_ramsize()); +} diff --git a/sys/arm/at91/files.at91 b/sys/arm/at91/files.at91 index 8b5d7e295c5..4aa0b0ce412 100644 --- a/sys/arm/at91/files.at91 +++ b/sys/arm/at91/files.at91 @@ -4,14 +4,15 @@ arm/arm/irq_dispatch.S standard arm/at91/at91_machdep.c standard arm/at91/at91.c standard arm/at91/at91_cfata.c optional at91_cfata -arm/at91/at91_st.c standard arm/at91/at91_mci.c optional at91_mci +arm/at91/at91_nand.c optional nand arm/at91/at91_pio.c standard arm/at91/at91_pmc.c standard arm/at91/at91_rtc.c optional at91_rtc -arm/at91/at91_ssc.c optional at91_ssc arm/at91/at91_spi.c optional at91_spi \ dependency "spibus_if.h" +arm/at91/at91_ssc.c optional at91_ssc +arm/at91/at91_st.c standard arm/at91/at91_tc.c optional at91_tc arm/at91/at91_twi.c optional at91_twi arm/at91/if_ate.c optional ate @@ -19,6 +20,10 @@ arm/at91/uart_bus_at91usart.c optional uart arm/at91/uart_cpu_at91rm9200usart.c optional uart arm/at91/uart_dev_at91usart.c optional uart # +# All the "systems on a chip" we support +# +arm/at91/at91rm9200.c standard +# # All the boards we support # arm/at91/board_bwct.c optional at91_board_bwct diff --git a/sys/arm/at91/files.at91sam9 b/sys/arm/at91/files.at91sam9 index fb61cb6e652..21fae6bf171 100644 --- a/sys/arm/at91/files.at91sam9 +++ b/sys/arm/at91/files.at91sam9 @@ -1,27 +1,36 @@ # $FreeBSD$ arm/arm/cpufunc_asm_arm9.S standard arm/arm/irq_dispatch.S standard -arm/at91/at91sam9_machdep.c standard -arm/at91/at91sam9.c standard -arm/at91/at91_cfata.c optional at91_cfata -#arm/at91/at91_pit.c standard +arm/at91/at91_machdep.c standard +arm/at91/at91.c standard arm/at91/at91_mci.c optional at91_mci arm/at91/at91_nand.c optional nand arm/at91/at91_pio.c standard arm/at91/at91_pmc.c standard arm/at91/at91_pit.c standard -arm/at91/at91_rtc.c optional at91_rtc -arm/at91/at91_ssc.c optional at91_ssc +arm/at91/at91_reset.S standard +arm/at91/at91_rst.c standard arm/at91/at91_spi.c optional at91_spi \ dependency "spibus_if.h" +arm/at91/at91_ssc.c optional at91_ssc arm/at91/at91_tc.c optional at91_tc arm/at91/at91_twi.c optional at91_twi +arm/at91/at91_wdt.c optional at91_wdt +arm/at91/if_ate.c optional ate arm/at91/if_macb.c optional macb arm/at91/uart_bus_at91usart.c optional uart arm/at91/uart_cpu_at91rm9200usart.c optional uart arm/at91/uart_dev_at91usart.c optional uart +dev/usb/controller/ohci_atmelarm.c optional ohci +# +# All the "systems on a chip" we support +# +arm/at91/at91sam9g20.c optional at91sam9g20 +arm/at91/at91sam9260.c optional at91sam9260 +# # # All the boards we support # arm/at91/board_hl201.c optional at91_board_hl201 -dev/usb/controller/ohci_atmelarm.c optional ohci +arm/at91/board_sam9g20ek.c optional at91_board_sam9g20ek +arm/at91/board_qila9g20.c optional at91_board_qila9g20 diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c index b0654823470..ddf27614ae5 100644 --- a/sys/arm/at91/if_ate.c +++ b/sys/arm/at91/if_ate.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2009 Greg Ansley. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,13 +37,14 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include +#include #include #include #include #include #include + #include #include @@ -65,44 +67,91 @@ __FBSDID("$FreeBSD$"); #include #include + +#include "opt_at91.h" +#include +#include #include #include "miibus_if.h" -#define ATE_MAX_TX_BUFFERS 2 /* We have ping-pong tx buffers */ -#define ATE_MAX_RX_BUFFERS 64 - /* * Driver-specific flags. */ -#define ATE_FLAG_MULTICAST 0x01 +#define ATE_FLAG_DETACHING 0x01 +#define ATE_FLAG_MULTICAST 0x02 + +/* + * Old EMAC assumes whole packet fits in one buffer; + * new EBACB assumes all receive buffers are 128 bytes + */ +#define RX_BUF_SIZE(sc) (sc->is_emacb ? 128 : MCLBYTES) + +/* + * EMACB has an 11 bit counter for Rx/Tx Descriptors + * for max total of 1024 decriptors each. + */ +#define ATE_MAX_RX_DESCR 1024 +#define ATE_MAX_TX_DESCR 1024 + +/* How many buffers to allocate */ +#define ATE_MAX_TX_BUFFERS 4 /* We have ping-pong tx buffers */ + +/* How much memory to use for rx buffers */ +#define ATE_RX_MEMORY (ATE_MAX_RX_DESCR * 128) + +/* Actual number of descriptors we allocate */ +#define ATE_NUM_RX_DESCR ATE_MAX_RX_DESCR +#define ATE_NUM_TX_DESCR ATE_MAX_TX_BUFFERS + +#if ATE_NUM_TX_DESCR > ATE_MAX_TX_DESCR +#error "Can't have more TX buffers that descriptors" +#endif +#if ATE_NUM_RX_DESCR > ATE_MAX_RX_DESCR +#error "Can't have more RX buffers that descriptors" +#endif + +/* Wrap indexes the same way the hardware does */ +#define NEXT_RX_IDX(sc, cur) \ + ((sc->rx_descs[cur].addr & ETH_WRAP_BIT) ? 0 : (cur + 1)) + +#define NEXT_TX_IDX(sc, cur) \ + ((sc->tx_descs[cur].status & ETHB_TX_WRAP) ? 0 : (cur + 1)) struct ate_softc { - struct ifnet *ifp; /* ifnet pointer */ - struct mtx sc_mtx; /* Basically a perimeter lock */ - device_t dev; /* Myself */ - device_t miibus; /* My child miibus */ - struct resource *irq_res; /* IRQ resource */ - struct resource *mem_res; /* Memory resource */ - struct callout tick_ch; /* Tick callout */ + struct ifnet *ifp; /* ifnet pointer */ + struct mtx sc_mtx; /* Basically a perimeter lock */ + device_t dev; /* Myself */ + device_t miibus; /* My child miibus */ + struct resource *irq_res; /* IRQ resource */ + struct resource *mem_res; /* Memory resource */ + struct callout tick_ch; /* Tick callout */ struct ifmib_iso_8802_3 mibdata; /* Stuff for network mgmt */ - struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */ - bus_dma_tag_t mtag; /* bus dma tag for mbufs */ - bus_dma_tag_t rxtag; - bus_dma_tag_t rx_desc_tag; - bus_dmamap_t rx_desc_map; - bus_dmamap_t rx_map[ATE_MAX_RX_BUFFERS]; - bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS]; - bus_addr_t rx_desc_phys; - eth_rx_desc_t *rx_descs; - void *rx_buf[ATE_MAX_RX_BUFFERS]; /* RX buffer space */ - void *intrhand; /* Interrupt handle */ - int flags; - int if_flags; - int rx_buf_ptr; - int txcur; /* Current TX map pointer */ - int use_rmii; + bus_dma_tag_t mtag; /* bus dma tag for mbufs */ + bus_dma_tag_t rx_tag; + bus_dma_tag_t rx_desc_tag; + bus_dmamap_t rx_desc_map; + bus_dmamap_t rx_map[ATE_MAX_RX_DESCR]; + bus_addr_t rx_desc_phys; /* PA of rx descriptors */ + eth_rx_desc_t *rx_descs; /* VA of rx descriptors */ + void *rx_buf[ATE_NUM_RX_DESCR]; /* RX buffer space */ + int rxhead; /* Current RX map/desc index */ + uint32_t rx_buf_size; /* Size of Rx buffers */ + + bus_dma_tag_t tx_desc_tag; + bus_dmamap_t tx_desc_map; + bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS]; + bus_addr_t tx_desc_phys; /* PA of tx descriptors */ + eth_tx_desc_t *tx_descs; /* VA of tx descriptors */ + int txhead; /* Current TX map/desc index */ + int txtail; /* Current TX map/desc index */ + struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */ + void *intrhand; /* Interrupt handle */ + int flags; + int if_flags; + int use_rmii; + int is_emacb; /* SAM9x hardware version */ }; static inline uint32_t @@ -167,9 +216,12 @@ static int ate_get_mac(struct ate_softc *sc, u_char *eaddr); static void ate_set_mac(struct ate_softc *sc, u_char *eaddr); static void ate_rxfilter(struct ate_softc *sc); +static int ate_miibus_readreg(device_t dev, int phy, int reg); + +static int ate_miibus_writereg(device_t dev, int phy, int reg, int data); /* - * The AT91 family of products has the ethernet called EMAC. However, - * it isn't self identifying. It is anticipated that the parent bus + * The AT91 family of products has the ethernet interface called EMAC. + * However, it isn't self identifying. It is anticipated that the parent bus * code will take care to only add ate devices where they really are. As * such, we do nothing here to identify the device and just set its name. */ @@ -195,11 +247,7 @@ ate_attach(device_t dev) sc = device_get_softc(dev); sc->dev = dev; ATE_LOCK_INIT(sc); - callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); - /* - * Allocate resources. - */ rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -217,28 +265,41 @@ ate_attach(device_t dev) goto out; } + /* New or old version, chooses buffer size. */ + sc->is_emacb = at91_is_sam9(); + sc->rx_buf_size = RX_BUF_SIZE(sc); + err = ate_activate(dev); if (err) goto out; - sc->use_rmii = (RD4(sc, ETH_CFG) & ETH_CFG_RMII) == ETH_CFG_RMII; + /* Default to what boot rom did */ + if (!sc->is_emacb) + sc->use_rmii = + (RD4(sc, ETH_CFG) & ETH_CFG_RMII) == ETH_CFG_RMII; + else + sc->use_rmii = + (RD4(sc, ETHB_UIO) & ETHB_UIO_RMII) == ETHB_UIO_RMII; +#ifdef AT91_ATE_USE_RMII + /* Compile time override */ + sc->use_rmii = 1; +#endif /* Sysctls */ sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "rmii", - CTLFLAG_RD, &sc->use_rmii, 0, "rmii in use"); + CTLFLAG_RW, &sc->use_rmii, 0, "rmii in use"); /* Calling atestop before ifp is set is OK. */ ATE_LOCK(sc); atestop(sc); ATE_UNLOCK(sc); + callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); if ((err = ate_get_mac(sc, eaddr)) != 0) { - /* - * No MAC address configured. Generate the random one. - */ - if (bootverbose) + /* No MAC address configured. Generate the random one. */ + if (bootverbose) device_printf(dev, "Generating random ethernet address.\n"); rnd = arc4random(); @@ -252,16 +313,22 @@ ate_attach(device_t dev) eaddr[1] = 's'; eaddr[2] = 'd'; eaddr[3] = (rnd >> 16) & 0xff; - eaddr[4] = (rnd >> 8) & 0xff; - eaddr[5] = rnd & 0xff; + eaddr[4] = (rnd >> 8) & 0xff; + eaddr[5] = (rnd >> 0) & 0xff; } sc->ifp = ifp = if_alloc(IFT_ETHER); - if (mii_phy_probe(dev, &sc->miibus, ate_ifmedia_upd, ate_ifmedia_sts)) { - device_printf(dev, "Cannot find my PHY.\n"); - err = ENXIO; + err = mii_attach(dev, &sc->miibus, ifp, ate_ifmedia_upd, + ate_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (err != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto out; } + /* + * XXX: Clear the isolate bit, or we won't get up, + * at least on the HL201 + */ + ate_miibus_writereg(dev, 0, 0, 0x3000); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); @@ -272,8 +339,8 @@ ate_attach(device_t dev) ifp->if_ioctl = ateioctl; ifp->if_init = ateinit; ifp->if_baudrate = 10000000; - IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); - ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); ifp->if_linkmib = &sc->mibdata; ifp->if_linkmiblen = sizeof(sc->mibdata); @@ -282,9 +349,7 @@ ate_attach(device_t dev) ether_ifattach(ifp, eaddr); - /* - * Activate the interrupt. - */ + /* Activate the interrupt. */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, NULL, ate_intr, sc, &sc->intrhand); if (err) { @@ -309,11 +374,12 @@ ate_detach(device_t dev) KASSERT(sc != NULL, ("[ate: %d]: sc is NULL", __LINE__)); ifp = sc->ifp; if (device_is_attached(dev)) { - ether_ifdetach(ifp); ATE_LOCK(sc); - atestop(sc); + sc->flags |= ATE_FLAG_DETACHING; + atestop(sc); ATE_UNLOCK(sc); callout_drain(&sc->tick_ch); + ether_ifdetach(ifp); } if (sc->miibus != NULL) { device_delete_child(dev, sc->miibus); @@ -346,55 +412,29 @@ ate_detach(device_t dev) static void ate_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { - struct ate_softc *sc; if (error != 0) return; - sc = (struct ate_softc *)arg; - sc->rx_desc_phys = segs[0].ds_addr; + *(bus_addr_t *)arg = segs[0].ds_addr; } static void ate_load_rx_buf(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { struct ate_softc *sc; - int i; if (error != 0) return; sc = (struct ate_softc *)arg; - i = sc->rx_buf_ptr; - /* - * For the last buffer, set the wrap bit so the controller - * restarts from the first descriptor. - */ bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); - if (i == ATE_MAX_RX_BUFFERS - 1) - sc->rx_descs[i].addr = segs[0].ds_addr | ETH_WRAP_BIT; - else - sc->rx_descs[i].addr = segs[0].ds_addr; + sc->rx_descs[sc->rxhead].addr = segs[0].ds_addr; + sc->rx_descs[sc->rxhead].status = 0; bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTWRITE); - sc->rx_descs[i].status = 0; - /* Flush the memory in the mbuf */ - bus_dmamap_sync(sc->rxtag, sc->rx_map[i], BUS_DMASYNC_PREREAD); -} - -static uint32_t -ate_mac_hash(const uint8_t *buf) -{ - uint32_t index = 0; - for (int i = 0; i < 48; i++) { - index ^= ((buf[i >> 3] >> (i & 7)) & 1) << (i % 6); - } - return (index); } /* - * Compute the multicast filter for this device using the standard - * algorithm. I wonder why this isn't in ether somewhere as a lot - * of different MAC chips use this method (or the reverse the bits) - * method. + * Compute the multicast filter for this device. */ static int ate_setmcast(struct ate_softc *sc) @@ -415,17 +455,15 @@ ate_setmcast(struct ate_softc *sc) return (1); } - /* - * Compute the multicast hash. - */ + /* Compute the multicast hash. */ mcaf[0] = 0; mcaf[1] = 0; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; - index = ate_mac_hash(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr)); + index = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; af[index >> 3] |= 1 << (index & 7); } if_maddr_runlock(ifp); @@ -446,69 +484,124 @@ static int ate_activate(device_t dev) { struct ate_softc *sc; - int err, i; + int i; sc = device_get_softc(dev); - /* - * Allocate DMA tags and maps. - */ - err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, + /* Allocate DMA tags and maps for TX mbufs */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - 1, MCLBYTES, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->mtag); - if (err != 0) + 1, MCLBYTES, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->mtag)) goto errout; for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { - err = bus_dmamap_create(sc->mtag, 0, &sc->tx_map[i]); - if (err != 0) + if ( bus_dmamap_create(sc->mtag, 0, &sc->tx_map[i])) goto errout; } - /* - * Allocate DMA tags and maps for RX. - */ - err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - 1, MCLBYTES, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->rxtag); - if (err != 0) - goto errout; - /* - * DMA tag and map for the RX descriptors. - */ - err = bus_dma_tag_create(bus_get_dma_tag(dev), sizeof(eth_rx_desc_t), + /* DMA tag and map for the RX descriptors. */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), sizeof(eth_rx_desc_t), 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t), 1, - ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t), 0, busdma_lock_mutex, - &sc->sc_mtx, &sc->rx_desc_tag); - if (err != 0) + ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), 1, + ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), 0, busdma_lock_mutex, + &sc->sc_mtx, &sc->rx_desc_tag)) goto errout; if (bus_dmamem_alloc(sc->rx_desc_tag, (void **)&sc->rx_descs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->rx_desc_map) != 0) goto errout; if (bus_dmamap_load(sc->rx_desc_tag, sc->rx_desc_map, - sc->rx_descs, ATE_MAX_RX_BUFFERS * sizeof(eth_rx_desc_t), - ate_getaddr, sc, 0) != 0) + sc->rx_descs, ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), + ate_getaddr, &sc->rx_desc_phys, 0) != 0) + goto errout; + + /* Allocate DMA tags and maps for RX. buffers */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + sc->rx_buf_size, 1, sc->rx_buf_size, 0, + busdma_lock_mutex, &sc->sc_mtx, &sc->rx_tag)) goto errout; /* - * Allocate our RX buffers. This chip has a RX structure that's filled - * in. + * Allocate our RX buffers. + * This chip has a RX structure that's filled in. + * XXX On MACB (SAM9 part) we should receive directly into mbuf + * to avoid the copy. XXX */ - for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) { - sc->rx_buf_ptr = i; - if (bus_dmamem_alloc(sc->rxtag, (void **)&sc->rx_buf[i], - BUS_DMA_NOWAIT, &sc->rx_map[i]) != 0) + sc->rxhead = 0; + for (sc->rxhead = 0; sc->rxhead < ATE_RX_MEMORY/sc->rx_buf_size; + sc->rxhead++) { + if (bus_dmamem_alloc(sc->rx_tag, + (void **)&sc->rx_buf[sc->rxhead], BUS_DMA_NOWAIT, + &sc->rx_map[sc->rxhead]) != 0) goto errout; - if (bus_dmamap_load(sc->rxtag, sc->rx_map[i], sc->rx_buf[i], - MCLBYTES, ate_load_rx_buf, sc, 0) != 0) + + if (bus_dmamap_load(sc->rx_tag, sc->rx_map[sc->rxhead], + sc->rx_buf[sc->rxhead], sc->rx_buf_size, + ate_load_rx_buf, sc, 0) != 0) { + printf("bus_dmamem_load\n"); goto errout; + } + bus_dmamap_sync(sc->rx_tag, sc->rx_map[sc->rxhead], BUS_DMASYNC_PREREAD); } - sc->rx_buf_ptr = 0; + + /* + * For the last buffer, set the wrap bit so the controller + * restarts from the first descriptor. + */ + sc->rx_descs[--sc->rxhead].addr |= ETH_WRAP_BIT; + sc->rxhead = 0; + /* Flush the memory for the EMAC rx descriptor. */ bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); + /* Write the descriptor queue address. */ WR4(sc, ETH_RBQP, sc->rx_desc_phys); + + /* + * DMA tag and map for the TX descriptors. + * XXX Old EMAC (not EMACB) doesn't really need DMA'able + * memory. We could just malloc it. gja XXX + */ + if (bus_dma_tag_create(bus_get_dma_tag(dev), sizeof(eth_tx_desc_t), + 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), 1, + ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), 0, busdma_lock_mutex, + &sc->sc_mtx, &sc->tx_desc_tag) != 0) + goto errout; + + if (bus_dmamem_alloc(sc->tx_desc_tag, (void **)&sc->tx_descs, + BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->tx_desc_map) != 0) + goto errout; + + if (bus_dmamap_load(sc->tx_desc_tag, sc->tx_desc_map, + sc->tx_descs, ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), + ate_getaddr, &sc->tx_desc_phys, 0) != 0) + goto errout; + + /* Initilize descriptors; mark all empty */ + for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { + sc->tx_descs[i].addr =0; + sc->tx_descs[i].status = ETHB_TX_USED; + sc->sent_mbuf[i] = NULL; + } + + /* Mark last entry to cause wrap when indexing through */ + sc->tx_descs[ATE_MAX_TX_BUFFERS - 1].status = + ETHB_TX_WRAP | ETHB_TX_USED; + + /* Flush the memory for the EMAC tx descriptor. */ + bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_PREWRITE); + + sc->txhead = sc->txtail = 0; + if (sc->is_emacb) { + /* Write the descriptor queue address. */ + WR4(sc, ETHB_TBQP, sc->tx_desc_phys); + } + + /* EMACB: Enable transceiver input clock */ + if (sc->is_emacb) + WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) | ETHB_UIO_CLKE); + return (0); errout: @@ -546,24 +639,22 @@ ate_deactivate(struct ate_softc *sc) } } } - if (sc->rxtag != NULL) { - for (i = 0; i < ATE_MAX_RX_BUFFERS; i++) { - if (sc->rx_buf[i] != NULL) { - if (sc->rx_descs[i].addr != 0) { - bus_dmamap_sync(sc->rxtag, - sc->rx_map[i], - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->rxtag, - sc->rx_map[i]); - sc->rx_descs[i].addr = 0; - } - bus_dmamem_free(sc->rxtag, sc->rx_buf[i], + if (sc->rx_tag != NULL) { + for (i = 0; sc->rx_buf[i] != NULL; i++) { + if (sc->rx_descs[i].addr != 0) { + bus_dmamap_sync(sc->rx_tag, + sc->rx_map[i], + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->rx_tag, sc->rx_map[i]); - sc->rx_buf[i] = NULL; - sc->rx_map[i] = NULL; + sc->rx_descs[i].addr = 0; } + bus_dmamem_free(sc->rx_tag, sc->rx_buf[i], + sc->rx_map[i]); + sc->rx_buf[i] = NULL; + sc->rx_map[i] = NULL; } - bus_dma_tag_destroy(sc->rxtag); + bus_dma_tag_destroy(sc->rx_tag); } if (sc->rx_desc_tag != NULL) { if (sc->rx_descs != NULL) @@ -573,6 +664,9 @@ ate_deactivate(struct ate_softc *sc) sc->rx_descs = NULL; sc->rx_desc_tag = NULL; } + + if (sc->is_emacb) + WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) & ~ETHB_UIO_CLKE); } /* @@ -689,9 +783,7 @@ ate_tick(void *xsc) sc->ifp->if_ierrors += RD4(sc, ETH_CDE) + RD4(sc, ETH_RJB) + RD4(sc, ETH_USF); - /* - * Schedule another timeout one second from now. - */ + /* Schedule another timeout one second from now. */ callout_reset(&sc->tick_ch, hz, ate_tick, sc); } @@ -713,8 +805,8 @@ ate_get_mac(struct ate_softc *sc, u_char *eaddr) int i; /* - * The boot loader setup the MAC with an address, if one is set in - * the loader. Grab one MAC address from the SA[1-4][HL] registers. + * The boot loader may setup the MAC with an address(es), grab the + * first MAC address from the SA[1-4][HL] registers. */ for (i = 0; i < 4; i++) { low = RD4(sc, sa_low_reg[i]); @@ -738,87 +830,162 @@ ate_intr(void *xsc) struct ate_softc *sc = xsc; struct ifnet *ifp = sc->ifp; struct mbuf *mb; - void *bp; - uint32_t status, reg, rx_stat; - int i; + eth_rx_desc_t *rxdhead; + uint32_t status, reg, idx; + int remain, count, done; status = RD4(sc, ETH_ISR); if (status == 0) return; + if (status & ETH_ISR_RCOM) { - bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, + + bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTREAD); - while (sc->rx_descs[sc->rx_buf_ptr].addr & ETH_CPU_OWNER) { - i = sc->rx_buf_ptr; - sc->rx_buf_ptr = (i + 1) % ATE_MAX_RX_BUFFERS; - bp = sc->rx_buf[i]; - rx_stat = sc->rx_descs[i].status; - if ((rx_stat & ETH_LEN_MASK) == 0) { - if (bootverbose) - device_printf(sc->dev, "ignoring bogus zero-length packet\n"); - bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, - BUS_DMASYNC_PREWRITE); - sc->rx_descs[i].addr &= ~ETH_CPU_OWNER; - bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, - BUS_DMASYNC_POSTWRITE); + + rxdhead = &sc->rx_descs[sc->rxhead]; + while (rxdhead->addr & ETH_CPU_OWNER) { + if (!sc->is_emacb) { + /* + * Simulate SAM9 FIRST/LAST bits for RM9200. + * RM9200 EMAC has only on Rx buffer per packet. + * But sometime we are handed a zero lenght packet. + */ + if ((rxdhead->status & ETH_LEN_MASK) == 0) + rxdhead->status = 0; /* Mark error */ + else + rxdhead->status |= ETH_BUF_FIRST | ETH_BUF_LAST; + } + + if ((rxdhead->status & ETH_BUF_FIRST) == 0) { + /* Something went wrong during RX so + release back to EMAC all buffers of invalid packets. + */ + rxdhead->status = 0; + rxdhead->addr &= ~ETH_CPU_OWNER; + sc->rxhead = NEXT_RX_IDX(sc, sc->rxhead); + rxdhead = &sc->rx_descs[sc->rxhead]; continue; } - /* Flush memory for mbuf so we don't get stale bytes */ - bus_dmamap_sync(sc->rxtag, sc->rx_map[i], - BUS_DMASYNC_POSTREAD); - WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); - /* - * The length returned by the device includes the - * ethernet CRC calculation for the packet, but - * ifnet drivers are supposed to discard it. - */ - mb = m_devget(sc->rx_buf[i], - (rx_stat & ETH_LEN_MASK) - ETHER_CRC_LEN, - ETHER_ALIGN, ifp, NULL); - bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, - BUS_DMASYNC_PREWRITE); - sc->rx_descs[i].addr &= ~ETH_CPU_OWNER; - bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_sync(sc->rxtag, sc->rx_map[i], - BUS_DMASYNC_PREREAD); + /* Find end of packet or start of next */ + idx = sc->rxhead; + if ((sc->rx_descs[idx].status & ETH_BUF_LAST) == 0) { + idx = NEXT_RX_IDX(sc, idx); + + while ((sc->rx_descs[idx].addr & ETH_CPU_OWNER) && + ((sc->rx_descs[idx].status & + (ETH_BUF_FIRST|ETH_BUF_LAST))== 0)) + idx = NEXT_RX_IDX(sc, idx); + } + + /* Packet NOT yet completely in memory; we are done */ + if ((sc->rx_descs[idx].addr & ETH_CPU_OWNER) == 0 || + ((sc->rx_descs[idx].status & (ETH_BUF_FIRST|ETH_BUF_LAST))== 0)) + break; + + /* Packets with no end descriptor are invalid. */ + if ((sc->rx_descs[idx].status & ETH_BUF_LAST) == 0) { + rxdhead->status &= ~ETH_BUF_FIRST; + continue; + } + + /* FCS is not coppied into mbuf. */ + remain = (sc->rx_descs[idx].status & ETH_LEN_MASK) - 4; + + /* Get an appropriately sized mbuf */ + if (remain + ETHER_ALIGN >= MINCLSIZE) + mb = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + else + MGETHDR(mb, M_DONTWAIT, MT_DATA); + + if (mb == NULL) { + sc->ifp->if_iqdrops++; + rxdhead->status = 0; + continue; + } + mb->m_data += ETHER_ALIGN; + mb->m_pkthdr.rcvif = ifp; + + WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); /* Reset status */ + + /* Now we process the buffers that make up the packet */ + do { + + /* Last buffer may just be 1-4 bytes of FCS so remain + * may be zero for last decriptor. */ + if (remain > 0) { + /* Make sure we get the current bytes */ + bus_dmamap_sync(sc->rx_tag, sc->rx_map[sc->rxhead], + BUS_DMASYNC_POSTREAD); + + count = MIN(remain, sc->rx_buf_size); + + /* XXX Performance robbing copy. Could + * recieve directly to mbufs if not an + * RM9200. XXX */ + m_append(mb, count, sc->rx_buf[sc->rxhead]); + remain -= count; + } + + done = (rxdhead->status & ETH_BUF_LAST) != 0; + + /* Return the descriptor to the EMAC */ + rxdhead->status = 0; + rxdhead->addr &= ~ETH_CPU_OWNER; + bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, + BUS_DMASYNC_PREWRITE); + + /* Move on to next descriptor with wrap */ + sc->rxhead = NEXT_RX_IDX(sc, sc->rxhead); + rxdhead = &sc->rx_descs[sc->rxhead]; + + } while (!done); + if (mb != NULL) { ifp->if_ipackets++; (*ifp->if_input)(ifp, mb); } - } } + + if (status & ETH_ISR_TCOM) { + bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, + BUS_DMASYNC_POSTREAD); + ATE_LOCK(sc); /* XXX TSR register should be cleared */ - if (sc->sent_mbuf[0]) { - bus_dmamap_sync(sc->mtag, sc->tx_map[0], + if (!sc->is_emacb) { + /* Simulate Transmit descriptor table */ + + /* First packet done */ + if (sc->txtail < sc->txhead) + sc->tx_descs[sc->txtail].status |= ETHB_TX_USED; + + /* Second Packet done */ + if (sc->txtail + 1 < sc->txhead && + RD4(sc, ETH_TSR) & ETH_TSR_IDLE) + sc->tx_descs[sc->txtail + 1].status |= ETHB_TX_USED; + } + + while (sc->txtail != sc->txhead && + sc->tx_descs[sc->txtail].status & ETHB_TX_USED ) { + + bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txtail], BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->mtag, sc->tx_map[0]); - m_freem(sc->sent_mbuf[0]); + bus_dmamap_unload(sc->mtag, sc->tx_map[sc->txtail]); + m_freem(sc->sent_mbuf[sc->txtail]); + sc->tx_descs[sc->txtail].addr = 0; + sc->sent_mbuf[sc->txtail] = NULL; + ifp->if_opackets++; - sc->sent_mbuf[0] = NULL; - } - if (sc->sent_mbuf[1]) { - if (RD4(sc, ETH_TSR) & ETH_TSR_IDLE) { - bus_dmamap_sync(sc->mtag, sc->tx_map[1], - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->mtag, sc->tx_map[1]); - m_freem(sc->sent_mbuf[1]); - ifp->if_opackets++; - sc->txcur = 0; - sc->sent_mbuf[0] = sc->sent_mbuf[1] = NULL; - } else { - sc->sent_mbuf[0] = sc->sent_mbuf[1]; - sc->sent_mbuf[1] = NULL; - sc->txcur = 1; - } - } else { - sc->sent_mbuf[0] = NULL; - sc->txcur = 0; + sc->txtail = NEXT_TX_IDX(sc, sc->txtail); } + + /* Flush descriptors to EMAC */ + bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_PREWRITE); + /* * We're no longer busy, so clear the busy flag and call the * start routine to xmit more packets. @@ -827,8 +994,9 @@ ate_intr(void *xsc) atestart_locked(sc->ifp); ATE_UNLOCK(sc); } + if (status & ETH_ISR_RBNA) { - /* Workaround Errata #11 */ + /* Workaround RM9200 Errata #11 */ if (bootverbose) device_printf(sc->dev, "RBNA workaround\n"); reg = RD4(sc, ETH_CTL); @@ -846,7 +1014,7 @@ ateinit_locked(void *xsc) { struct ate_softc *sc = xsc; struct ifnet *ifp = sc->ifp; - struct mii_data *mii; + struct mii_data *mii; uint8_t eaddr[ETHER_ADDR_LEN]; uint32_t reg; @@ -859,20 +1027,27 @@ ateinit_locked(void *xsc) * need to think about how best to turn it on/off as the interface * is brought up/down, as well as dealing with the mii bus... * - * We also need to multiplex the pins correctly. + * We also need to multiplex the pins correctly (in board_xxx.c). */ /* * There are two different ways that the mii bus is connected - * to this chip. Select the right one based on a compile-time - * option. + * to this chip mii or rmii. */ - reg = RD4(sc, ETH_CFG); - if (sc->use_rmii) - reg |= ETH_CFG_RMII; - else - reg &= ~ETH_CFG_RMII; - WR4(sc, ETH_CFG, reg); + if (!sc->is_emacb) { + /* RM9200 */ + reg = RD4(sc, ETH_CFG); + if (sc->use_rmii) + reg |= ETH_CFG_RMII; + else + reg &= ~ETH_CFG_RMII; + WR4(sc, ETH_CFG, reg); + } else { + /* SAM9 */ + reg = ETHB_UIO_CLKE; + reg |= (sc->use_rmii) ? ETHB_UIO_RMII : 0; + WR4(sc, ETHB_UIO, reg); + } ate_rxfilter(sc); @@ -882,6 +1057,13 @@ ateinit_locked(void *xsc) bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); ate_set_mac(sc, eaddr); + /* Make sure we know state of TX queue */ + sc->txhead = sc->txtail = 0; + if (sc->is_emacb) { + /* Write the descriptor queue address. */ + WR4(sc, ETHB_TBQP, sc->tx_desc_phys); + } + /* * Turn on MACs and interrupt processing. */ @@ -921,23 +1103,26 @@ atestart_locked(struct ifnet *ifp) if (ifp->if_drv_flags & IFF_DRV_OACTIVE) return; - while (sc->txcur < ATE_MAX_TX_BUFFERS) { + while (sc->tx_descs[sc->txhead].status & ETHB_TX_USED) { /* * Check to see if there's room to put another packet into the - * xmit queue. The EMAC chip has a ping-pong buffer for xmit - * packets. We use OACTIVE to indicate "we can stuff more into - * our buffers (clear) or not (set)." + * xmit queue. The old EMAC version has a ping-pong buffer for + * xmit packets. We use OACTIVE to indicate "we can stuff more + * into our buffers (clear) or not (set)." */ - if (!(RD4(sc, ETH_TSR) & ETH_TSR_BNQ)) { - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - return; + if (!sc->is_emacb) { + /* RM9200 has only two hardware entries */ + if (!sc->is_emacb && (RD4(sc, ETH_TSR) & ETH_TSR_BNQ) == 0) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + return; + } } + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); - if (m == 0) { - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - return; - } - e = bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txcur], m, + if (m == 0) + break; + + e = bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txhead], m, segs, &nseg, 0); if (e == EFBIG) { mdefrag = m_defrag(m, M_DONTWAIT); @@ -947,30 +1132,41 @@ atestart_locked(struct ifnet *ifp) } m = mdefrag; e = bus_dmamap_load_mbuf_sg(sc->mtag, - sc->tx_map[sc->txcur], m, segs, &nseg, 0); + sc->tx_map[sc->txhead], m, segs, &nseg, 0); } if (e != 0) { m_freem(m); continue; } - bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txcur], + sc->sent_mbuf[sc->txhead] = m; + + bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txhead], BUS_DMASYNC_PREWRITE); - /* - * Tell the hardware to xmit the packet. - */ - WR4(sc, ETH_TAR, segs[0].ds_addr); - BARRIER(sc, ETH_TAR, 8, BUS_SPACE_BARRIER_WRITE); - WR4(sc, ETH_TCR, segs[0].ds_len); + /* Tell the hardware to xmit the packet. */ + if (!sc->is_emacb) { + WR4(sc, ETH_TAR, segs[0].ds_addr); + BARRIER(sc, ETH_TAR, 4, BUS_SPACE_BARRIER_WRITE); + WR4(sc, ETH_TCR, segs[0].ds_len); + } else { + bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, + BUS_DMASYNC_POSTWRITE); + sc->tx_descs[sc->txhead].addr = segs[0].ds_addr; + sc->tx_descs[sc->txhead].status = segs[0].ds_len | + (sc->tx_descs[sc->txhead].status & ETHB_TX_WRAP) | + ETHB_TX_BUF_LAST; + bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, + BUS_DMASYNC_PREWRITE); + WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETHB_CTL_TGO); + } + sc->txhead = NEXT_TX_IDX(sc, sc->txhead); - /* - * Tap off here if there is a bpf listener. - */ + /* Tap off here if there is a bpf listener. */ BPF_MTAP(ifp, m); - - sc->sent_mbuf[sc->txcur] = m; - sc->txcur++; } + + if ((sc->tx_descs[sc->txhead].status & ETHB_TX_USED) == 0) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; } static void @@ -1006,6 +1202,7 @@ atestop(struct ate_softc *sc) ATE_ASSERT_LOCKED(sc); ifp = sc->ifp; if (ifp) { + //ifp->if_timer = 0; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } @@ -1022,7 +1219,18 @@ atestop(struct ate_softc *sc) /* * Turn off all the configured options and revert to defaults. */ - WR4(sc, ETH_CFG, ETH_CFG_CLK_32); + + /* Make sure thate the MDIO clk is less than + * 2.5 Mhz. Can no longer default to /32 since + * SAM9 family may have MCK > 80 Mhz */ + if (at91_master_clock <= 2000000) + WR4(sc, ETH_CFG, ETH_CFG_CLK_8); + else if (at91_master_clock <= 4000000) + WR4(sc, ETH_CFG, ETH_CFG_CLK_16); + else if (at91_master_clock <= 800000) + WR4(sc, ETH_CFG, ETH_CFG_CLK_32); + else + WR4(sc, ETH_CFG, ETH_CFG_CLK_64); /* * Turn off all the interrupts, and ack any pending ones by reading @@ -1038,9 +1246,7 @@ atestop(struct ate_softc *sc) WR4(sc, ETH_TSR, 0xffffffff); WR4(sc, ETH_RSR, 0xffffffff); - /* - * Release TX resources. - */ + /* Release TX resources. */ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { if (sc->sent_mbuf[i] != NULL) { bus_dmamap_sync(sc->mtag, sc->tx_map[i], @@ -1051,6 +1257,10 @@ atestop(struct ate_softc *sc) } } + /* Turn off transeiver input clock */ + if (sc->is_emacb) + WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) & ~ETHB_UIO_CLKE); + /* * XXX we should power down the EMAC if it isn't in use, after * putting it into loopback mode. This saves about 400uA according @@ -1069,17 +1279,13 @@ ate_rxfilter(struct ate_softc *sc) ATE_ASSERT_LOCKED(sc); ifp = sc->ifp; - /* - * Wipe out old filter settings. - */ + /* Wipe out old filter settings. */ reg = RD4(sc, ETH_CFG); reg &= ~(ETH_CFG_CAF | ETH_CFG_MTI | ETH_CFG_UNI); reg |= ETH_CFG_NBC; sc->flags &= ~ATE_FLAG_MULTICAST; - /* - * Set new parameters. - */ + /* Set new parameters. */ if ((ifp->if_flags & IFF_BROADCAST) != 0) reg &= ~ETH_CFG_NBC; if ((ifp->if_flags & IFF_PROMISC) != 0) { @@ -1098,8 +1304,8 @@ static int ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ate_softc *sc = ifp->if_softc; - struct mii_data *mii; - struct ifreq *ifr = (struct ifreq *)data; + struct mii_data *mii; + struct ifreq *ifr = (struct ifreq *)data; int drv_flags, flags; int mask, error, enabled; @@ -1115,9 +1321,11 @@ ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) & (IFF_PROMISC | IFF_ALLMULTI)) != 0) ate_rxfilter(sc); } else { - ateinit_locked(sc); + if ((sc->flags & ATE_FLAG_DETACHING) == 0) + ateinit_locked(sc); } } else if ((drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; atestop(sc); } sc->if_flags = flags; @@ -1135,11 +1343,11 @@ ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - mii = device_get_softc(sc->miibus); - error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); - break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + mii = device_get_softc(sc->miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); + break; case SIOCSIFCAP: mask = ifp->if_capenable ^ ifr->ifr_reqcap; if (mask & IFCAP_VLAN_MTU) { diff --git a/sys/arm/at91/if_atereg.h b/sys/arm/at91/if_atereg.h index 10fbfdb326e..fc7e4de942c 100644 --- a/sys/arm/at91/if_atereg.h +++ b/sys/arm/at91/if_atereg.h @@ -28,6 +28,8 @@ #ifndef ARM_AT91_IF_ATEREG_H #define ARM_AT91_IF_ATEREG_H +/* deines begining ETHB_ are EMACB (newer SAM9 hardware) versions only */ + #define ETH_CTL 0x00 /* EMAC Control Register */ #define ETH_CFG 0x04 /* EMAC Configuration Register */ #define ETH_SR 0x08 /* EMAC STatus Register */ @@ -35,7 +37,7 @@ #define ETH_TCR 0x10 /* EMAC Transmit Control Register */ #define ETH_TSR 0x14 /* EMAC Transmit Status Register */ #define ETH_RBQP 0x18 /* EMAC Receive Buffer Queue Pointer */ - /* 0x1c reserved */ +#define ETHB_TBQP 0x1c /* reserved */ #define ETH_RSR 0x20 /* EMAC Receive Status Register */ #define ETH_ISR 0x24 /* EMAC Interrupt Status Register */ #define ETH_IER 0x28 /* EMAC Interrupt Enable Register */ @@ -74,6 +76,8 @@ #define ETH_SA3H 0xac /* EMAC Specific Address 3 High */ #define ETH_SA4L 0xb0 /* EMAC Specific Address 4 Low */ #define ETH_SA4H 0xb4 /* EMAC Specific Address 4 High */ +#define ETHB_TID 0xb8 /* EMAC Type ID Checking */ +#define ETHB_UIO 0xC0 /* EMAC User I/O Reg */ /* ETH_CTL */ @@ -87,6 +91,9 @@ #define ETH_CTL_WES (1U << 7) /* WES: Write Enable Statistics regs */ #define ETH_CTL_BP (1U << 8) /* BP: Back Pressure */ +#define ETHB_CTL_TGO (1U << 9) /* TGO: Transmitter Start */ +#define ETHB_CTL_TSTP (1U << 10) /* TSTP: Transmitter Stop */ + /* ETH_CFG */ #define ETH_CFG_SPD (1U << 0) /* SPD: Speed 1 == 100: 0 == 10 */ #define ETH_CFG_FD (1U << 1) /* FD: Full duplex */ @@ -105,6 +112,17 @@ #define ETH_CFG_RTY (1U << 12) /* RTY: Retry Test*/ #define ETH_CFG_RMII (1U << 13) /* RMII: Reduce MII */ +#define ETHB_CFG_JBO (1U << 3) /* JBO: Jumbo Frames */ +#define ETHB_CFG_PAE (1U << 13) /* PAE: Pause Enable */ +#define ETHB_CFG_RBOF_0 (0U << 14) /* RBOF: Rx Buffer Offset */ +#define ETHB_CFG_RBOF_1 (1U << 14) /* RBOF: Rx Buffer Offset */ +#define ETHB_CFG_RBOF_2 (3U << 14) /* RBOF: Rx Buffer Offset */ +#define ETHB_CFG_RBOF_3 (3U << 14) /* RBOF: Rx Buffer Offset */ +#define ETHB_CFG_RCLE (1U << 16) /* RCLE: Rx Length Check Enable */ +#define ETHB_CFG_DRFC (1U << 17) /* DRFC: Discard Rx FCS */ +#define ETHB_CFG_RHD (1U << 18) /* RHD: RX TX'ed frame in half-duplex */ +#define ETHB_CFG_IFCS (1U << 19) /* IFCS: Ignore bad RX FCS */ + /* ETH_SR */ #define ETH_SR_LINK (1U << 0) /* Reserved! */ #define ETH_SR_MDIO (1U << 1) /* MDIO pin status */ @@ -142,6 +160,10 @@ #define ETH_ISR_ROVR (1U << 10) /* ROVR: RX Overrun */ #define ETH_ISR_ABT (1U << 11) /* ABT: Abort */ +/* ETHB_UIO */ +#define ETHB_UIO_RMII (1U << 0) /* RMII: Reduce MII */ +#define ETHB_UIO_CLKE (1U << 1) /* CLKE: Clock Enable */ + /* ETH_MAN */ #define ETH_MAN_BITS 0x40020000 /* HIGH and CODE bits */ #define ETH_MAN_READ (2U << 28) @@ -160,8 +182,11 @@ typedef struct { uint32_t addr; #define ETH_CPU_OWNER (1U << 0) #define ETH_WRAP_BIT (1U << 1) +#define ETH_ADR_MASK ~(EHT_CPU_OWNER | ETH_WRAP_BIT) uint32_t status; #define ETH_LEN_MASK 0x7ff +#define ETH_BUF_FIRST (1U << 14) /* Packet matched addr 4 */ +#define ETH_BUF_LAST (1U << 15) /* Packet matched addr 4 */ #define ETH_MAC_LOCAL_4 (1U << 23) /* Packet matched addr 4 */ #define ETH_MAC_LOCAL_3 (1U << 24) /* Packet matched addr 3 */ #define ETH_MAC_LOCAL_2 (1U << 25) /* Packet matched addr 2 */ @@ -173,4 +198,17 @@ typedef struct { #define ETH_MAC_ONES (1U << 31) /* Global all ones bcast addr */ } eth_rx_desc_t; +typedef struct { + uint32_t addr; + uint32_t status; +#define ETHB_TX_LEN_MASK 0x7ff +#define ETHB_TX_BUF_LAST (1U << 15) /* Last buffer in packet */ +#define ETHB_TX_NOCRC (1U << 16) /* Don't xmit CRC*/ +#define ETHB_TX_BUFE (1U << 27) /* Buffers exhausted mid frame */ +#define ETHB_TX_TUND (1U << 28) /* Transmit Underrun */ +#define ETHB_TX_RTRYE (1U << 29) /* Re-try limit exceeded */ +#define ETHB_TX_WRAP (1U << 30) /* Last descritor in list */ +#define ETHB_TX_USED (1U << 31) /* Packet Transmitted */ +} eth_tx_desc_t; + #endif /* ARM_AT91_IF_ATEREG_H */ diff --git a/sys/arm/at91/if_macb.c b/sys/arm/at91/if_macb.c index 7504c0797cc..02dedac6810 100644 --- a/sys/arm/at91/if_macb.c +++ b/sys/arm/at91/if_macb.c @@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -1336,34 +1335,8 @@ macb_attach(device_t dev) goto out; } - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, 1<<7, 0); - - at91_pio_gpio_input(AT91SAM9G20_PIOA_BASE, 1<<7); - at91_pio_gpio_set_deglitch(AT91SAM9G20_PIOA_BASE, 1<<7, 1); - - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA19, 0); /* ETXCK_EREFCK */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA17, 0); /* ERXDV */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA14, 0); /* ERX0 */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA15, 0); /* ERX1 */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA18, 0); /* ERXER */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA16, 0); /* ETXEN */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA12, 0); /* ETX0 */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA13, 0); /* ETX1 */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA21, 0); /* EMDIO */ - at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA20, 0); /* EMDC */ - - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA28, 0); /* ECRS */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA29, 0); /* ECOL */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA25, 0); /* ERX2 */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA26, 0); /* ERX3 */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA27, 0); /* ERXCK */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA23, 0); /* ETX2 */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA24, 0); /* ETX3 */ - at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA22, 0); /* ETXER */ - - /*setup clock*/ - sc->clk = at91_pmc_clock_ref("macb_clk"); + sc->clk = at91_pmc_clock_ref(device_get_nameunit(sc->dev)); at91_pmc_clock_enable(sc->clk); macb_reset(sc); @@ -1391,9 +1364,10 @@ macb_attach(device_t dev) write_4(sc, EMAC_NCR, MPE_ENABLE); //enable MPE sc->ifp = ifp = if_alloc(IFT_ETHER); - if (mii_phy_probe(dev, &sc->miibus, macb_ifmedia_upd, macb_ifmedia_sts)) { - device_printf(dev, "Cannot find my PHY.\n"); - err = ENXIO; + err = mii_attach(dev, &sc->miibus, ifp, macb_ifmedia_upd, + macb_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (err != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto out; } diff --git a/sys/arm/at91/std.at91sam9 b/sys/arm/at91/std.at91sam9 index 96aeb2b9882..ab1fa9547a9 100644 --- a/sys/arm/at91/std.at91sam9 +++ b/sys/arm/at91/std.at91sam9 @@ -2,5 +2,8 @@ files "../at91/files.at91sam9" cpu CPU_ARM9 -makeoptions CONF_CFLAGS="-mcpu=arm9 -DAT91SAM9G20" +makeoptions CONF_CFLAGS="-mcpu=arm9" options PHYSADDR=0x20000000 + +device at91sam9g20 +device at91sam9260 diff --git a/sys/arm/at91/std.kb920x b/sys/arm/at91/std.kb920x index 85c8d038bf7..26d0443f28f 100644 --- a/sys/arm/at91/std.kb920x +++ b/sys/arm/at91/std.kb920x @@ -6,5 +6,6 @@ makeoptions KERNPHYSADDR=0x20000000 options KERNPHYSADDR=0x20000000 makeoptions KERNVIRTADDR=0xc0000000 options KERNVIRTADDR=0xc0000000 +options AT91C_MASTER_CLOCK=60000000 device at91_board_kb920x diff --git a/sys/arm/at91/std.qila9g20 b/sys/arm/at91/std.qila9g20 new file mode 100644 index 00000000000..007cdf5f8ba --- /dev/null +++ b/sys/arm/at91/std.qila9g20 @@ -0,0 +1,11 @@ +#$FreeBSD$ +include "../at91/std.at91sam9" + +options STARTUP_PAGETABLE_ADDR=0x20800000 +makeoptions KERNPHYSADDR=0x20000000 +makeoptions KERNVIRTADDR=0xc0000000 +options KERNPHYSADDR=0x20000000 +options KERNVIRTADDR=0xc0000000 +options AT91C_MASTER_CLOCK=((12000000*133)/12) + +device at91_board_qila9g20 diff --git a/sys/arm/at91/std.sam9g20ek b/sys/arm/at91/std.sam9g20ek new file mode 100644 index 00000000000..c5509c5ced6 --- /dev/null +++ b/sys/arm/at91/std.sam9g20ek @@ -0,0 +1,15 @@ +#$FreeBSD$ +include "../at91/std.at91sam9" + +options STARTUP_PAGETABLE_ADDR=0x20800000 +makeoptions KERNPHYSADDR=0x20000000 +makeoptions KERNVIRTADDR=0xc0000000 +options KERNPHYSADDR=0x20000000 +options KERNVIRTADDR=0xc0000000 + +#SAM9G20 w/ 18.432 Mhz Clock +#options AT91C_MASTER_CLOCK=((18432000*43)/6) +#SAM9260 w/ 18.432 Mhz Clock +#options AT91C_MASTER_CLOCK=((18432000*97)/18) + +device at91_board_sam9g20ek diff --git a/sys/arm/at91/uart_cpu_at91rm9200usart.c b/sys/arm/at91/uart_cpu_at91rm9200usart.c index d290c284f05..9e9baa2a758 100644 --- a/sys/arm/at91/uart_cpu_at91rm9200usart.c +++ b/sys/arm/at91/uart_cpu_at91rm9200usart.c @@ -64,7 +64,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) struct uart_class *class; class = &at91_usart_class; - if (class->uc_rclk == 0) + if (class->uc_rclk == 0 && at91_master_clock != 0) class->uc_rclk = at91_master_clock; di->ops = uart_getops(class); di->bas.chan = 0; @@ -77,7 +77,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->bas.bsh = AT91RM92_BASE + AT91RM92_USART0_BASE; di->baudrate = 38400; #else - di->bas.bsh = AT91RM92_BASE + AT91RM92_SYS_BASE + DBGU; + di->bas.bsh = AT91RM92_BASE + AT91RM92_DBGU_BASE; di->baudrate = 115200; #endif di->bas.regshft = 0; diff --git a/sys/arm/at91/uart_dev_at91usart.c b/sys/arm/at91/uart_dev_at91usart.c index 77ab0ca8c10..89ed2d26a89 100644 --- a/sys/arm/at91/uart_dev_at91usart.c +++ b/sys/arm/at91/uart_dev_at91usart.c @@ -190,9 +190,10 @@ at91_usart_param(struct uart_bas *bas, int baudrate, int databits, WR4(bas, USART_MR, mr); /* - * Set the baud rate + * Set the baud rate (only if we know our master clock rate) */ - WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate)); + if (DEFAULT_RCLK != 0) + WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate)); /* XXX Need to take possible synchronous mode into account */ return (0); @@ -674,7 +675,10 @@ at91_usart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) case UART_IOCTL_OFLOW: break; case UART_IOCTL_BAUD: - WR4(&sc->sc_bas, USART_BRGR, BAUD2DIVISOR(*(int *)data)); + /* only if we know our master clock rate */ + if (DEFAULT_RCLK != 0) + WR4(&sc->sc_bas, USART_BRGR, + BAUD2DIVISOR(*(int *)data)); return (0); } return (EINVAL); diff --git a/sys/arm/conf/DOCKSTAR b/sys/arm/conf/DOCKSTAR new file mode 100644 index 00000000000..780cb78d4d6 --- /dev/null +++ b/sys/arm/conf/DOCKSTAR @@ -0,0 +1,76 @@ +# +# Custom kernel for Seagate DockStar (Marvell SheevaPlug based) devices. +# +# $FreeBSD$ +# + +ident DOCKSTAR +include "../mv/kirkwood/std.sheevaplug" + +options SOC_MV_KIRKWOOD +makeoptions MODULES_OVERRIDE="" + +#makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +makeoptions WERROR="-Werror" + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options FFS #Berkeley Fast Filesystem +options NFSCLIENT #Network Filesystem Client +options NFSLOCKD #Network Lock Manager +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options BOOTP +options BOOTP_NFSROOT +options BOOTP_NFSV3 +options BOOTP_COMPAT +options BOOTP_WIRED_TO=mge0 + +# Root fs on USB device +#options ROOTDEVNAME=\"ufs:/dev/da0a\" + +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +options MUTEX_NOINLINE +options RWLOCK_NOINLINE +options NO_FFS_SNAPSHOT +options NO_SWAPPING + +# Debugging +options ALT_BREAK_TO_DEBUGGER +options DDB +options KDB + +# Pseudo devices +device md +device random +device pty +device loop + +# Serial ports +device uart + +# Networking +device ether +device mge # Marvell Gigabit Ethernet controller +device mii +device bpf +options HZ=1000 +options DEVICE_POLLING +device vlan + +# USB +options USB_DEBUG # enable debug msgs +device usb +device ehci +device umass +device scbus +device pass +device da + +# Flattened Device Tree +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=dockstar.dts diff --git a/sys/arm/conf/QILA9G20 b/sys/arm/conf/QILA9G20 new file mode 100644 index 00000000000..55839cee1ad --- /dev/null +++ b/sys/arm/conf/QILA9G20 @@ -0,0 +1,153 @@ +# Kernel configuration for Calao Syatems QIL-A9G20 development card +# http://www.calao-systems.com +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident QILA9G20 + +include "../at91/std.qila9g20" + +#To statically compile in device wiring instead of /boot/device.hints +hints "QILA9G20.hints" +makeoptions MODULES_OVERRIDE="" + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options DDB +options KDB + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +#options INET6 #IPv6 communications protocols +options FFS #Berkeley Fast Filesystem +#options SOFTUPDATES #Enable FFS soft updates support +#options UFS_ACL #Support for access control lists +#options UFS_DIRHASH #Improve performance on big directories +#options MD_ROOT #MD is a potential root device +#options MD_ROOT_SIZE=4096 # 3MB ram disk +options NFSCLIENT #Network Filesystem Client +#options NFSSERVER #Network Filesystem Server +#options NFSLOCKD #Network Lock Manager +#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options BOOTP_NFSROOT +#options BOOTP +#options BOOTP_NFSV3 +#options BOOTP_WIRED_TO=ate0 +#options BOOTP_COMPAT + +options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" + +options ALT_BREAK_TO_DEBUGGER + +#options MSDOSFS #MSDOS Filesystem +#options CD9660 #ISO 9660 Filesystem +#options PROCFS #Process filesystem (requires PSEUDOFS) +#options PSEUDOFS #Pseudo-filesystem framework +#options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI +#options KTRACE #ktrace(1) support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +#options SYSCTL_OMIT_DESCR +options MUTEX_NOINLINE +options RWLOCK_NOINLINE +options NO_FFS_SNAPSHOT +options NO_SWAPPING + +# Debugging for use in -current +#options INVARIANTS #Enable calls of extra sanity checking +#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options DIAGNOSTIC + +device random +device pty +device loop +device bpf +device ether +device md + +device uart # Serial Ports + +# Ethernet +device ate # Ethernet Driver +#device macb # Alternate Ethernet driver +device mii +option AT91_ATE_USE_RMII + +device at91_twi # TWI: Two Wire Interface (EEPROM) +device at91_wdt # WDT: Watchdog timer + +# NOTE: SPI DataFlash and mci/mmc/mmcsd have hardware +# confilict on this card. Use one or the other. +# see board_sam9g20ek.c + +# SPI: Data Flash +#device at91_spi # SPI: +#device spibus +#device at45d # at45db642 and maybe others + +# MMC/SD +device at91_mci +device mmc +device mmcsd +option AT91_MCI_HAS_4WIRE + +# iic +device iic +device iicbus +device icee + +# SCSI peripherals +device scbus # SCSI bus (required for SCSI) +device da # Direct Access (disks) +device cd # CD +device pass # Passthrough device (direct SCSI access) + +# USB support +device ohci # OHCI localbus->USB interface +device usb # USB Bus (required) +device umass # Disks/Mass storage - Requires scbus and da +device uhid # "Human Interface Devices" +#device ulpt # Printer +#device udbp # USB Double Bulk Pipe devices + +# USB Ethernet, requires miibus +device miibus +#device aue # ADMtek USB Ethernet +#device axe # ASIX Electronics USB Ethernet +#device cdce # Generic USB over Ethernet +#device cue # CATC USB Ethernet +#device kue # Kawasaki LSI USB Ethernet +#device rue # RealTek RTL8150 USB Ethernet +device udav # Davicom DM9601E USB + +# USB Wireless +#device rum # Ralink Technology RT2501USB wireless NICs +#device uath # Atheros AR5523 wireless NICs +#device ural # Ralink Technology RT2500USB wireless NICs +#device zyd # ZyDAS zb1211/zb1211b wireless NICs + +# Wireless NIC cards +#device wlan # 802.11 support +#device wlan_wep # 802.11 WEP support +#device wlan_ccmp # 802.11 CCMP support +#device wlan_tkip # 802.11 TKIP support +#device wlan_amrr # AMRR transmit rate control algorithm + diff --git a/sys/arm/conf/QILA9G20.hints b/sys/arm/conf/QILA9G20.hints new file mode 100644 index 00000000000..cf391f5fa5d --- /dev/null +++ b/sys/arm/conf/QILA9G20.hints @@ -0,0 +1,9 @@ +# $FreeBSD$ +# Kernel configuration hits for Calao Syatems QIL-A9G20 development card +# http://www.calao-systems.com + +# STMicroelctrtronics M41T94 Real-Time Clock +# on SPI0 NPCS0 + +# STMicroelctrtronics M95640 8k x 8 EEPROM +# on SPI0 NPCS1 diff --git a/sys/arm/conf/SAM9G20EK b/sys/arm/conf/SAM9G20EK new file mode 100644 index 00000000000..6c2e94ef1cd --- /dev/null +++ b/sys/arm/conf/SAM9G20EK @@ -0,0 +1,153 @@ +# Kernel configuration for Atmel AT91SAM9G20EK Rev B. development card +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +ident SAM9G20EK + +include "../at91/std.sam9g20ek" + +#To statically compile in device wiring instead of /boot/device.hints +hints "SAM9G20EK.hints" +makeoptions MODULES_OVERRIDE="" + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options DDB +options KDB + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +#options INET6 #IPv6 communications protocols +options FFS #Berkeley Fast Filesystem +#options SOFTUPDATES #Enable FFS soft updates support +#options UFS_ACL #Support for access control lists +#options UFS_DIRHASH #Improve performance on big directories +#options MD_ROOT #MD is a potential root device +#options MD_ROOT_SIZE=4096 # 3MB ram disk +options NFSCLIENT #Network Filesystem Client +#options NFSSERVER #Network Filesystem Server +#options NFSLOCKD #Network Lock Manager +#options NFS_ROOT #NFS usable as /, requires NFSCLIENT +#options BOOTP_NFSROOT +#options BOOTP +#options BOOTP_NFSV3 +#options BOOTP_WIRED_TO=ate0 +#options BOOTP_COMPAT + +options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\" + +options ALT_BREAK_TO_DEBUGGER + +#options MSDOSFS #MSDOS Filesystem +#options CD9660 #ISO 9660 Filesystem +#options PROCFS #Process filesystem (requires PSEUDOFS) +#options PSEUDOFS #Pseudo-filesystem framework +#options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI +#options KTRACE #ktrace(1) support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions +#options SYSCTL_OMIT_DESCR +options MUTEX_NOINLINE +options RWLOCK_NOINLINE +options NO_FFS_SNAPSHOT +options NO_SWAPPING + +# Debugging for use in -current +#options INVARIANTS #Enable calls of extra sanity checking +#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed +#options DIAGNOSTIC + +device random +device pty +device loop +device bpf +device ether +device md + +device uart # Serial Ports + +# Ethernet +device ate # Ethernet Driver +#device macb # Alternate Ethernet driver +device mii +option AT91_ATE_USE_RMII + +device at91_twi # TWI: Two Wire Interface (EEPROM) +device at91_wdt # WDT: Watchdog timer + +# NOTE: SPI DataFlash and mci/mmc/mmcsd have hardware +# confilict on this card. Use one or the other. +# see board_sam9g20ek.c + +# SPI: Data Flash +#device at91_spi # SPI: +#device spibus +#device at45d # at45db642 and maybe others + +# MMC/SD +device at91_mci +device mmc +device mmcsd +option AT91_MCI_SLOT_B +option AT91_MCI_HAS_4WIRE + +# iic +device iic +device iicbus +device icee + +# SCSI peripherals +device scbus # SCSI bus (required for SCSI) +device da # Direct Access (disks) +device cd # CD +device pass # Passthrough device (direct SCSI access) + +# USB support +device ohci # OHCI localbus->USB interface +device usb # USB Bus (required) +device umass # Disks/Mass storage - Requires scbus and da +device uhid # "Human Interface Devices" +#device ulpt # Printer +#device udbp # USB Double Bulk Pipe devices + +# USB Ethernet, requires miibus +device miibus +#device aue # ADMtek USB Ethernet +#device axe # ASIX Electronics USB Ethernet +#device cdce # Generic USB over Ethernet +#device cue # CATC USB Ethernet +#device kue # Kawasaki LSI USB Ethernet +#device rue # RealTek RTL8150 USB Ethernet +device udav # Davicom DM9601E USB + +# USB Wireless +#device rum # Ralink Technology RT2501USB wireless NICs +#device uath # Atheros AR5523 wireless NICs +#device ural # Ralink Technology RT2500USB wireless NICs +#device zyd # ZyDAS zb1211/zb1211b wireless NICs + +# Wireless NIC cards +#device wlan # 802.11 support +#device wlan_wep # 802.11 WEP support +#device wlan_ccmp # 802.11 CCMP support +#device wlan_tkip # 802.11 TKIP support +#device wlan_amrr # AMRR transmit rate control algorithm + diff --git a/sys/arm/conf/SAM9G20EK.hints b/sys/arm/conf/SAM9G20EK.hints new file mode 100644 index 00000000000..166efdb5013 --- /dev/null +++ b/sys/arm/conf/SAM9G20EK.hints @@ -0,0 +1,10 @@ +# $FreeBSD$ +# + +# EEPROM +hint.icee.0.at="iicbus0" +hint.icee.0.addr=0xa0 +hint.icee.0.type=16 +hint.icee.0.size=65536 +hint.icee.0.rd_sz=256 +hint.icee.0.wr_sz=256 diff --git a/sys/arm/econa/if_ece.c b/sys/arm/econa/if_ece.c index 136860c4aa0..a7433f24215 100644 --- a/sys/arm/econa/if_ece.c +++ b/sys/arm/econa/if_ece.c @@ -353,10 +353,11 @@ ece_attach(device_t dev) } ece_set_mac(sc, eaddr); sc->ifp = ifp = if_alloc(IFT_ETHER); - if (mii_phy_probe(dev, &sc->miibus, ece_ifmedia_upd, - ece_ifmedia_sts)) { - device_printf(dev, "Cannot find my PHY.\n"); - err = ENXIO; + /* Only one PHY at address 0 in this device. */ + err = mii_attach(dev, &sc->miibus, ifp, ece_ifmedia_upd, + ece_ifmedia_sts, BMSR_DEFCAPMASK, 0, MII_OFFSET_ANY, 0); + if (err != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto out; } ifp->if_softc = sc; @@ -1904,9 +1905,6 @@ static int ece_miibus_readreg(device_t dev, int phy, int reg) { struct ece_softc *sc; - /* Only one phy in this device. */ - if (phy>0) - return (0); sc = device_get_softc(dev); return (phy_read(sc, phy, reg)); } diff --git a/sys/arm/include/cpufunc.h b/sys/arm/include/cpufunc.h index 4ab63fbe3fa..b06783650a0 100644 --- a/sys/arm/include/cpufunc.h +++ b/sys/arm/include/cpufunc.h @@ -400,6 +400,7 @@ extern unsigned arm10_dcache_index_max; extern unsigned arm10_dcache_index_inc; u_int sheeva_control_ext (u_int, u_int); +void sheeva_cpu_sleep (int); void sheeva_setttb (u_int); void sheeva_dcache_wbinv_range (vm_offset_t, vm_size_t); void sheeva_dcache_inv_range (vm_offset_t, vm_size_t); diff --git a/sys/arm/include/elf.h b/sys/arm/include/elf.h index 0660ba6bea6..4cb2ae35a0f 100644 --- a/sys/arm/include/elf.h +++ b/sys/arm/include/elf.h @@ -76,8 +76,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ #define R_ARM_COUNT 33 /* Count of defined relocation types. */ diff --git a/sys/arm/mv/mv_sata.c b/sys/arm/mv/mv_sata.c index 13ae1e01123..277c837ed23 100644 --- a/sys/arm/mv/mv_sata.c +++ b/sys/arm/mv/mv_sata.c @@ -710,7 +710,7 @@ sata_channel_status(device_t dev) if ((icr & SATA_ICR_DEV(ch->unit)) || iecr) { /* Disable EDMA before accessing SATA registers */ sata_edma_ctrl(dev, 0); - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); /* Ack device and error interrupt */ SATA_OUTL(sc, SATA_ICR, ~SATA_ICR_DEV(ch->unit)); diff --git a/sys/arm/mv/timer.c b/sys/arm/mv/timer.c index bcc4e81d1d8..fb3b321a689 100644 --- a/sys/arm/mv/timer.c +++ b/sys/arm/mv/timer.c @@ -178,14 +178,14 @@ mv_hardclock(void *arg) struct mv_timer_softc *sc; uint32_t irq_cause; - sc = (struct mv_timer_softc *)arg; - if (sc->et.et_active) - sc->et.et_event_cb(&sc->et, sc->et.et_arg); - irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE); irq_cause &= ~(IRQ_TIMER0); write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause); + sc = (struct mv_timer_softc *)arg; + if (sc->et.et_active) + sc->et.et_event_cb(&sc->et, sc->et.et_arg); + return (FILTER_HANDLED); } @@ -394,6 +394,8 @@ mv_timer_start(struct eventtimer *et, val |= CPU_TIMER0_EN; if (period != NULL) val |= CPU_TIMER0_AUTO; + else + val &= ~CPU_TIMER0_AUTO; mv_set_timer_control(val); return (0); } diff --git a/sys/arm/xscale/ixp425/if_npe.c b/sys/arm/xscale/ixp425/if_npe.c index 3d8d670eec9..d4a1f10268e 100644 --- a/sys/arm/xscale/ixp425/if_npe.c +++ b/sys/arm/xscale/ixp425/if_npe.c @@ -137,7 +137,6 @@ struct npe_softc { int rx_freeqid; /* rx free buffers qid */ int tx_qid; /* tx qid */ int tx_doneqid; /* tx completed qid */ - int sc_phy; /* PHY id */ struct ifmib_iso_8802_3 mibdata; bus_dma_tag_t sc_stats_tag; /* bus dma tag for stats block */ struct npestats *sc_stats; @@ -668,7 +667,7 @@ static int npe_activate(device_t dev) { struct npe_softc *sc = device_get_softc(dev); - int error, i, macbase, miibase; + int error, i, macbase, miibase, phy; /* * Setup NEP ID, MAC, and MII bindings. We allow override @@ -693,8 +692,8 @@ npe_activate(device_t dev) } /* PHY */ - if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1)) - sc->sc_phy = npeconfig[sc->sc_npeid].phy; + if (!override_unit(dev, "phy", &phy, 0, MII_NPHY - 1)) + phy = npeconfig[sc->sc_npeid].phy; if (!override_addr(dev, "mii", &miibase)) miibase = npeconfig[sc->sc_npeid].miibase; device_printf(sc->sc_dev, "MII at 0x%x\n", miibase); @@ -721,10 +720,12 @@ npe_activate(device_t dev) return error; } - /* probe for PHY */ - if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) { - device_printf(dev, "cannot find PHY %d.\n", sc->sc_phy); - return ENXIO; + /* attach PHY */ + error = mii_attach(dev, &sc->sc_mii, sc->sc_ifp, npe_ifmedia_update, + npe_ifmedia_status, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); + return error; } error = npe_dma_setup(sc, &sc->txdma, "tx", npe_txbuf, NPE_MAXSEG); @@ -1700,8 +1701,6 @@ npe_miibus_readreg(device_t dev, int phy, int reg) struct npe_softc *sc = device_get_softc(dev); uint32_t v; - if (phy != sc->sc_phy) /* XXX no auto-detect */ - return 0xffff; v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL) | NPE_MII_GO; npe_mii_mdio_write(sc, NPE_MAC_MDIO_CMD, v); if (npe_mii_mdio_wait(sc)) @@ -1717,8 +1716,6 @@ npe_miibus_writereg(device_t dev, int phy, int reg, int data) struct npe_softc *sc = device_get_softc(dev); uint32_t v; - if (phy != sc->sc_phy) /* XXX */ - return (0); v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL) | data | NPE_MII_WRITE | NPE_MII_GO; diff --git a/sys/arm/xscale/ixp425/ixp425.c b/sys/arm/xscale/ixp425/ixp425.c index ac70bcbd409..9b11b4339e2 100644 --- a/sys/arm/xscale/ixp425/ixp425.c +++ b/sys/arm/xscale/ixp425/ixp425.c @@ -369,7 +369,7 @@ ixp425_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -ixp425_add_child(device_t dev, int order, const char *name, int unit) +ixp425_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct ixp425_ivar *ivar; diff --git a/sys/boot/Makefile b/sys/boot/Makefile index b2eeb955470..6c879972f92 100644 --- a/sys/boot/Makefile +++ b/sys/boot/Makefile @@ -1,31 +1,13 @@ # $FreeBSD$ .include +.include .if ${MK_FORTH} != "no" # Build the add-in FORTH interpreter. SUBDIR+= ficl .endif -# Build EFI library. -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE} == "i386" || ${MACHINE_ARCH} == "ia64" -SUBDIR+= efi -.endif - -# Build Open Firmware library. -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" || ${MACHINE_ARCH} == "sparc64" -SUBDIR+= ofw -.endif - -# Build U-Boot library. -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" || ${MACHINE_ARCH} == "arm" -SUBDIR+= uboot -.endif - -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE} == "i386" -SUBDIR+= zfs -.endif - .if ${MK_FDT} != "no" SUBDIR+= fdt .endif diff --git a/sys/boot/Makefile.amd64 b/sys/boot/Makefile.amd64 new file mode 100644 index 00000000000..256201d4f94 --- /dev/null +++ b/sys/boot/Makefile.amd64 @@ -0,0 +1,4 @@ +# $FreeBSD$ + +SUBDIR+= efi +SUBDIR+= zfs diff --git a/sys/boot/Makefile.arm b/sys/boot/Makefile.arm new file mode 100644 index 00000000000..f96104db47c --- /dev/null +++ b/sys/boot/Makefile.arm @@ -0,0 +1,3 @@ +# $FreeBSD$ + +SUBDIR+= uboot diff --git a/sys/boot/Makefile.i386 b/sys/boot/Makefile.i386 new file mode 100644 index 00000000000..256201d4f94 --- /dev/null +++ b/sys/boot/Makefile.i386 @@ -0,0 +1,4 @@ +# $FreeBSD$ + +SUBDIR+= efi +SUBDIR+= zfs diff --git a/sys/boot/Makefile.ia64 b/sys/boot/Makefile.ia64 new file mode 100644 index 00000000000..921f2930d30 --- /dev/null +++ b/sys/boot/Makefile.ia64 @@ -0,0 +1,3 @@ +# $FreeBSD$ + +SUBDIR+= efi diff --git a/sys/boot/Makefile.pc98 b/sys/boot/Makefile.pc98 new file mode 100644 index 00000000000..aa989e1784b --- /dev/null +++ b/sys/boot/Makefile.pc98 @@ -0,0 +1,4 @@ +# $FreeBSD$ + +# Blank, to override Makefile.i386 since Makefile.$MACHINE is included before +# Makefile.$MACHINE_ARCH diff --git a/sys/boot/Makefile.powerpc b/sys/boot/Makefile.powerpc new file mode 100644 index 00000000000..ca8c33139b1 --- /dev/null +++ b/sys/boot/Makefile.powerpc @@ -0,0 +1,4 @@ +# $FreeBSD$ + +SUBDIR+= ofw +SUBDIR+= uboot diff --git a/sys/boot/Makefile.sparc64 b/sys/boot/Makefile.sparc64 new file mode 100644 index 00000000000..5723629ba47 --- /dev/null +++ b/sys/boot/Makefile.sparc64 @@ -0,0 +1,3 @@ +# $FreeBSD$ + +SUBDIR+= ofw diff --git a/sys/boot/arm/ixp425/boot2/Makefile b/sys/boot/arm/ixp425/boot2/Makefile index 138446b6fa2..a329b65c0db 100644 --- a/sys/boot/arm/ixp425/boot2/Makefile +++ b/sys/boot/arm/ixp425/boot2/Makefile @@ -20,7 +20,7 @@ NO_MAN= KERNPHYSADDR=0x180000 KERNVIRTADDR=${KERNPHYSADDR} BOOT_STACK=0x200000-4 -M=${MACHINE_ARCH} +M=${MACHINE} LDFLAGS=-e ${KERNPHYSADDR} -EB -T ldscript.${M} OBJS+= ${SRCS:N*.h:R:S/$/.o/g} S=${.CURDIR}/../../../.. diff --git a/sys/boot/arm/uboot/Makefile b/sys/boot/arm/uboot/Makefile index 573f9489f35..906fc871a88 100644 --- a/sys/boot/arm/uboot/Makefile +++ b/sys/boot/arm/uboot/Makefile @@ -77,7 +77,7 @@ CLEANFILES+= vers.c loader.help CFLAGS+= -ffreestanding -LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.arm +LDFLAGS= -nostdlib -static -T ${.CURDIR}/ldscript.${MACHINE_CPUARCH} # Pull in common loader code .PATH: ${.CURDIR}/../../uboot/common diff --git a/sys/boot/common/Makefile.inc b/sys/boot/common/Makefile.inc index 23f8fbf444d..989327839e7 100644 --- a/sys/boot/common/Makefile.inc +++ b/sys/boot/common/Makefile.inc @@ -4,19 +4,19 @@ SRCS+= boot.c commands.c console.c devopen.c interp.c SRCS+= interp_backslash.c interp_parse.c ls.c misc.c SRCS+= module.c panic.c -.if ${MACHINE} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE} == "i386" || ${MACHINE_CPUARCH} == "amd64" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c -.elif ${MACHINE} == "ia64" +.elif ${MACHINE_CPUARCH} == "ia64" SRCS+= load_elf64.c load_elf64_obj.c reloc_elf64.c .elif ${MACHINE} == "pc98" SRCS+= load_elf32.c load_elf32_obj.c reloc_elf32.c -.elif ${MACHINE_ARCH} == "arm" +.elif ${MACHINE_CPUARCH} == "arm" SRCS+= load_elf32.c reloc_elf32.c -.elif ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.elif ${MACHINE_CPUARCH} == "powerpc" SRCS+= load_elf32.c reloc_elf32.c SRCS+= load_elf64.c reloc_elf64.c -.elif ${MACHINE_ARCH} == "sparc64" +.elif ${MACHINE_CPUARCH} == "sparc64" SRCS+= load_elf64.c reloc_elf64.c .endif diff --git a/sys/boot/common/crc32.c b/sys/boot/common/crc32.c new file mode 100644 index 00000000000..032517993a4 --- /dev/null +++ b/sys/boot/common/crc32.c @@ -0,0 +1,108 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "crc32.h" + +static uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t +crc32(const void *buf, size_t size) +{ + const uint8_t *p = buf; + uint32_t crc; + + crc = ~0U; + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return (crc ^ ~0U); +} diff --git a/sys/boot/common/crc32.h b/sys/boot/common/crc32.h new file mode 100644 index 00000000000..adfd628671a --- /dev/null +++ b/sys/boot/common/crc32.h @@ -0,0 +1,13 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * $FreeBSD$ + */ + +#ifndef _CRC32_H_ +#define _CRC32_H_ + +uint32_t crc32(const void *buf, size_t size); + +#endif /* !_CRC32_H_ */ diff --git a/sys/boot/common/gpt.c b/sys/boot/common/gpt.c new file mode 100644 index 00000000000..9c0098008e3 --- /dev/null +++ b/sys/boot/common/gpt.c @@ -0,0 +1,381 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#ifndef LITTLE_ENDIAN +#error gpt.c works only for little endian architectures +#endif + +#include "crc32.h" +#include "drv.h" +#include "util.h" +#include "gpt.h" + +#define MAXTBLENTS 128 + +static struct gpt_hdr hdr_primary, hdr_backup, *gpthdr; +static uint64_t hdr_primary_lba, hdr_backup_lba; +static struct gpt_ent table_primary[MAXTBLENTS], table_backup[MAXTBLENTS]; +static struct gpt_ent *gpttable; +static int curent, bootonce; + +/* + * Buffer below 64kB passed on gptread(), which can hold at least + * one sector of data (512 bytes). + */ +static char *secbuf; + +static void +gptupdate(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + int entries_per_sec, firstent; + daddr_t slba; + + /* + * We need to update the following for both primary and backup GPT: + * 1. Sector on disk that contains current partition. + * 2. Partition table checksum. + * 3. Header checksum. + * 4. Header on disk. + */ + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = curent / entries_per_sec; + firstent = slba * entries_per_sec; + bcpy(&table[firstent], secbuf, DEV_BSIZE); + slba += hdr->hdr_lba_table; + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + return; + } + hdr->hdr_crc_table = crc32(table, hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcpy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) { + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); + return; + } +} + +int +gptfind(const uuid_t *uuid, struct dsk *dskp, int part) +{ + struct gpt_ent *ent; + int firsttry; + + if (part >= 0) { + if (part == 0 || part > gpthdr->hdr_entries) { + printf("%s: invalid partition index\n", BOOTPROG); + return (-1); + } + ent = &gpttable[part - 1]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) { + printf("%s: specified partition is not UFS\n", + BOOTPROG); + return (-1); + } + curent = part - 1; + goto found; + } + + firsttry = (curent == -1); + curent++; + if (curent >= gpthdr->hdr_entries) { + curent = gpthdr->hdr_entries; + return (-1); + } + if (bootonce) { + /* + * First look for partition with both GPT_ENT_ATTR_BOOTME and + * GPT_ENT_ATTR_BOOTONCE flags. + */ + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTONCE)) + continue; + /* Ok, found one. */ + goto found; + } + bootonce = 0; + curent = 0; + } + for (; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + if (!(ent->ent_attr & GPT_ENT_ATTR_BOOTME)) + continue; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) + continue; + /* Ok, found one. */ + goto found; + } + if (firsttry) { + /* + * No partition with BOOTME flag was found, try to boot from + * first UFS partition. + */ + for (curent = 0; curent < gpthdr->hdr_entries; curent++) { + ent = &gpttable[curent]; + if (bcmp(&ent->ent_type, uuid, sizeof(uuid_t)) != 0) + continue; + /* Ok, found one. */ + goto found; + } + } + return (-1); +found: + dskp->part = curent + 1; + ent = &gpttable[curent]; + dskp->start = ent->ent_lba_start; + if (ent->ent_attr & GPT_ENT_ATTR_BOOTONCE) { + /* + * Clear BOOTME, but leave BOOTONCE set before trying to + * boot from this partition. + */ + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTME; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } + } + return (0); +} + +static int +gptread_hdr(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + uint64_t hdrlba) +{ + uint32_t crc; + + if (drvread(dskp, secbuf, hdrlba, 1)) { + printf("%s: unable to read %s GPT header\n", BOOTPROG, which); + return (-1); + } + bcpy(secbuf, hdr, sizeof(*hdr)); + if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 || + hdr->hdr_lba_self != hdrlba || hdr->hdr_revision < 0x00010000 || + hdr->hdr_entsz < sizeof(struct gpt_ent) || + hdr->hdr_entries > MAXTBLENTS || DEV_BSIZE % hdr->hdr_entsz != 0) { + printf("%s: invalid %s GPT header\n", BOOTPROG, which); + return (-1); + } + crc = hdr->hdr_crc_self; + hdr->hdr_crc_self = 0; + if (crc32(hdr, hdr->hdr_size) != crc) { + printf("%s: %s GPT header checksum mismatch\n", BOOTPROG, + which); + return (-1); + } + hdr->hdr_crc_self = crc; + return (0); +} + +void +gptbootfailed(struct dsk *dskp) +{ + + if (!(gpttable[curent].ent_attr & GPT_ENT_ATTR_BOOTONCE)) + return; + + if (hdr_primary_lba > 0) { + table_primary[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_primary[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("primary", dskp, &hdr_primary, table_primary); + } + if (hdr_backup_lba > 0) { + table_backup[curent].ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + table_backup[curent].ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + gptupdate("backup", dskp, &hdr_backup, table_backup); + } +} + +static void +gptbootconv(const char *which, struct dsk *dskp, struct gpt_hdr *hdr, + struct gpt_ent *table) +{ + struct gpt_ent *ent; + daddr_t slba; + int table_updated, sector_updated; + int entries_per_sec, nent, part; + + table_updated = 0; + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + for (nent = 0, slba = hdr->hdr_lba_table; + slba < hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; + slba++, nent += entries_per_sec) { + sector_updated = 0; + for (part = 0; part < entries_per_sec; part++) { + ent = &table[nent + part]; + if ((ent->ent_attr & (GPT_ENT_ATTR_BOOTME | + GPT_ENT_ATTR_BOOTONCE | + GPT_ENT_ATTR_BOOTFAILED)) != + GPT_ENT_ATTR_BOOTONCE) { + continue; + } + ent->ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + ent->ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + table_updated = 1; + sector_updated = 1; + } + if (!sector_updated) + continue; + bcpy(&table[nent], secbuf, DEV_BSIZE); + if (drvwrite(dskp, secbuf, slba, 1)) { + printf("%s: unable to update %s GPT partition table\n", + BOOTPROG, which); + } + } + if (!table_updated) + return; + hdr->hdr_crc_table = crc32(table, hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + bzero(secbuf, DEV_BSIZE); + bcpy(hdr, secbuf, hdr->hdr_size); + if (drvwrite(dskp, secbuf, hdr->hdr_lba_self, 1)) + printf("%s: unable to update %s GPT header\n", BOOTPROG, which); +} + +static int +gptread_table(const char *which, const uuid_t *uuid, struct dsk *dskp, + struct gpt_hdr *hdr, struct gpt_ent *table) +{ + struct gpt_ent *ent; + int entries_per_sec; + int part, nent; + daddr_t slba; + + if (hdr->hdr_entries == 0) + return (0); + + entries_per_sec = DEV_BSIZE / hdr->hdr_entsz; + slba = hdr->hdr_lba_table; + nent = 0; + for (;;) { + if (drvread(dskp, secbuf, slba, 1)) { + printf("%s: unable to read %s GPT partition table\n", + BOOTPROG, which); + return (-1); + } + ent = (struct gpt_ent *)secbuf; + for (part = 0; part < entries_per_sec; part++, ent++) { + bcpy(ent, &table[nent], sizeof(table[nent])); + if (++nent >= hdr->hdr_entries) + break; + } + if (nent >= hdr->hdr_entries) + break; + slba++; + } + if (crc32(table, nent * hdr->hdr_entsz) != hdr->hdr_crc_table) { + printf("%s: %s GPT table checksum mismatch\n", BOOTPROG, which); + return (-1); + } + return (0); +} + +int +gptread(const uuid_t *uuid, struct dsk *dskp, char *buf) +{ + uint64_t altlba; + + /* + * Read and verify both GPT headers: primary and backup. + */ + + secbuf = buf; + hdr_primary_lba = hdr_backup_lba = 0; + curent = -1; + bootonce = 1; + dskp->start = 0; + + if (gptread_hdr("primary", dskp, &hdr_primary, 1) == 0 && + gptread_table("primary", uuid, dskp, &hdr_primary, + table_primary) == 0) { + hdr_primary_lba = hdr_primary.hdr_lba_self; + gpthdr = &hdr_primary; + gpttable = table_primary; + } + + altlba = drvsize(dskp); + if (altlba > 0) + altlba--; + else if (hdr_primary_lba > 0) { + /* + * If we cannot obtain disk size, but primary header + * is valid, we can get backup header location from + * there. + */ + altlba = hdr_primary.hdr_lba_alt; + } + if (altlba == 0) + printf("%s: unable to locate backup GPT header\n", BOOTPROG); + else if (gptread_hdr("backup", dskp, &hdr_backup, altlba) == 0 && + gptread_table("backup", uuid, dskp, &hdr_backup, + table_backup) == 0) { + hdr_backup_lba = hdr_backup.hdr_lba_self; + if (hdr_primary_lba == 0) { + gpthdr = &hdr_backup; + gpttable = table_backup; + printf("%s: using backup GPT\n", BOOTPROG); + } + } + + /* + * Convert all BOOTONCE without BOOTME flags into BOOTFAILED. + * BOOTONCE without BOOTME means that we tried to boot from it, + * but failed after leaving gptboot and machine was rebooted. + * We don't want to leave partitions marked as BOOTONCE only, + * because when we boot successfully start-up scripts should + * find at most one partition with only BOOTONCE flag and this + * will mean that we booted from that partition. + */ + if (hdr_primary_lba != 0) + gptbootconv("primary", dskp, &hdr_primary, table_primary); + if (hdr_backup_lba != 0) + gptbootconv("backup", dskp, &hdr_backup, table_backup); + + if (hdr_primary_lba == 0 && hdr_backup_lba == 0) + return (-1); + return (0); +} diff --git a/sys/boot/common/gpt.h b/sys/boot/common/gpt.h new file mode 100644 index 00000000000..c42b40de8a3 --- /dev/null +++ b/sys/boot/common/gpt.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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$ + */ + +#ifndef _GPT_H_ +#define _GPT_H_ + +#include +#include + +int gptread(const uuid_t *uuid, struct dsk *dskp, char *buf); +int gptfind(const uuid_t *uuid, struct dsk *dskp, int part); +void gptbootfailed(struct dsk *dskp); + +#endif /* !_GPT_H_ */ diff --git a/sys/boot/common/loader.8 b/sys/boot/common/loader.8 index 2490e3dcdbe..7ccd184a6aa 100644 --- a/sys/boot/common/loader.8 +++ b/sys/boot/common/loader.8 @@ -643,7 +643,6 @@ by it as arguments, and it is processed by a special parser which is not used for regular Forth commands. .Pp This special parser applies the following rules to the parsed text: -.Pp .Bl -enum .It All backslash characters are preprocessed. diff --git a/sys/boot/common/ufsread.c b/sys/boot/common/ufsread.c index cd3ba4c5d12..5d0e8af56b8 100644 --- a/sys/boot/common/ufsread.c +++ b/sys/boot/common/ufsread.c @@ -223,14 +223,19 @@ fsread(ino_t inode, void *buf, size_t nbyte) return -1; n = INO_TO_VBO(n, inode); #if defined(UFS1_ONLY) - dp1 = ((struct ufs1_dinode *)blkbuf)[n]; + memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, + sizeof(struct ufs1_dinode)); #elif defined(UFS2_ONLY) - dp2 = ((struct ufs2_dinode *)blkbuf)[n]; + memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, + sizeof(struct ufs2_dinode)); #else if (fs->fs_magic == FS_UFS1_MAGIC) - dp1 = ((struct ufs1_dinode *)blkbuf)[n]; + memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, + sizeof(struct ufs1_dinode)); else - dp2 = ((struct ufs2_dinode *)blkbuf)[n]; + memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, + sizeof(struct ufs2_dinode)); + #endif inomap = inode; fs_off = 0; diff --git a/sys/boot/common/util.c b/sys/boot/common/util.c new file mode 100644 index 00000000000..012106aef8a --- /dev/null +++ b/sys/boot/common/util.c @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * Copyright (c) 2010 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include "cons.h" +#include "util.h" + +void +memcpy(void *dst, const void *src, int len) +{ + const char *s = src; + char *d = dst; + + while (len--) + *d++ = *s++; +} + +void +memset(void *b, int c, size_t len) +{ + char *bp = b; + + while (len--) + *bp++ = (unsigned char)c; +} + +int +memcmp(const void *b1, const void *b2, size_t len) +{ + const unsigned char *p1, *p2; + + for (p1 = b1, p2 = b2; len > 0; len--, p1++, p2++) { + if (*p1 != *p2) + return ((*p1) - (*p2)); + } + return (0); +} + +int +strcmp(const char *s1, const char *s2) +{ + + for (; *s1 == *s2 && *s1 != '\0'; s1++, s2++) + ; + return ((unsigned char)*s1 - (unsigned char)*s2); +} + +int +strncmp(const char *s1, const char *s2, size_t len) +{ + + for (; *s1 == *s2 && *s1 != '\0' && len > 0; len--, s1++, s2++) + ; + return ((unsigned char)*s1 - (unsigned char)*s2); +} + +void +strcpy(char *dst, const char *src) +{ + + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +void +strcat(char *dst, const char *src) +{ + + while (*dst != '\0') + dst++; + while (*src != '\0') + *dst++ = *src++; + *dst = '\0'; +} + +char * +strchr(const char *s, char ch) +{ + + for (; *s != '\0'; s++) { + if (*s == ch) + return ((char *)(uintptr_t)(const void *)s); + } + return (NULL); +} + +size_t +strlen(const char *s) +{ + size_t len = 0; + + while (*s++ != '\0') + len++; + return (len); +} + +void +printf(const char *fmt, ...) +{ + va_list ap; + const char *hex = "0123456789abcdef"; + char buf[10], *s; + unsigned long long u; + int c, l; + + va_start(ap, fmt); + while ((c = *fmt++) != '\0') { + if (c != '%') { + putchar(c); + continue; + } + l = 0; +nextfmt: + c = *fmt++; + switch (c) { + case 'l': + l++; + goto nextfmt; + case 'c': + putchar(va_arg(ap, int)); + break; + case 's': + for (s = va_arg(ap, char *); *s != '\0'; s++) + putchar(*s); + break; + case 'd': /* A lie, always prints unsigned */ + case 'u': + case 'x': + switch (l) { + case 2: + u = va_arg(ap, unsigned long long); + break; + case 1: + u = va_arg(ap, unsigned long); + break; + default: + u = va_arg(ap, unsigned int); + break; + } + s = buf; + if (c == 'd' || c == 'u') { + do + *s++ = '0' + (u % 10U); + while (u /= 10); + } else { + do + *s++ = hex[u & 0xfu]; + while (u >>= 4); + } + while (--s >= buf) + putchar(*s); + break; + } + } + va_end(ap); +} diff --git a/sys/boot/common/util.h b/sys/boot/common/util.h new file mode 100644 index 00000000000..600c4e04c67 --- /dev/null +++ b/sys/boot/common/util.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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$ + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include + +#include + +void memcpy(void *dst, const void *src, int len); +void memset(void *b, int c, size_t len); +int memcmp(const void *b1, const void *b2, size_t len); + +#define bcpy(src, dst, len) memcpy((dst), (src), (len)) +#define bzero(buf, size) memset((buf), 0, (size)) +#define bcmp(b1, b2, len) (memcmp((b1), (b2), (len)) != 0) + +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t len); +void strcpy(char *dst, const char *src); +void strcat(char *dst, const char *src); +char *strchr(const char *s, char ch); +size_t strlen(const char *s); + +void printf(const char *fmt, ...); + +#endif /* !_UTIL_H_ */ diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile index 55053e1042f..beb9269d0a2 100644 --- a/sys/boot/efi/libefi/Makefile +++ b/sys/boot/efi/libefi/Makefile @@ -7,7 +7,7 @@ SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \ libefi.c time.c CFLAGS+= -I${.CURDIR}/../include -CFLAGS+= -I${.CURDIR}/../include/${MACHINE_ARCH:S/amd64/i386/} +CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH:S/amd64/i386/} CFLAGS+= -I${.CURDIR}/../../../../lib/libstand # Pick up the bootstrap header for some interface items diff --git a/sys/boot/fdt/dts/dockstar.dts b/sys/boot/fdt/dts/dockstar.dts new file mode 100644 index 00000000000..46981094e5d --- /dev/null +++ b/sys/boot/fdt/dts/dockstar.dts @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Semihalf under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Seagate DockStar (Marvell SheevaPlug based) Device Tree Source. + * + * $FreeBSD$ + */ + +/dts-v1/; + +/ { + model = "seagate,DockStar"; + compatible = "DockStar"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + ethernet0 = &enet0; + mpp = &MPP; + serial0 = &serial0; + serial1 = &serial1; + soc = &SOC; + sram = &SRAM; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "ARM,88FR131"; + reg = <0x0>; + d-cache-line-size = <32>; // 32 bytes + i-cache-line-size = <32>; // 32 bytes + d-cache-size = <0x4000>; // L1, 16K + i-cache-size = <0x4000>; // L1, 16K + timebase-frequency = <0>; + bus-frequency = <0>; + clock-frequency = <0>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x8000000>; // 128M at 0x0 + }; + + localbus@f1000000 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "mrvl,lbc"; + + /* This reflects CPU decode windows setup. */ + ranges = <0x0 0x0f 0xf9300000 0x00100000 + 0x1 0x1e 0xfa000000 0x00100000 + 0x2 0x1d 0xfa100000 0x02000000 + 0x3 0x1b 0xfc100000 0x00000400>; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x00100000>; + bank-width = <2>; + device-width = <1>; + }; + + led@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "led"; + reg = <0x1 0x0 0x00100000>; + }; + + nor@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x2 0x0 0x02000000>; + bank-width = <2>; + device-width = <1>; + }; + + nand@3,0 { + #address-cells = <1>; + #size-cells = <1>; + reg = <0x3 0x0 0x00100000>; + bank-width = <2>; + device-width = <1>; + }; + }; + + SOC: soc88f6281@f1000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0xf1000000 0x00100000>; + bus-frequency = <0>; + + PIC: pic@20200 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0x20200 0x3c>; + compatible = "mrvl,pic"; + }; + + timer@20300 { + compatible = "mrvl,timer"; + reg = <0x20300 0x30>; + interrupts = <1>; + interrupt-parent = <&PIC>; + mrvl,has-wdt; + }; + + MPP: mpp@10000 { + #pin-cells = <2>; + compatible = "mrvl,mpp"; + reg = <0x10000 0x34>; + pin-count = <50>; + pin-map = < + 0 1 /* MPP[0]: NF_IO[2] */ + 1 1 /* MPP[1]: NF_IO[3] */ + 2 1 /* MPP[2]: NF_IO[4] */ + 3 1 /* MPP[3]: NF_IO[5] */ + 4 1 /* MPP[4]: NF_IO[6] */ + 5 1 /* MPP[5]: NF_IO[7] */ + 6 1 /* MPP[6]: SYSRST_OUTn */ + 8 2 /* MPP[8]: UA0_RTS */ + 9 2 /* MPP[9]: UA0_CTS */ + 10 3 /* MPP[10]: UA0_TXD */ + 11 3 /* MPP[11]: UA0_RXD */ + 12 1 /* MPP[12]: SD_CLK */ + 13 1 /* MPP[13]: SD_CMD */ + 14 1 /* MPP[14]: SD_D[0] */ + 15 1 /* MPP[15]: SD_D[1] */ + 16 1 /* MPP[16]: SD_D[2] */ + 17 1 /* MPP[17]: SD_D[3] */ + 18 1 /* MPP[18]: NF_IO[0] */ + 19 1 /* MPP[19]: NF_IO[1] */ + 29 1 >; /* MPP[29]: TSMP[9] */ + }; + + GPIO: gpio@10100 { + #gpio-cells = <3>; + compatible = "mrvl,gpio"; + reg = <0x10100 0x20>; + gpio-controller; + interrupts = <35 36 37 38 39 40 41>; + interrupt-parent = <&PIC>; + }; + + rtc@10300 { + compatible = "mrvl,rtc"; + reg = <0x10300 0x08>; + }; + + twsi@11000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "mrvl,twsi"; + reg = <0x11000 0x20>; + interrupts = <43>; + interrupt-parent = <&PIC>; + }; + + enet0: ethernet@72000 { + #address-cells = <1>; + #size-cells = <1>; + model = "V2"; + compatible = "mrvl,ge"; + reg = <0x72000 0x2000>; + ranges = <0x0 0x72000 0x2000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <12 13 14 11 46>; + interrupt-parent = <&PIC>; + phy-handle = <&phy0>; + + mdio@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "mrvl,mdio"; + + phy0: ethernet-phy@0 { + reg = <0x0>; + }; + }; + }; + + serial0: serial@12000 { + compatible = "ns16550"; + reg = <0x12000 0x20>; + reg-shift = <2>; + clock-frequency = <0>; + interrupts = <33>; + interrupt-parent = <&PIC>; + }; + + serial1: serial@12100 { + compatible = "ns16550"; + reg = <0x12100 0x20>; + reg-shift = <2>; + clock-frequency = <0>; + interrupts = <34>; + interrupt-parent = <&PIC>; + }; + + crypto@30000 { + compatible = "mrvl,cesa"; + reg = <0x30000 0x10000>; + interrupts = <22>; + interrupt-parent = <&PIC>; + }; + + usb@50000 { + compatible = "mrvl,usb-ehci", "usb-ehci"; + reg = <0x50000 0x1000>; + interrupts = <48 19>; + interrupt-parent = <&PIC>; + }; + + xor@60000 { + compatible = "mrvl,xor"; + reg = <0x60000 0x1000>; + interrupts = <5 6 7 8>; + interrupt-parent = <&PIC>; + }; + }; + + SRAM: sram@fd000000 { + compatible = "mrvl,cesa-sram"; + reg = <0xfd000000 0x00100000>; + }; + + chosen { + stdin = "serial0"; + stdout = "serial0"; + }; +}; diff --git a/sys/boot/ficl/Makefile b/sys/boot/ficl/Makefile index cdc8f7eddee..61760d00328 100644 --- a/sys/boot/ficl/Makefile +++ b/sys/boot/ficl/Makefile @@ -1,20 +1,20 @@ # $FreeBSD$ # -.PATH: ${.CURDIR}/${MACHINE_ARCH:S/amd64/i386/:S/powerpc64/powerpc/} +.PATH: ${.CURDIR}/${MACHINE_CPUARCH:S/amd64/i386/} BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \ prefix.c search.c stack.c tools.c vm.c words.c SRCS= ${BASE_SRCS} sysdep.c softcore.c CLEANFILES= softcore.c testmain testmain.o CFLAGS+= -ffreestanding -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -mpreferred-stack-boundary=2 CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" CFLAGS+= -mno-sse3 .endif -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" || ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" CFLAGS+= -msoft-float .endif .if ${MACHINE} == "pc98" @@ -41,7 +41,7 @@ SOFTWORDS= softcore.fr jhlocal.fr marker.fr freebsd.fr ficllocal.fr \ # Optional OO extension softwords #SOFTWORDS+= oo.fr classes.fr -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -m32 -march=i386 -I. .endif @@ -49,14 +49,14 @@ CFLAGS+= -m32 -march=i386 -I. CFLAGS+= -m32 -mcpu=powerpc -I. .endif -CFLAGS+= -I${.CURDIR} -I${.CURDIR}/${MACHINE_ARCH:S/amd64/i386/:S/powerpc64/powerpc/} \ +CFLAGS+= -I${.CURDIR} -I${.CURDIR}/${MACHINE_CPUARCH:S/amd64/i386/} \ -I${.CURDIR}/../common softcore.c: ${SOFTWORDS} softcore.awk (cd ${.CURDIR}/softwords; cat ${SOFTWORDS} \ | awk -f softcore.awk -v datestamp="`LC_ALL=C date`") > ${.TARGET} -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" ${SRCS:M*.c:R:S/$/.o/g}: machine beforedepend ${OBJS}: machine diff --git a/sys/boot/forth/beastie.4th b/sys/boot/forth/beastie.4th index c726875907f..d96f5791e79 100644 --- a/sys/boot/forth/beastie.4th +++ b/sys/boot/forth/beastie.4th @@ -240,7 +240,10 @@ set-current drop 10 else - 0 0 2swap >number drop drop drop + 2dup s" -1" compare 0= if + 0 boot + then + 0 s>d 2swap >number 2drop drop then begin dup tkey diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf index eac8fe6886d..4f07b912178 100644 --- a/sys/boot/forth/loader.conf +++ b/sys/boot/forth/loader.conf @@ -473,6 +473,7 @@ vkbd_load="NO" # Virtual AT keyboard interface vpd_load="NO" # Vital Product Data kernel interface vpo_load="NO" # Parallel to SCSI interface driver amdtemp_load="NO" # AMD K8/K10/K11 temperature monitor +tpm_load="NO" # Trusted Platform Module ############################################################## ### ACPI settings ########################################## diff --git a/sys/boot/i386/Makefile.inc b/sys/boot/i386/Makefile.inc index 72c6395acf0..a25684012c9 100644 --- a/sys/boot/i386/Makefile.inc +++ b/sys/boot/i386/Makefile.inc @@ -9,7 +9,7 @@ CFLAGS+= -ffreestanding -mpreferred-stack-boundary=2 \ -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 LDFLAGS+= -nostdlib -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -m32 -march=i386 LDFLAGS+= -m elf_i386_fbsd AFLAGS+= --32 diff --git a/sys/boot/i386/boot2/Makefile b/sys/boot/i386/boot2/Makefile index ab5a69a8ba4..b91a43bccc4 100644 --- a/sys/boot/i386/boot2/Makefile +++ b/sys/boot/i386/boot2/Makefile @@ -1,5 +1,10 @@ # $FreeBSD$ +.include + +# XXX: clang can compile the boot code just fine, but boot2 gets too big +CC:=${CC:C/^(.*\/)?clang$/gcc/1} + FILES= boot boot1 boot2 NM?= nm @@ -94,7 +99,7 @@ boot2.h: boot1.out ORG1=`printf "%d" ${ORG1}` \ REL1=`printf "%d" ${REL1}` > ${.TARGET} -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend boot2.s: machine CLEANFILES+= machine machine: diff --git a/sys/boot/i386/boot2/boot2.c b/sys/boot/i386/boot2/boot2.c index f521fd7e071..307d4c5df08 100644 --- a/sys/boot/i386/boot2/boot2.c +++ b/sys/boot/i386/boot2/boot2.c @@ -348,7 +348,7 @@ load(void) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + *(uint32_t*)p = hdr.ex.a_syms; p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) @@ -385,7 +385,7 @@ load(void) if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) diff --git a/sys/boot/i386/common/cons.c b/sys/boot/i386/common/cons.c new file mode 100644 index 00000000000..56febf2037f --- /dev/null +++ b/sys/boot/i386/common/cons.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include + +#include "lib.h" +#include "rbx.h" +#include "util.h" +#include "cons.h" + +#define V86_ZR(x) ((x) & PSL_Z) + +#define SECOND 18 /* Circa that many ticks in a second. */ + +uint8_t ioctrl = IO_KEYBOARD; + +void +putc(int c) +{ + + v86.addr = 0x10; + v86.eax = 0xe00 | (c & 0xff); + v86.ebx = 0x7; + v86int(); +} + +void +xputc(int c) +{ + + if (ioctrl & IO_KEYBOARD) + putc(c); + if (ioctrl & IO_SERIAL) + sio_putc(c); +} + +void +putchar(int c) +{ + + if (c == '\n') + xputc('\r'); + xputc(c); +} + +int +getc(int fn) +{ + + /* + * The extra comparison against zero is an attempt to work around + * what appears to be a bug in QEMU and Bochs. Both emulators + * sometimes report a key-press with scancode one and ascii zero + * when no such key is pressed in reality. As far as I can tell, + * this only happens shortly after a reboot. + */ + v86.ctl = V86_FLAGS; + v86.addr = 0x16; + v86.eax = fn << 8; + v86int(); + return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff)); +} + +int +xgetc(int fn) +{ + + if (OPT_CHECK(RBX_NOINTR)) + return (0); + for (;;) { + if (ioctrl & IO_KEYBOARD && getc(1)) + return (fn ? 1 : getc(0)); + if (ioctrl & IO_SERIAL && sio_ischar()) + return (fn ? 1 : sio_getc()); + if (fn) + return (0); + } + /* NOTREACHED */ +} + +int +keyhit(unsigned int secs) +{ + uint32_t t0, t1; + + if (OPT_CHECK(RBX_NOINTR)) + return (0); + secs *= SECOND; + t0 = 0; + for (;;) { + if (xgetc(1)) + return (1); + if (secs > 0) { + t1 = *(uint32_t *)PTOV(0x46c); + if (!t0) + t0 = t1; + if (t1 < t0 || t1 >= t0 + secs) + return (0); + } + } + /* NOTREACHED */ +} + +void +getstr(char *cmdstr, size_t cmdstrsize) +{ + char *s; + int c; + + s = cmdstr; + for (;;) { + switch (c = xgetc(0)) { + case 0: + break; + case '\177': + case '\b': + if (s > cmdstr) { + s--; + printf("\b \b"); + } + break; + case '\n': + case '\r': + *s = 0; + return; + default: + if (s - cmdstr < cmdstrsize - 1) + *s++ = c; + putchar(c); + break; + } + } +} diff --git a/sys/boot/i386/common/cons.h b/sys/boot/i386/common/cons.h new file mode 100644 index 00000000000..fe00a13e717 --- /dev/null +++ b/sys/boot/i386/common/cons.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#ifndef _CONS_H_ +#define _CONS_H_ + +#define IO_KEYBOARD 1 +#define IO_SERIAL 2 + +extern uint8_t ioctrl; + +void putc(int c); +void xputc(int c); +void putchar(int c); +int getc(int fn); +int xgetc(int fn); +int keyhit(unsigned int secs); +void getstr(char *cmdstr, size_t cmdstrsize); + +#endif /* !_CONS_H_ */ diff --git a/sys/boot/i386/common/drv.c b/sys/boot/i386/common/drv.c new file mode 100644 index 00000000000..d249bc18640 --- /dev/null +++ b/sys/boot/i386/common/drv.c @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * Copyright (c) 2010 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include + +#include "rbx.h" +#include "util.h" +#include "drv.h" +#ifndef GPT +#include "xreadorg.h" +#endif + +#define V86_CY(x) ((x) & PSL_C) +#define V86_ZR(x) ((x) & PSL_Z) + +#ifdef GPT +uint64_t +drvsize(struct dsk *dskp) +{ + unsigned char params[0x42]; + uint64_t sectors; + + *(uint32_t *)params = sizeof(params); + + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4800; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(params); + v86.esi = VTOPOFF(params); + v86int(); + if (V86_CY(v86.efl)) { + printf("error %u\n", v86.eax >> 8 & 0xff); + return (0); + } + memcpy(§ors, params + 0x10, sizeof(sectors)); + return (sectors); +} +#endif /* GPT */ + +#ifdef GPT +static struct { + uint16_t len; + uint16_t count; + uint16_t off; + uint16_t seg; + uint64_t lba; +} packet; +#endif /* GPT */ + +int +drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + static unsigned c = 0x2d5c7c2f; + + if (!OPT_CHECK(RBX_QUIET)) + printf("%c\b", c = c << 8 | c >> 24); +#ifdef GPT + packet.len = 0x10; + packet.count = nblk; + packet.off = VTOPOFF(buf); + packet.seg = VTOPSEG(buf); + packet.lba = lba; + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4200; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(&packet); + v86.esi = VTOPOFF(&packet); +#else /* !GPT */ + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = XREADORG; /* call to xread in boot1 */ + v86.es = VTOPSEG(buf); + v86.eax = lba; + v86.ebx = VTOPOFF(buf); + v86.ecx = lba >> 32; + v86.edx = nblk << 8 | dskp->drive; +#endif /* !GPT */ + v86int(); + if (V86_CY(v86.efl)) { + printf("%s: error %u lba %u\n", + BOOTPROG, v86.eax >> 8 & 0xff, lba); + return (-1); + } + return (0); +} + +#ifdef GPT +int +drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk) +{ + + packet.len = 0x10; + packet.count = nblk; + packet.off = VTOPOFF(buf); + packet.seg = VTOPSEG(buf); + packet.lba = lba; + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x4300; + v86.edx = dskp->drive; + v86.ds = VTOPSEG(&packet); + v86.esi = VTOPOFF(&packet); + v86int(); + if (V86_CY(v86.efl)) { + printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); + return (-1); + } + return (0); +} +#endif /* GPT */ diff --git a/sys/boot/i386/common/drv.h b/sys/boot/i386/common/drv.h new file mode 100644 index 00000000000..1ecfbc3af9e --- /dev/null +++ b/sys/boot/i386/common/drv.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2010 Pawel Jakub Dawidek + * 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$ + */ + +#ifndef _DRV_H_ +#define _DRV_H_ + +struct dsk { + unsigned int drive; + unsigned int type; + unsigned int unit; + unsigned int slice; + int part; + daddr_t start; + int init; +}; + +int drvread(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +#ifdef GPT +int drvwrite(struct dsk *dskp, void *buf, daddr_t lba, unsigned nblk); +uint64_t drvsize(struct dsk *dskp); +#endif /* GPT */ + +#endif /* !_DRV_H_ */ diff --git a/sys/boot/i386/common/rbx.h b/sys/boot/i386/common/rbx.h new file mode 100644 index 00000000000..21371a56380 --- /dev/null +++ b/sys/boot/i386/common/rbx.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + * + * $FreeBSD$ + */ + +#ifndef _RBX_H_ +#define _RBX_H_ + +#define RBX_ASKNAME 0x0 /* -a */ +#define RBX_SINGLE 0x1 /* -s */ +/* 0x2 is reserved for log2(RB_NOSYNC). */ +/* 0x3 is reserved for log2(RB_HALT). */ +/* 0x4 is reserved for log2(RB_INITNAME). */ +#define RBX_DFLTROOT 0x5 /* -r */ +#define RBX_KDB 0x6 /* -d */ +/* 0x7 is reserved for log2(RB_RDONLY). */ +/* 0x8 is reserved for log2(RB_DUMP). */ +/* 0x9 is reserved for log2(RB_MINIROOT). */ +#define RBX_CONFIG 0xa /* -c */ +#define RBX_VERBOSE 0xb /* -v */ +#define RBX_SERIAL 0xc /* -h */ +#define RBX_CDROM 0xd /* -C */ +/* 0xe is reserved for log2(RB_POWEROFF). */ +#define RBX_GDB 0xf /* -g */ +#define RBX_MUTE 0x10 /* -m */ +/* 0x11 is reserved for log2(RB_SELFTEST). */ +/* 0x12 is reserved for boot programs. */ +/* 0x13 is reserved for boot programs. */ +#define RBX_PAUSE 0x14 /* -p */ +#define RBX_QUIET 0x15 /* -q */ +#define RBX_NOINTR 0x1c /* -n */ +/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ +#define RBX_DUAL 0x1d /* -D */ +/* 0x1f is reserved for log2(RB_BOOTINFO). */ + +/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ +#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ + OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ + OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ + OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ + OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ + OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) + +#define OPT_SET(opt) (1 << (opt)) +#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) + +extern uint32_t opts; + +#endif /* !_RBX_H_ */ diff --git a/sys/boot/i386/efi/Makefile b/sys/boot/i386/efi/Makefile index 2d1104611f5..943de119081 100644 --- a/sys/boot/i386/efi/Makefile +++ b/sys/boot/i386/efi/Makefile @@ -42,7 +42,7 @@ ${PROG}: ${LDSCRIPT} CLEANFILES= vers.c loader.efi -NEWVERSWHAT= "EFI loader" ${MACHINE_ARCH} +NEWVERSWHAT= "EFI loader" x86 vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} diff --git a/sys/boot/i386/gptboot/Makefile b/sys/boot/i386/gptboot/Makefile index cc71b3575e8..a0fad610c00 100644 --- a/sys/boot/i386/gptboot/Makefile +++ b/sys/boot/i386/gptboot/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../boot2 +.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common ${.CURDIR}/../../common FILES= gptboot @@ -19,20 +19,24 @@ GPTBOOT_UFS?= UFS1_AND_UFS2 #GPTBOOT_UFS?= UFS2_ONLY #GPTBOOT_UFS?= UFS1_ONLY -CFLAGS= -Os \ +CFLAGS= -DBOOTPROG=\"gptboot\" \ + -Os \ -fno-guess-branch-probability \ -fomit-frame-pointer \ -fno-unit-at-a-time \ -mno-align-long-strings \ -mrtd \ -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 \ + -DGPT \ -D${GPTBOOT_UFS} \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ + -I${.CURDIR}/../common \ -I${.CURDIR}/../btx/lib -I. \ -I${.CURDIR}/../boot2 \ + -I${.CURDIR}/../../.. \ -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings \ @@ -57,17 +61,17 @@ gptldr.bin: gptldr.out gptldr.out: gptldr.o ${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} gptldr.o -CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o +CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o ufsread.o gptboot.bin: gptboot.out objcopy -S -O binary gptboot.out ${.TARGET} -gptboot.out: ${BTXCRT} gptboot.o sio.o - ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} +gptboot.out: ${BTXCRT} gptboot.o sio.o gpt.o crc32.o drv.o cons.o util.o + ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} gptboot.o: ${.CURDIR}/../../common/ufsread.c -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend gptboot.o: machine CLEANFILES+= machine machine: diff --git a/sys/boot/i386/gptboot/gptboot.c b/sys/boot/i386/gptboot/gptboot.c index 6939556eb0d..5f0ab7c655c 100644 --- a/sys/boot/i386/gptboot/gptboot.c +++ b/sys/boot/i386/gptboot/gptboot.c @@ -32,46 +32,11 @@ __FBSDID("$FreeBSD$"); #include #include "lib.h" - -#define IO_KEYBOARD 1 -#define IO_SERIAL 2 - -#define SECOND 18 /* Circa that many ticks in a second. */ - -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) +#include "rbx.h" +#include "drv.h" +#include "util.h" +#include "cons.h" +#include "gpt.h" #define PATH_CONFIG "/boot.config" #define PATH_BOOT3 "/boot/loader" @@ -82,8 +47,6 @@ __FBSDID("$FreeBSD$"); #define NDEV 3 #define MEM_BASE 0x12 #define MEM_EXT 0x15 -#define V86_CY(x) ((x) & PSL_C) -#define V86_ZR(x) ((x) & PSL_Z) #define DRV_HARD 0x80 #define DRV_MASK 0x7f @@ -93,211 +56,178 @@ __FBSDID("$FreeBSD$"); #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) - extern uint32_t _end; static const uuid_t freebsd_ufs_uuid = GPT_ENT_TYPE_FREEBSD_UFS; static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ static const unsigned char flags[NOPT] = { - RBX_DUAL, - RBX_SERIAL, - RBX_ASKNAME, - RBX_CDROM, - RBX_CONFIG, - RBX_KDB, - RBX_GDB, - RBX_MUTE, - RBX_NOINTR, - RBX_PAUSE, - RBX_QUIET, - RBX_DFLTROOT, - RBX_SINGLE, - RBX_VERBOSE + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_MUTE, + RBX_NOINTR, + RBX_PAUSE, + RBX_QUIET, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_VERBOSE }; +uint32_t opts; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; -static struct dsk { - unsigned drive; - unsigned type; - unsigned unit; - int part; - daddr_t start; - int init; -} dsk; -static char cmd[512], cmddup[512]; +static struct dsk dsk; static char kname[1024]; -static uint32_t opts; static int comspeed = SIOSPD; static struct bootinfo bootinfo; -static uint8_t ioctrl = IO_KEYBOARD; void exit(int); -static int bcmp(const void *, const void *, size_t); static void load(void); -static int parse(void); +static int parse(char *, int *); static int xfsread(ino_t, void *, size_t); static int dskread(void *, daddr_t, unsigned); -static void printf(const char *,...); -static void putchar(int); -static void memcpy(void *, const void *, int); static uint32_t memsize(void); -static int drvread(void *, daddr_t, unsigned); -static int keyhit(unsigned); -static int xputc(int); -static int xgetc(int); -static int getc(int); - -static void -memcpy(void *dst, const void *src, int len) -{ - const char *s = src; - char *d = dst; - - while (len--) - *d++ = *s++; -} - -static inline int -strcmp(const char *s1, const char *s2) -{ - for (; *s1 == *s2 && *s1; s1++, s2++); - return (unsigned char)*s1 - (unsigned char)*s2; -} #include "ufsread.c" static inline int xfsread(ino_t inode, void *buf, size_t nbyte) { - if ((size_t)fsread(inode, buf, nbyte) != nbyte) { - printf("Invalid %s\n", "format"); - return -1; - } - return 0; + + if ((size_t)fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return (-1); + } + return (0); } static inline uint32_t memsize(void) { - v86.addr = MEM_EXT; - v86.eax = 0x8800; - v86int(); - return v86.eax; + + v86.addr = MEM_EXT; + v86.eax = 0x8800; + v86int(); + return (v86.eax); } -static inline void -getstr(void) +static int +gptinit(void) { - char *s; - int c; - s = cmd; - for (;;) { - switch (c = xgetc(0)) { - case 0: - break; - case '\177': - case '\b': - if (s > cmd) { - s--; - printf("\b \b"); - } - break; - case '\n': - case '\r': - *s = 0; - return; - default: - if (s - cmd < sizeof(cmd) - 1) - *s++ = c; - putchar(c); + if (gptread(&freebsd_ufs_uuid, &dsk, dmadat->secbuf) == -1) { + printf("%s: unable to load GPT\n", BOOTPROG); + return (-1); } - } -} - -static inline void -putc(int c) -{ - v86.addr = 0x10; - v86.eax = 0xe00 | (c & 0xff); - v86.ebx = 0x7; - v86int(); + if (gptfind(&freebsd_ufs_uuid, &dsk, dsk.part) == -1) { + printf("%s: no UFS partition was found\n", BOOTPROG); + return (-1); + } + dsk_meta = 0; + return (0); } int main(void) { - int autoboot; - ino_t ino; + char cmd[512], cmdtmp[512]; + int autoboot, dskupdated; + ino_t ino; - dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); - v86.ctl = V86_FLAGS; - v86.efl = PSL_RESERVED_DEFAULT | PSL_I; - dsk.drive = *(uint8_t *)PTOV(ARGS); - dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; - dsk.unit = dsk.drive & DRV_MASK; - dsk.part = -1; - bootinfo.bi_version = BOOTINFO_VERSION; - bootinfo.bi_size = sizeof(bootinfo); - bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ - bootinfo.bi_extmem = memsize(); - bootinfo.bi_memsizes_valid++; + dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base); + v86.ctl = V86_FLAGS; + v86.efl = PSL_RESERVED_DEFAULT | PSL_I; + dsk.drive = *(uint8_t *)PTOV(ARGS); + dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; + dsk.unit = dsk.drive & DRV_MASK; + dsk.part = -1; + dsk.start = 0; + bootinfo.bi_version = BOOTINFO_VERSION; + bootinfo.bi_size = sizeof(bootinfo); + bootinfo.bi_basemem = 0; /* XXX will be filled by loader or kernel */ + bootinfo.bi_extmem = memsize(); + bootinfo.bi_memsizes_valid++; - /* Process configuration file */ + /* Process configuration file */ - autoboot = 1; + if (gptinit() != 0) + return (-1); - if ((ino = lookup(PATH_CONFIG))) - fsread(ino, cmd, sizeof(cmd)); + autoboot = 1; + *cmd = '\0'; - if (*cmd) { - memcpy(cmddup, cmd, sizeof(cmd)); - if (parse()) - autoboot = 0; - if (!OPT_CHECK(RBX_QUIET)) - printf("%s: %s", PATH_CONFIG, cmddup); - /* Do not process this command twice */ - *cmd = 0; - } + for (;;) { + *kname = '\0'; + ino = lookup(PATH_CONFIG); + if (ino > 0) + fsread(ino, cmd, sizeof(cmd)); - /* - * Try to exec stage 3 boot loader. If interrupted by a keypress, - * or in case of failure, try to load a kernel directly instead. - */ + if (*cmd != '\0') { + memcpy(cmdtmp, cmd, sizeof(cmdtmp)); + if (parse(cmdtmp, &dskupdated)) + break; + if (dskupdated && gptinit() != 0) + break; + if (!OPT_CHECK(RBX_QUIET)) + printf("%s: %s", PATH_CONFIG, cmd); + *cmd = '\0'; + } - if (autoboot && !*kname) { - memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); - if (!keyhit(3*SECOND)) { - load(); - memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); + if (autoboot && keyhit(3)) { + if (*kname == '\0') + memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); + break; + } + autoboot = 0; + + /* + * Try to exec stage 3 boot loader. If interrupted by a + * keypress, or in case of failure, try to load a kernel + * directly instead. + */ + if (*kname != '\0') + load(); + memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); + load(); + memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); + load(); + gptbootfailed(&dsk); + if (gptfind(&freebsd_ufs_uuid, &dsk, -1) == -1) + break; + dsk_meta = 0; } - } - /* Present the user with the boot2 prompt. */ + /* Present the user with the boot2 prompt. */ - for (;;) { - if (!autoboot || !OPT_CHECK(RBX_QUIET)) - printf("\nFreeBSD/x86 boot\n" - "Default: %u:%s(%up%u)%s\n" - "boot: ", - dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, - dsk.part, kname); - if (ioctrl & IO_SERIAL) - sio_flush(); - if (!autoboot || keyhit(5*SECOND)) - getstr(); - else if (!autoboot || !OPT_CHECK(RBX_QUIET)) - putchar('\n'); - autoboot = 0; - if (parse()) - putchar('\a'); - else - load(); - } + for (;;) { + if (!OPT_CHECK(RBX_QUIET)) { + printf("\nFreeBSD/x86 boot\n" + "Default: %u:%s(%up%u)%s\n" + "boot: ", + dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, + dsk.part, kname); + } + if (ioctrl & IO_SERIAL) + sio_flush(); + *cmd = '\0'; + if (keyhit(0)) + getstr(cmd, sizeof(cmd)); + else if (!OPT_CHECK(RBX_QUIET)) + putchar('\n'); + if (parse(cmd, &dskupdated)) { + putchar('\a'); + continue; + } + if (dskupdated && gptinit() != 0) + continue; + load(); + } + /* NOTREACHED */ } /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ @@ -321,8 +251,11 @@ load(void) int fmt, i, j; if (!(ino = lookup(kname))) { - if (!ls) - printf("No %s\n", kname); + if (!ls) { + printf("%s: No %s on %u:%s(%up%u)\n", BOOTPROG, + kname, dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, + dsk.part); + } return; } if (xfsread(ino, &hdr, sizeof(hdr))) @@ -402,14 +335,15 @@ load(void) } static int -parse(void) +parse(char *cmdstr, int *dskupdated) { - char *arg = cmd; + char *arg = cmdstr; char *ep, *p, *q; const char *cp; unsigned int drv; int c, i, j; + *dskupdated = 0; while ((c = *arg++)) { if (c == ' ' || c == '\t' || c == '\n') continue; @@ -480,7 +414,7 @@ parse(void) drv = dsk.unit; dsk.drive = (dsk.type <= TYPE_MAXHARD ? DRV_HARD : 0) + drv; - dsk_meta = 0; + *dskupdated = 1; } if ((i = ep - arg)) { if ((size_t)i >= sizeof(kname)) @@ -496,232 +430,6 @@ parse(void) static int dskread(void *buf, daddr_t lba, unsigned nblk) { - struct gpt_hdr hdr; - struct gpt_ent *ent; - char *sec; - daddr_t slba, elba; - int part, entries_per_sec; - if (!dsk_meta) { - /* Read and verify GPT. */ - sec = dmadat->secbuf; - dsk.start = 0; - if (drvread(sec, 1, 1)) - return -1; - memcpy(&hdr, sec, sizeof(hdr)); - if (bcmp(hdr.hdr_sig, GPT_HDR_SIG, sizeof(hdr.hdr_sig)) != 0 || - hdr.hdr_lba_self != 1 || hdr.hdr_revision < 0x00010000 || - hdr.hdr_entsz < sizeof(*ent) || DEV_BSIZE % hdr.hdr_entsz != 0) { - printf("Invalid GPT header\n"); - return -1; - } - - /* XXX: CRC check? */ - - /* - * If the partition isn't specified, then search for the first UFS - * partition and hope it is /. Perhaps we should be using an OS - * flag in the GPT entry to mark / partitions. - * - * If the partition is specified, then figure out the LBA for the - * sector containing that partition index and load it. - */ - entries_per_sec = DEV_BSIZE / hdr.hdr_entsz; - if (dsk.part == -1) { - slba = hdr.hdr_lba_table; - elba = slba + hdr.hdr_entries / entries_per_sec; - while (slba < elba && dsk.part == -1) { - if (drvread(sec, slba, 1)) - return -1; - for (part = 0; part < entries_per_sec; part++) { - ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); - if (bcmp(&ent->ent_type, &freebsd_ufs_uuid, - sizeof(uuid_t)) == 0) { - dsk.part = (slba - hdr.hdr_lba_table) * - entries_per_sec + part + 1; - dsk.start = ent->ent_lba_start; - break; - } - } - slba++; - } - if (dsk.part == -1) { - printf("No UFS partition was found\n"); - return -1; - } - } else { - if (dsk.part > hdr.hdr_entries) { - printf("Invalid partition index\n"); - return -1; - } - slba = hdr.hdr_lba_table + (dsk.part - 1) / entries_per_sec; - if (drvread(sec, slba, 1)) - return -1; - part = (dsk.part - 1) % entries_per_sec; - ent = (struct gpt_ent *)(sec + part * hdr.hdr_entsz); - if (bcmp(&ent->ent_type, &freebsd_ufs_uuid, sizeof(uuid_t)) != 0) { - printf("Specified partition is not UFS\n"); - return -1; - } - dsk.start = ent->ent_lba_start; - } - /* - * XXX: No way to detect SCSI vs. ATA currently. - */ -#if 0 - if (!dsk.init) { - if (d->d_type == DTYPE_SCSI) - dsk.type = TYPE_DA; - dsk.init++; - } -#endif - } - return drvread(buf, dsk.start + lba, nblk); -} - -static void -printf(const char *fmt,...) -{ - va_list ap; - char buf[10]; - char *s; - unsigned u; - int c; - - va_start(ap, fmt); - while ((c = *fmt++)) { - if (c == '%') { - c = *fmt++; - switch (c) { - case 'c': - putchar(va_arg(ap, int)); - continue; - case 's': - for (s = va_arg(ap, char *); *s; s++) - putchar(*s); - continue; - case 'u': - u = va_arg(ap, unsigned); - s = buf; - do - *s++ = '0' + u % 10U; - while (u /= 10U); - while (--s >= buf) - putchar(*s); - continue; - } - } - putchar(c); - } - va_end(ap); - return; -} - -static void -putchar(int c) -{ - if (c == '\n') - xputc('\r'); - xputc(c); -} - -static int -bcmp(const void *b1, const void *b2, size_t length) -{ - const char *p1 = b1, *p2 = b2; - - if (length == 0) - return (0); - do { - if (*p1++ != *p2++) - break; - } while (--length); - return (length); -} - -static struct { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; -} packet; - -static int -drvread(void *buf, daddr_t lba, unsigned nblk) -{ - static unsigned c = 0x2d5c7c2f; - - if (!OPT_CHECK(RBX_QUIET)) - printf("%c\b", c = c << 8 | c >> 24); - packet.len = 0x10; - packet.count = nblk; - packet.off = VTOPOFF(buf); - packet.seg = VTOPSEG(buf); - packet.lba = lba; - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4200; - v86.edx = dsk.drive; - v86.ds = VTOPSEG(&packet); - v86.esi = VTOPOFF(&packet); - v86int(); - if (V86_CY(v86.efl)) { - printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); - return -1; - } - return 0; -} - -static int -keyhit(unsigned ticks) -{ - uint32_t t0, t1; - - if (OPT_CHECK(RBX_NOINTR)) - return 0; - t0 = 0; - for (;;) { - if (xgetc(1)) - return 1; - t1 = *(uint32_t *)PTOV(0x46c); - if (!t0) - t0 = t1; - if (t1 < t0 || t1 >= t0 + ticks) - return 0; - } -} - -static int -xputc(int c) -{ - if (ioctrl & IO_KEYBOARD) - putc(c); - if (ioctrl & IO_SERIAL) - sio_putc(c); - return c; -} - -static int -xgetc(int fn) -{ - if (OPT_CHECK(RBX_NOINTR)) - return 0; - for (;;) { - if (ioctrl & IO_KEYBOARD && getc(1)) - return fn ? 1 : getc(0); - if (ioctrl & IO_SERIAL && sio_ischar()) - return fn ? 1 : sio_getc(); - if (fn) - return 0; - } -} - -static int -getc(int fn) -{ - v86.addr = 0x16; - v86.eax = fn << 8; - v86int(); - return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); + return drvread(&dsk, buf, lba + dsk.start, nblk); } diff --git a/sys/boot/i386/gptzfsboot/Makefile b/sys/boot/i386/gptzfsboot/Makefile index 467d3123aec..30a5fc78aba 100644 --- a/sys/boot/i386/gptzfsboot/Makefile +++ b/sys/boot/i386/gptzfsboot/Makefile @@ -1,6 +1,8 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot ${.CURDIR}/../zfsboot +.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../gptboot \ + ${.CURDIR}/../zfsboot ${.CURDIR}/../common \ + ${.CURDIR}/../../common FILES= gptzfsboot @@ -14,7 +16,8 @@ REL1= 0x700 ORG1= 0x7c00 ORG2= 0x0 -CFLAGS= -Os \ +CFLAGS= -DBOOTPROG=\"gptzfsboot\" \ + -Os \ -fno-guess-branch-probability \ -fomit-frame-pointer \ -fno-unit-at-a-time \ @@ -26,6 +29,7 @@ CFLAGS= -Os \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ -I${.CURDIR}/../../common \ + -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ -I${.CURDIR}/../btx/lib -I. \ @@ -59,12 +63,12 @@ CLEANFILES+= gptzfsboot.bin gptzfsboot.out zfsboot.o sio.o gptzfsboot.bin: gptzfsboot.out objcopy -S -O binary gptzfsboot.out ${.TARGET} -gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o +gptzfsboot.out: ${BTXCRT} zfsboot.o sio.o gpt.o drv.o cons.o util.o ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} zfsboot.o: ${.CURDIR}/../../zfs/zfsimpl.c -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend zfsboot.o: machine CLEANFILES+= machine machine: diff --git a/sys/boot/i386/libfirewire/Makefile b/sys/boot/i386/libfirewire/Makefile index 28f76307d8a..191b95479e2 100644 --- a/sys/boot/i386/libfirewire/Makefile +++ b/sys/boot/i386/libfirewire/Makefile @@ -16,7 +16,7 @@ CFLAGS+= -I${.CURDIR}/../libi386 CFLAGS+= -Wformat -Wall -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CLEANFILES+= machine machine: ln -sf ${.CURDIR}/../../../i386/include machine @@ -24,7 +24,7 @@ machine: .include -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine .endif diff --git a/sys/boot/i386/libi386/Makefile b/sys/boot/i386/libi386/Makefile index f1a461a88c4..3b897847ea8 100644 --- a/sys/boot/i386/libi386/Makefile +++ b/sys/boot/i386/libi386/Makefile @@ -53,7 +53,7 @@ CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../btx/lib \ # the location of libstand CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CLEANFILES+= machine machine: ln -sf ${.CURDIR}/../../../i386/include machine @@ -61,6 +61,6 @@ machine: .include -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine .endif diff --git a/sys/boot/i386/libi386/biosdisk.c b/sys/boot/i386/libi386/biosdisk.c index cf0b03353ea..a67a7ef9a88 100644 --- a/sys/boot/i386/libi386/biosdisk.c +++ b/sys/boot/i386/libi386/biosdisk.c @@ -214,10 +214,12 @@ bd_init(void) /* sequence 0, 0x80 */ for (base = 0; base <= 0x80; base += 0x80) { for (unit = base; (nbdinfo < MAXBDDEV); unit++) { +#ifndef VIRTUALBOX /* check the BIOS equipment list for number of fixed disks */ if((base == 0x80) && (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) - break; + break; +#endif bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = (unit < 0x80) ? BD_FLOPPY : 0; diff --git a/sys/boot/i386/libi386/pxe.c b/sys/boot/i386/libi386/pxe.c index 5629d90e2cb..0caee6abe42 100644 --- a/sys/boot/i386/libi386/pxe.c +++ b/sys/boot/i386/libi386/pxe.c @@ -409,6 +409,7 @@ pxe_perror(int err) * Reach inside the libstand NFS code and dig out an NFS handle * for the root filesystem. */ +#ifdef OLD_NFSV2 struct nfs_iodesc { struct iodesc *iodesc; off_t off; @@ -456,6 +457,64 @@ pxe_setnfshandle(char *rootpath) sprintf(cp, "X"); setenv("boot.nfsroot.nfshandle", buf, 1); } +#else /* !OLD_NFSV2 */ + +#define NFS_V3MAXFHSIZE 64 + +struct nfs_iodesc { + struct iodesc *iodesc; + off_t off; + uint32_t fhsize; + u_char fh[NFS_V3MAXFHSIZE]; + /* structure truncated */ +}; +extern struct nfs_iodesc nfs_root_node; +extern int rpc_port; + +static void +pxe_rpcmountcall() +{ + struct iodesc *d; + int error; + + if (!(d = socktodesc(pxe_sock))) + return; + d->myport = htons(--rpc_port); + d->destip = rootip; + if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize, + nfs_root_node.fh)) != 0) { + printf("NFS MOUNT RPC error: %d\n", error); + nfs_root_node.fhsize = 0; + } + nfs_root_node.iodesc = d; +} + +static void +pxe_setnfshandle(char *rootpath) +{ + int i; + u_char *fh; + char buf[2 * NFS_V3MAXFHSIZE + 3], *cp; + + /* + * If NFS files were never opened, we need to do mount call + * ourselves. Use nfs_root_node.iodesc as flag indicating + * previous NFS usage. + */ + if (nfs_root_node.iodesc == NULL) + pxe_rpcmountcall(); + + fh = &nfs_root_node.fh[0]; + buf[0] = 'X'; + cp = &buf[1]; + for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2) + sprintf(cp, "%02x", fh[i]); + sprintf(cp, "X"); + setenv("boot.nfsroot.nfshandle", buf, 1); + sprintf(buf, "%d", nfs_root_node.fhsize); + setenv("boot.nfsroot.nfshandlelen", buf, 1); +} +#endif /* OLD_NFSV2 */ void pxenv_call(int func) diff --git a/sys/boot/i386/loader/Makefile b/sys/boot/i386/loader/Makefile index 71307c04606..b834ea064f3 100644 --- a/sys/boot/i386/loader/Makefile +++ b/sys/boot/i386/loader/Makefile @@ -6,7 +6,7 @@ MK_SSP= no LOADER?= loader PROG= ${LOADER}.sym INTERNALPROG= -NEWVERSWHAT?= "bootstrap loader" i386 +NEWVERSWHAT?= "bootstrap loader" x86 # architecture-specific loader code SRCS= main.c conf.c vers.c @@ -119,7 +119,7 @@ LDADD= ${LIBFICL} ${LIBFIREWIRE} ${LIBZFS} ${LIBI386} ${LIBSTAND} .include -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine CLEANFILES+= machine machine: diff --git a/sys/boot/i386/zfsboot/Makefile b/sys/boot/i386/zfsboot/Makefile index 1653534a325..10616e418ac 100644 --- a/sys/boot/i386/zfsboot/Makefile +++ b/sys/boot/i386/zfsboot/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../boot2 +.PATH: ${.CURDIR}/../boot2 ${.CURDIR}/../common ${.CURDIR}/../../common FILES= zfsboot @@ -17,7 +17,8 @@ REL1= 0x700 ORG1= 0x7c00 ORG2= 0x2000 -CFLAGS= -Os -g \ +CFLAGS= -DBOOTPROG=\"zfsboot\" \ + -Os -g \ -fno-guess-branch-probability \ -fomit-frame-pointer \ -fno-unit-at-a-time \ @@ -29,6 +30,8 @@ CFLAGS= -Os -g \ -DSIOPRT=${BOOT_COMCONSOLE_PORT} \ -DSIOFMT=${B2SIOFMT} \ -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \ + -I${.CURDIR}/../../common \ + -I${.CURDIR}/../common \ -I${.CURDIR}/../../zfs \ -I${.CURDIR}/../../../cddl/boot/zfs \ -I${.CURDIR}/../btx/lib -I. \ @@ -57,7 +60,7 @@ zfsldr.out: zfsldr.o ${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} zfsldr.o CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \ - zfsboot.o zfsboot.s zfsboot.s.tmp zfsboot.h sio.o + zfsboot.o zfsboot.s zfsboot.s.tmp xreadorg.h sio.o # We currently allow 32768 bytes for zfsboot - in practice it could be # any size up to 3.5Mb but keeping it fixed size simplifies zfsldr. @@ -79,26 +82,26 @@ zfsboot.ldr: zfsboot.bin: zfsboot.out objcopy -S -O binary zfsboot.out ${.TARGET} -zfsboot.out: ${BTXCRT} zfsboot.o sio.o +zfsboot.out: ${BTXCRT} zfsboot.o sio.o drv.o cons.o util.o ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC} ${LIBSTAND} zfsboot.o: zfsboot.s -SRCS= zfsboot.c zfsboot.h +SRCS= zfsboot.c xreadorg.h -zfsboot.s: zfsboot.c zfsboot.h ${.CURDIR}/../../zfs/zfsimpl.c +zfsboot.s: zfsboot.c xreadorg.h ${.CURDIR}/../../zfs/zfsimpl.c ${CC} ${CFLAGS} -S -o zfsboot.s.tmp ${.CURDIR}/zfsboot.c sed -e '/align/d' -e '/nop/d' < zfsboot.s.tmp > zfsboot.s rm -f zfsboot.s.tmp -zfsboot.h: zfsldr.out +xreadorg.h: zfsldr.out ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \ { x = $$1 - ORG1; \ printf("#define XREADORG %#x\n", REL1 + x) }' \ ORG1=`printf "%d" ${ORG1}` \ REL1=`printf "%d" ${REL1}` > ${.TARGET} -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend zfsboot.s: machine CLEANFILES+= machine machine: diff --git a/sys/boot/i386/zfsboot/zfsboot.c b/sys/boot/i386/zfsboot/zfsboot.c index b6e5f0cfc7c..1d0077b7a4a 100644 --- a/sys/boot/i386/zfsboot/zfsboot.c +++ b/sys/boot/i386/zfsboot/zfsboot.c @@ -36,50 +36,11 @@ __FBSDID("$FreeBSD$"); #include -#ifndef GPT -#include "zfsboot.h" -#endif #include "lib.h" - -#define IO_KEYBOARD 1 -#define IO_SERIAL 2 - -#define SECOND 18 /* Circa that many ticks in a second. */ - -#define RBX_ASKNAME 0x0 /* -a */ -#define RBX_SINGLE 0x1 /* -s */ -/* 0x2 is reserved for log2(RB_NOSYNC). */ -/* 0x3 is reserved for log2(RB_HALT). */ -/* 0x4 is reserved for log2(RB_INITNAME). */ -#define RBX_DFLTROOT 0x5 /* -r */ -#define RBX_KDB 0x6 /* -d */ -/* 0x7 is reserved for log2(RB_RDONLY). */ -/* 0x8 is reserved for log2(RB_DUMP). */ -/* 0x9 is reserved for log2(RB_MINIROOT). */ -#define RBX_CONFIG 0xa /* -c */ -#define RBX_VERBOSE 0xb /* -v */ -#define RBX_SERIAL 0xc /* -h */ -#define RBX_CDROM 0xd /* -C */ -/* 0xe is reserved for log2(RB_POWEROFF). */ -#define RBX_GDB 0xf /* -g */ -#define RBX_MUTE 0x10 /* -m */ -/* 0x11 is reserved for log2(RB_SELFTEST). */ -/* 0x12 is reserved for boot programs. */ -/* 0x13 is reserved for boot programs. */ -#define RBX_PAUSE 0x14 /* -p */ -#define RBX_QUIET 0x15 /* -q */ -#define RBX_NOINTR 0x1c /* -n */ -/* 0x1d is reserved for log2(RB_MULTIPLE) and is just misnamed here. */ -#define RBX_DUAL 0x1d /* -D */ -/* 0x1f is reserved for log2(RB_BOOTINFO). */ - -/* pass: -a, -s, -r, -d, -c, -v, -h, -C, -g, -m, -p, -D */ -#define RBX_MASK (OPT_SET(RBX_ASKNAME) | OPT_SET(RBX_SINGLE) | \ - OPT_SET(RBX_DFLTROOT) | OPT_SET(RBX_KDB ) | \ - OPT_SET(RBX_CONFIG) | OPT_SET(RBX_VERBOSE) | \ - OPT_SET(RBX_SERIAL) | OPT_SET(RBX_CDROM) | \ - OPT_SET(RBX_GDB ) | OPT_SET(RBX_MUTE) | \ - OPT_SET(RBX_PAUSE) | OPT_SET(RBX_DUAL)) +#include "rbx.h" +#include "drv.h" +#include "util.h" +#include "cons.h" /* Hint to loader that we came from ZFS */ #define KARGS_FLAGS_ZFS 0x4 @@ -91,10 +52,8 @@ __FBSDID("$FreeBSD$"); #define ARGS 0x900 #define NOPT 14 #define NDEV 3 -#define V86_CY(x) ((x) & 1) -#define V86_ZR(x) ((x) & 0x40) -#define BIOS_NUMDRIVES 0x475 +#define BIOS_NUMDRIVES 0x475 #define DRV_HARD 0x80 #define DRV_MASK 0x7f @@ -103,8 +62,7 @@ __FBSDID("$FreeBSD$"); #define TYPE_MAXHARD TYPE_DA #define TYPE_FD 2 -#define OPT_SET(opt) (1 << (opt)) -#define OPT_CHECK(opt) ((opts) & OPT_SET(opt)) +#define MAXBDDEV 31 extern uint32_t _end; @@ -128,26 +86,16 @@ static const unsigned char flags[NOPT] = { RBX_SINGLE, RBX_VERBOSE }; +uint32_t opts; static const char *const dev_nm[NDEV] = {"ad", "da", "fd"}; static const unsigned char dev_maj[NDEV] = {30, 4, 2}; -struct dsk { - unsigned drive; - unsigned type; - unsigned unit; - unsigned slice; - unsigned part; - int init; - daddr_t start; -}; static char cmd[512]; static char kname[1024]; -static uint32_t opts; static int comspeed = SIOSPD; static struct bootinfo bootinfo; static uint32_t bootdev; -static uint8_t ioctrl = IO_KEYBOARD; vm_offset_t high_heap_base; uint32_t bios_basemem, bios_extmem, high_heap_size; @@ -173,79 +121,7 @@ static struct dmadat *dmadat; void exit(int); static void load(void); static int parse(void); -static void printf(const char *,...); -static void putchar(int); static void bios_getmem(void); -static int drvread(struct dsk *, void *, daddr_t, unsigned); -static int keyhit(unsigned); -static int xputc(int); -static int xgetc(int); -static int getc(int); - -static void memcpy(void *, const void *, int); -static void -memcpy(void *dst, const void *src, int len) -{ - const char *s = src; - char *d = dst; - - while (len--) - *d++ = *s++; -} - -static void -strcpy(char *dst, const char *src) -{ - while (*src) - *dst++ = *src++; - *dst++ = 0; -} - -static void -strcat(char *dst, const char *src) -{ - while (*dst) - dst++; - while (*src) - *dst++ = *src++; - *dst++ = 0; -} - -static int -strcmp(const char *s1, const char *s2) -{ - for (; *s1 == *s2 && *s1; s1++, s2++); - return (unsigned char)*s1 - (unsigned char)*s2; -} - -static const char * -strchr(const char *s, char ch) -{ - for (; *s; s++) - if (*s == ch) - return s; - return 0; -} - -static int -memcmp(const void *p1, const void *p2, size_t n) -{ - const char *s1 = (const char *) p1; - const char *s2 = (const char *) p2; - for (; n > 0 && *s1 == *s2; s1++, s2++, n--); - if (n) - return (unsigned char)*s1 - (unsigned char)*s2; - else - return 0; -} - -static void -memset(void *p, char val, size_t n) -{ - char *s = (char *) p; - while (n--) - *s++ = val; -} static void * malloc(size_t n) @@ -261,15 +137,6 @@ malloc(size_t n) return p; } -static size_t -strlen(const char *s) -{ - size_t len = 0; - while (*s++) - len++; - return len; -} - static char * strdup(const char *s) { @@ -324,6 +191,7 @@ vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) p = buf; lba = off / DEV_BSIZE; + lba += dsk->start; while (bytes > 0) { nb = bytes / DEV_BSIZE; if (nb > READ_BUF_SIZE / DEV_BSIZE) @@ -435,46 +303,6 @@ bios_getmem(void) } } -static inline void -getstr(void) -{ - char *s; - int c; - - s = cmd; - for (;;) { - switch (c = xgetc(0)) { - case 0: - break; - case '\177': - case '\b': - if (s > cmd) { - s--; - printf("\b \b"); - } - break; - case '\n': - case '\r': - *s = 0; - return; - default: - if (s - cmd < sizeof(cmd) - 1) - *s++ = c; - putchar(c); - } - } -} - -static inline void -putc(int c) -{ - v86.ctl = 0; - v86.addr = 0x10; - v86.eax = 0xe00 | (c & 0xff); - v86.ebx = 0x7; - v86int(); -} - /* * Try to detect a device supported by the legacy int13 BIOS */ @@ -571,7 +399,7 @@ probe_drive(struct dsk *dsk, spa_t **spap) * We record the first pool we find (we will try * to boot from that one). */ - spap = 0; + spap = NULL; /* * This slice had a vdev. We need a new dsk @@ -667,7 +495,12 @@ main(void) * will find any other available pools and it may fill in missing * vdevs for the boot pool. */ - for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) { +#ifndef VIRTUALBOX + for (i = 0; i < *(unsigned char *)PTOV(BIOS_NUMDRIVES); i++) +#else + for (i = 0; i < MAXBDDEV; i++) +#endif + { if ((i | DRV_HARD) == *(uint8_t *)PTOV(ARGS)) continue; @@ -682,7 +515,7 @@ main(void) dsk->part = 0; dsk->start = 0; dsk->init = 0; - probe_drive(dsk, 0); + probe_drive(dsk, NULL); } /* @@ -692,7 +525,7 @@ main(void) if (!spa) { spa = STAILQ_FIRST(&zfs_pools); if (!spa) { - printf("No ZFS pools located, can't boot\n"); + printf("%s: No ZFS pools located, can't boot\n", BOOTPROG); for (;;) ; } @@ -721,7 +554,7 @@ main(void) if (autoboot && !*kname) { memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); - if (!keyhit(3*SECOND)) { + if (!keyhit(3)) { load(); memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); } @@ -737,8 +570,8 @@ main(void) spa->spa_name, kname); if (ioctrl & IO_SERIAL) sio_flush(); - if (!autoboot || keyhit(5*SECOND)) - getstr(); + if (!autoboot || keyhit(5)) + getstr(cmd, sizeof(cmd)); else if (!autoboot || !OPT_CHECK(RBX_QUIET)) putchar('\n'); autoboot = 0; @@ -853,7 +686,7 @@ load(void) } static int -parse() +parse(void) { char *arg = cmd; char *ep, *p, *q; @@ -945,222 +778,3 @@ parse() } return 0; } - -static void -printf(const char *fmt,...) -{ - va_list ap; - char buf[20]; - char *s; - unsigned long long u; - int c; - int minus; - int prec; - int l; - int len; - int pad; - - va_start(ap, fmt); - while ((c = *fmt++)) { - if (c == '%') { - minus = 0; - prec = 0; - l = 0; - nextfmt: - c = *fmt++; - switch (c) { - case '-': - minus = 1; - goto nextfmt; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - prec = 10 * prec + (c - '0'); - goto nextfmt; - case 'c': - putchar(va_arg(ap, int)); - continue; - case 'l': - l++; - goto nextfmt; - case 's': - s = va_arg(ap, char *); - if (prec) { - len = strlen(s); - if (len < prec) - pad = prec - len; - else - pad = 0; - if (minus) - while (pad--) - putchar(' '); - for (; *s; s++) - putchar(*s); - if (!minus) - while (pad--) - putchar(' '); - } else { - for (; *s; s++) - putchar(*s); - } - continue; - case 'u': - switch (l) { - case 2: - u = va_arg(ap, unsigned long long); - break; - case 1: - u = va_arg(ap, unsigned long); - break; - default: - u = va_arg(ap, unsigned); - break; - } - s = buf; - do - *s++ = '0' + u % 10U; - while (u /= 10U); - while (--s >= buf) - putchar(*s); - continue; - } - } - putchar(c); - } - va_end(ap); - return; -} - -static void -putchar(int c) -{ - if (c == '\n') - xputc('\r'); - xputc(c); -} - -#ifdef GPT -static struct { - uint16_t len; - uint16_t count; - uint16_t off; - uint16_t seg; - uint64_t lba; -} packet; -#endif - -static int -drvread(struct dsk *dsk, void *buf, daddr_t lba, unsigned nblk) -{ -#ifdef GPT - static unsigned c = 0x2d5c7c2f; - - if (!OPT_CHECK(RBX_QUIET)) - printf("%c\b", c = c << 8 | c >> 24); - packet.len = 0x10; - packet.count = nblk; - packet.off = VTOPOFF(buf); - packet.seg = VTOPSEG(buf); - packet.lba = lba + dsk->start; - v86.ctl = V86_FLAGS; - v86.addr = 0x13; - v86.eax = 0x4200; - v86.edx = dsk->drive; - v86.ds = VTOPSEG(&packet); - v86.esi = VTOPOFF(&packet); - v86int(); - if (V86_CY(v86.efl)) { - printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); - return -1; - } - return 0; -#else - static unsigned c = 0x2d5c7c2f; - - lba += dsk->start; - if (!OPT_CHECK(RBX_QUIET)) - printf("%c\b", c = c << 8 | c >> 24); - v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; - v86.addr = XREADORG; /* call to xread in boot1 */ - v86.es = VTOPSEG(buf); - v86.eax = lba; - v86.ebx = VTOPOFF(buf); - v86.ecx = lba >> 32; - v86.edx = nblk << 8 | dsk->drive; - v86int(); - v86.ctl = V86_FLAGS; - if (V86_CY(v86.efl)) { - printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba); - return -1; - } - return 0; -#endif -} - -static int -keyhit(unsigned ticks) -{ - uint32_t t0, t1; - - if (OPT_CHECK(RBX_NOINTR)) - return 0; - t0 = 0; - for (;;) { - if (xgetc(1)) - return 1; - t1 = *(uint32_t *)PTOV(0x46c); - if (!t0) - t0 = t1; - if (t1 < t0 || t1 >= t0 + ticks) - return 0; - } -} - -static int -xputc(int c) -{ - if (ioctrl & IO_KEYBOARD) - putc(c); - if (ioctrl & IO_SERIAL) - sio_putc(c); - return c; -} - -static int -xgetc(int fn) -{ - if (OPT_CHECK(RBX_NOINTR)) - return 0; - for (;;) { - if (ioctrl & IO_KEYBOARD && getc(1)) - return fn ? 1 : getc(0); - if (ioctrl & IO_SERIAL && sio_ischar()) - return fn ? 1 : sio_getc(); - if (fn) - return 0; - } -} - -static int -getc(int fn) -{ - /* - * The extra comparison against zero is an attempt to work around - * what appears to be a bug in QEMU and Bochs. Both emulators - * sometimes report a key-press with scancode one and ascii zero - * when no such key is pressed in reality. As far as I can tell, - * this only happens shortly after a reboot. - */ - v86.ctl = V86_FLAGS; - v86.addr = 0x16; - v86.eax = fn << 8; - v86int(); - return fn == 0 ? v86.eax & 0xff : (!V86_ZR(v86.efl) && (v86.eax & 0xff)); -} diff --git a/sys/boot/i386/zfsloader/Makefile b/sys/boot/i386/zfsloader/Makefile index 51338e17f82..926d69d0548 100644 --- a/sys/boot/i386/zfsloader/Makefile +++ b/sys/boot/i386/zfsloader/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../loader LOADER= zfsloader -NEWVERSWHAT= "ZFS enabled bootstrap loader" i386 +NEWVERSWHAT= "ZFS enabled bootstrap loader" x86 LOADER_ZFS_SUPPORT=yes LOADER_ONLY= yes NO_MAN= yes diff --git a/sys/boot/ia64/common/Makefile b/sys/boot/ia64/common/Makefile index 8261c25539c..3204edcd6c4 100644 --- a/sys/boot/ia64/common/Makefile +++ b/sys/boot/ia64/common/Makefile @@ -9,7 +9,7 @@ INTERNALLIB= SRCS= autoload.c bootinfo.c copy.c devicename.c exec.c CFLAGS+= -I${.CURDIR}/../../efi/include -CFLAGS+= -I${.CURDIR}/../../efi/include/${MACHINE_ARCH} +CFLAGS+= -I${.CURDIR}/../../efi/include/${MACHINE_CPUARCH} CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../../../lib/libstand @@ -17,7 +17,7 @@ CFLAGS+= -I${.CURDIR}/../../../../lib/libstand BOOT_FORTH= yes CFLAGS+= -DBOOT_FORTH CFLAGS+= -I${.CURDIR}/../../ficl -CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_ARCH} +CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH} .endif .PATH: ${.CURDIR}/../../common diff --git a/sys/boot/ia64/efi/Makefile b/sys/boot/ia64/efi/Makefile index 5682ac85ea6..27e81b996ab 100644 --- a/sys/boot/ia64/efi/Makefile +++ b/sys/boot/ia64/efi/Makefile @@ -9,21 +9,21 @@ PROG= loader.sym INTERNALPROG= SRCS= conf.c efimd.c main.c pal.S start.S vers.c -.PATH: ${.CURDIR}/../../../${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${.CURDIR}/../../../${MACHINE_CPUARCH}/${MACHINE_CPUARCH} CFLAGS+= -I${.CURDIR}/../common CFLAGS+= -I${.CURDIR}/../../common CFLAGS+= -I${.CURDIR}/../../efi/include -CFLAGS+= -I${.CURDIR}/../../efi/include/${MACHINE_ARCH} +CFLAGS+= -I${.CURDIR}/../../efi/include/${MACHINE_CPUARCH} CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../../../lib/libstand -LDSCRIPT= ${.CURDIR}/ldscript.${MACHINE_ARCH} +LDSCRIPT= ${.CURDIR}/ldscript.${MACHINE_CPUARCH} LDFLAGS= -Wl,-T${LDSCRIPT} -shared -symbolic ${PROG}: ${LDSCRIPT} -NEWVERSWHAT= "EFI boot" ${MACHINE_ARCH} +NEWVERSWHAT= "EFI boot" ${MACHINE_CPUARCH} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} @@ -42,7 +42,7 @@ loader.efi: loader.sym fi ${OBJCOPY} -j .data -j .dynamic -j .dynstr -j .dynsym -j .hash \ -j .rela.dyn -j .reloc -j .sdata -j .text \ - --target=efi-app-${MACHINE_ARCH} ${.ALLSRC} ${.TARGET} + --target=efi-app-${MACHINE_CPUARCH} ${.ALLSRC} ${.TARGET} CLEANFILES= vers.c loader.efi diff --git a/sys/boot/ia64/ski/Makefile b/sys/boot/ia64/ski/Makefile index 081fd72e8e7..5151435b94c 100644 --- a/sys/boot/ia64/ski/Makefile +++ b/sys/boot/ia64/ski/Makefile @@ -17,10 +17,10 @@ CFLAGS+= -I${.CURDIR}/../../common CFLAGS+= -I${.CURDIR}/../../.. CFLAGS+= -I${.CURDIR}/../../../../lib/libstand -LDSCRIPT= ${.CURDIR}/ldscript.${MACHINE_ARCH} +LDSCRIPT= ${.CURDIR}/ldscript.${MACHINE_CPUARCH} LDFLAGS= -Wl,-T${LDSCRIPT} -NEWVERSWHAT= "SKI boot" ${MACHINE_ARCH} +NEWVERSWHAT= "SKI boot" ${MACHINE_CPUARCH} vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} diff --git a/sys/boot/ofw/libofw/Makefile b/sys/boot/ofw/libofw/Makefile index 5ea0de972af..945d6508988 100644 --- a/sys/boot/ofw/libofw/Makefile +++ b/sys/boot/ofw/libofw/Makefile @@ -13,7 +13,7 @@ CFLAGS+= -I${.CURDIR}/../../../../lib/libstand/ CFLAGS+= -I${.CURDIR}/../../common -I${.CURDIR}/../../.. -I. CFLAGS+= -ffreestanding -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.if ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -msoft-float SRCS+= ppc64_elf_freebsd.c .endif @@ -24,7 +24,7 @@ CFLAGS+= -DDISK_DEBUG .endif machine: - ln -sf ${.CURDIR}/../../../${MACHINE_ARCH}/include machine + ln -sf ${.CURDIR}/../../../${MACHINE_CPUARCH}/include machine CLEANFILES+= machine diff --git a/sys/boot/ofw/libofw/ofw_copy.c b/sys/boot/ofw/libofw/ofw_copy.c index 93e7ec656d0..781d4233a01 100644 --- a/sys/boot/ofw/libofw/ofw_copy.c +++ b/sys/boot/ofw/libofw/ofw_copy.c @@ -68,7 +68,7 @@ ofw_mapmem(vm_offset_t dest, const size_t len) /* * Trim area covered by existing mapping, if any */ - if (dest < (last_dest + last_len)) { + if (dest < (last_dest + last_len) && dest >= last_dest) { nlen -= (last_dest + last_len) - dest; dest = last_dest + last_len; } diff --git a/sys/boot/pc98/boot2/Makefile b/sys/boot/pc98/boot2/Makefile index 63f364c2261..dfd8607510c 100644 --- a/sys/boot/pc98/boot2/Makefile +++ b/sys/boot/pc98/boot2/Makefile @@ -1,5 +1,10 @@ # $FreeBSD$ +.include + +# XXX: clang can compile the boot code just fine, but boot2 gets too big +CC:=${CC:C/^(.*\/)?clang$/gcc/1} + FILES= boot boot1 boot2 NM?= nm diff --git a/sys/boot/pc98/boot2/boot2.c b/sys/boot/pc98/boot2/boot2.c index 8c833ba02d8..259d5de93fe 100644 --- a/sys/boot/pc98/boot2/boot2.c +++ b/sys/boot/pc98/boot2/boot2.c @@ -187,9 +187,8 @@ xfsread(ino_t inode, void *buf, size_t nbyte) static inline uint32_t memsize(void) { - u_char *p = (u_char *)PTOV(0); - - return *(p + 0x401) * 128 * 1024 + *(u_int16_t *)(p + 0x594) * 1024 * 1024; + return (*(u_char *)PTOV(0x401) * 128 * 1024 + + *(uint16_t *)PTOV(0x594) * 1024 * 1024); } static inline void @@ -486,7 +485,7 @@ load(void) return; p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); bootinfo.bi_symtab = VTOP(p); - memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + *(uint32_t*)p = hdr.ex.a_syms; p += sizeof(hdr.ex.a_syms); if (hdr.ex.a_syms) { if (xfsread(ino, p, hdr.ex.a_syms)) @@ -523,7 +522,7 @@ load(void) if (xfsread(ino, &es, sizeof(es))) return; for (i = 0; i < 2; i++) { - memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + *(Elf32_Word *)p = es[i].sh_size; p += sizeof(es[i].sh_size); fs_off = es[i].sh_offset; if (xfsread(ino, p, es[i].sh_size)) diff --git a/sys/boot/sparc64/boot1/boot1.c b/sys/boot/sparc64/boot1/boot1.c index 813da29f4ec..6b9fa30ace4 100644 --- a/sys/boot/sparc64/boot1/boot1.c +++ b/sys/boot/sparc64/boot1/boot1.c @@ -26,9 +26,7 @@ __FBSDID("$FreeBSD$"); #define _PATH_LOADER "/boot/loader" #define _PATH_KERNEL "/boot/kernel/kernel" -#define BSIZEMAX 16384 - -typedef int putc_func_t(int c, void *arg); +typedef int putc_func_t(char c, void *arg); typedef int32_t ofwh_t; struct sp_data { @@ -44,11 +42,6 @@ static char bootargs[128]; static ofwh_t bootdev; -static struct fs fs; -static ino_t inomap; -static char blkbuf[BSIZEMAX]; -static unsigned int fsblks; - static uint32_t fs_off; int main(int ac, char **av); @@ -66,14 +59,13 @@ static int mount(const char *device); static void panic(const char *fmt, ...) __dead2; static int printf(const char *fmt, ...); -static int putchar(int c, void *arg); +static int putchar(char c, void *arg); static int vprintf(const char *fmt, va_list ap); static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); -static int __putc(int c, void *arg); static int __puts(const char *s, putc_func_t *putc, void *arg); -static int __sputc(int c, void *arg); +static int __sputc(char c, void *arg); static char *__uitoa(char *buf, u_int val, int base); static char *__ultoa(char *buf, u_long val, int base); @@ -83,19 +75,18 @@ static char *__ultoa(char *buf, u_long val, int base); typedef u_int64_t ofwcell_t; typedef u_int32_t u_ofwh_t; typedef int (*ofwfp_t)(ofwcell_t []); -ofwfp_t ofw; /* the prom Open Firmware entry */ +static ofwfp_t ofw; /* the PROM Open Firmware entry */ void ofw_init(int, int, int, int, ofwfp_t); -ofwh_t ofw_finddevice(const char *); -ofwh_t ofw_open(const char *); -int ofw_getprop(ofwh_t, const char *, void *, size_t); -int ofw_read(ofwh_t, void *, size_t); -int ofw_write(ofwh_t, const void *, size_t); -int ofw_seek(ofwh_t, u_int64_t); -void ofw_exit(void) __dead2; +static ofwh_t ofw_finddevice(const char *); +static ofwh_t ofw_open(const char *); +static int ofw_getprop(ofwh_t, const char *, void *, size_t); +static int ofw_read(ofwh_t, void *, size_t); +static int ofw_write(ofwh_t, const void *, size_t); +static int ofw_seek(ofwh_t, u_int64_t); +static void ofw_exit(void) __dead2; -ofwh_t bootdevh; -ofwh_t stdinh, stdouth; +static ofwh_t stdinh, stdouth; /* * This has to stay here, as the PROM seems to ignore the @@ -138,7 +129,7 @@ ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) exit(main(ac, av)); } -ofwh_t +static ofwh_t ofw_finddevice(const char *name) { ofwcell_t args[] = { @@ -156,7 +147,7 @@ ofw_finddevice(const char *name) return (args[4]); } -int +static int ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) { ofwcell_t args[] = { @@ -178,7 +169,7 @@ ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) return (0); } -ofwh_t +static ofwh_t ofw_open(const char *path) { ofwcell_t args[] = { @@ -196,7 +187,7 @@ ofw_open(const char *path) return (args[4]); } -int +static int ofw_close(ofwh_t devh) { ofwcell_t args[] = { @@ -213,12 +204,12 @@ ofw_close(ofwh_t devh) return (0); } -int +static int ofw_read(ofwh_t devh, void *buf, size_t len) { ofwcell_t args[] = { (ofwcell_t)"read", - 4, + 3, 1, (u_ofwh_t)devh, (ofwcell_t)buf, @@ -233,7 +224,7 @@ ofw_read(ofwh_t devh, void *buf, size_t len) return (0); } -int +static int ofw_write(ofwh_t devh, const void *buf, size_t len) { ofwcell_t args[] = { @@ -253,12 +244,12 @@ ofw_write(ofwh_t devh, const void *buf, size_t len) return (0); } -int +static int ofw_seek(ofwh_t devh, u_int64_t off) { ofwcell_t args[] = { (ofwcell_t)"seek", - 4, + 3, 1, (u_ofwh_t)devh, off >> 32, @@ -273,7 +264,7 @@ ofw_seek(ofwh_t devh, u_int64_t off) return (0); } -void +static void ofw_exit(void) { ofwcell_t args[3]; @@ -299,6 +290,7 @@ bcopy(const void *src, void *dst, size_t len) static void memcpy(void *dst, const void *src, size_t len) { + bcopy(src, dst, len); } @@ -314,6 +306,7 @@ bzero(void *b, size_t len) static int strcmp(const char *s1, const char *s2) { + for (; *s1 == *s2 && *s1; s1++, s2++) ; return ((u_char)*s1 - (u_char)*s2); @@ -431,6 +424,7 @@ load(const char *fname) static int dskread(void *buf, u_int64_t lba, int nblk) { + /* * The Open Firmware should open the correct partition for us. * That means, if we read from offset zero on an open instance handle, @@ -468,7 +462,7 @@ printf(const char *fmt, ...) } static int -putchar(int c, void *arg) +putchar(char c, void *arg) { char buf; @@ -614,7 +608,7 @@ reswitch: c = *fmt++; } static int -__sputc(int c, void *arg) +__sputc(char c, void *arg) { struct sp_data *sp; diff --git a/sys/boot/uboot/lib/Makefile b/sys/boot/uboot/lib/Makefile index 11088f133f2..039a282553c 100644 --- a/sys/boot/uboot/lib/Makefile +++ b/sys/boot/uboot/lib/Makefile @@ -23,7 +23,7 @@ CFLAGS+= -DDISK_DEBUG .endif machine: - ln -sf ${.CURDIR}/../../../${MACHINE_ARCH}/include machine + ln -sf ${.CURDIR}/../../../${MACHINE_CPUARCH}/include machine CLEANFILES+= machine diff --git a/sys/boot/zfs/Makefile b/sys/boot/zfs/Makefile index b48804bc37a..91525d77c8d 100644 --- a/sys/boot/zfs/Makefile +++ b/sys/boot/zfs/Makefile @@ -5,28 +5,29 @@ INTERNALLIB= SRCS+= zfs.c +CFLAGS+= -DBOOTPROG=\"zfsloader\" CFLAGS+= -I${.CURDIR}/../common -I${.CURDIR}/../.. -I. CFLAGS+= -I${.CURDIR}/../../../lib/libstand CFLAGS+= -I${.CURDIR}/../../cddl/boot/zfs CFLAGS+= -ffreestanding -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -mpreferred-stack-boundary=2 CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" CFLAGS+= -mno-sse3 .endif -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" CFLAGS+= -msoft-float .endif -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -m32 -march=i386 .endif CFLAGS+= -Wformat -Wall -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CLEANFILES+= machine machine: ln -sf ${.CURDIR}/../../i386/include machine @@ -34,6 +35,6 @@ machine: .include -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" beforedepend ${OBJS}: machine .endif diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c index 5aec76676f1..a995f574f7b 100644 --- a/sys/boot/zfs/zfs.c +++ b/sys/boot/zfs/zfs.c @@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$"); #include "zfsimpl.c" +#define MAXBDDEV 31 + static int zfs_open(const char *path, struct open_file *f); static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); static int zfs_close(struct open_file *f); @@ -402,7 +404,7 @@ zfs_dev_init(void) * diskN, diskNpM or diskNsM. */ zfs_init(); - for (unit = 0; unit < 32 /* XXX */; unit++) { + for (unit = 0; unit < MAXBDDEV; unit++) { sprintf(devname, "disk%d:", unit); fd = open(devname, O_RDONLY); if (fd == -1) diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index e645ebaa6cd..cb0912099c1 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -376,6 +376,27 @@ vdev_mirror_read(vdev_t *vdev, const blkptr_t *bp, void *buf, return (rc); } +static int +vdev_replacing_read(vdev_t *vdev, const blkptr_t *bp, void *buf, + off_t offset, size_t bytes) +{ + vdev_t *kid; + + /* + * Here we should have two kids: + * First one which is the one we are replacing and we can trust + * only this one to have valid data, but it might not be present. + * Second one is that one we are replacing with. It is most likely + * healthy, but we can't trust it has needed data, so we won't use it. + */ + kid = STAILQ_FIRST(&vdev->v_children); + if (kid == NULL) + return (EIO); + if (kid->v_state != VDEV_STATE_HEALTHY) + return (EIO); + return (kid->v_read(kid, bp, buf, offset, bytes)); +} + static vdev_t * vdev_find(uint64_t guid) { @@ -416,7 +437,7 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) vdev_t *vdev, *kid; const unsigned char *kids; int nkids, i, is_new; - uint64_t is_offline, is_faulted, is_degraded, is_removed; + uint64_t is_offline, is_faulted, is_degraded, is_removed, isnt_present; if (nvlist_find(nvlist, ZPOOL_CONFIG_GUID, DATA_TYPE_UINT64, 0, &guid) @@ -430,12 +451,13 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) if (strcmp(type, VDEV_TYPE_MIRROR) && strcmp(type, VDEV_TYPE_DISK) - && strcmp(type, VDEV_TYPE_RAIDZ)) { + && strcmp(type, VDEV_TYPE_RAIDZ) + && strcmp(type, VDEV_TYPE_REPLACING)) { printf("ZFS: can only boot from disk, mirror or raidz vdevs\n"); return (EIO); } - is_offline = is_removed = is_faulted = is_degraded = 0; + is_offline = is_removed = is_faulted = is_degraded = isnt_present = 0; nvlist_find(nvlist, ZPOOL_CONFIG_OFFLINE, DATA_TYPE_UINT64, 0, &is_offline); @@ -445,6 +467,8 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) &is_faulted); nvlist_find(nvlist, ZPOOL_CONFIG_DEGRADED, DATA_TYPE_UINT64, 0, &is_degraded); + nvlist_find(nvlist, ZPOOL_CONFIG_NOT_PRESENT, DATA_TYPE_UINT64, 0, + &isnt_present); vdev = vdev_find(guid); if (!vdev) { @@ -454,6 +478,8 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) vdev = vdev_create(guid, vdev_mirror_read); else if (!strcmp(type, VDEV_TYPE_RAIDZ)) vdev = vdev_create(guid, vdev_raidz_read); + else if (!strcmp(type, VDEV_TYPE_REPLACING)) + vdev = vdev_create(guid, vdev_replacing_read); else vdev = vdev_create(guid, vdev_disk_read); @@ -470,12 +496,7 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) vdev->v_nparity = 0; if (nvlist_find(nvlist, ZPOOL_CONFIG_PATH, DATA_TYPE_STRING, 0, &path) == 0) { - if (strlen(path) > 5 - && path[0] == '/' - && path[1] == 'd' - && path[2] == 'e' - && path[3] == 'v' - && path[4] == '/') + if (strncmp(path, "/dev/", 5) == 0) path += 5; vdev->v_name = strdup(path); } else { @@ -488,7 +509,16 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) vdev->v_name = strdup(type); } } + } else { + is_new = 0; + } + if (is_new || is_newer) { + /* + * This is either new vdev or we've already seen this vdev, + * but from an older vdev label, so let's refresh its state + * from the newer label. + */ if (is_offline) vdev->v_state = VDEV_STATE_OFFLINE; else if (is_removed) @@ -497,28 +527,10 @@ vdev_init_from_nvlist(const unsigned char *nvlist, vdev_t **vdevp, int is_newer) vdev->v_state = VDEV_STATE_FAULTED; else if (is_degraded) vdev->v_state = VDEV_STATE_DEGRADED; + else if (isnt_present) + vdev->v_state = VDEV_STATE_CANT_OPEN; else vdev->v_state = VDEV_STATE_HEALTHY; - } else { - is_new = 0; - - if (is_newer) { - /* - * We've already seen this vdev, but from an older - * vdev label, so let's refresh its state from the - * newer label. - */ - if (is_offline) - vdev->v_state = VDEV_STATE_OFFLINE; - else if (is_removed) - vdev->v_state = VDEV_STATE_REMOVED; - else if (is_faulted) - vdev->v_state = VDEV_STATE_FAULTED; - else if (is_degraded) - vdev->v_state = VDEV_STATE_DEGRADED; - else - vdev->v_state = VDEV_STATE_HEALTHY; - } } rc = nvlist_find(nvlist, ZPOOL_CONFIG_CHILDREN, @@ -665,7 +677,7 @@ pager_printf(const char *fmt, ...) #endif -#define STATUS_FORMAT " %-16s %-10s\n" +#define STATUS_FORMAT " %s %s\n" static void print_state(int indent, const char *name, vdev_state_t state) @@ -754,6 +766,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap) uint64_t val; uint64_t guid; uint64_t pool_txg, pool_guid; + uint64_t is_log; const char *pool_name; const unsigned char *vdevs; int i, rc, is_newer; @@ -830,6 +843,12 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv, spa_t **spap) return (EIO); } + is_log = 0; + (void) nvlist_find(nvlist, ZPOOL_CONFIG_IS_LOG, DATA_TYPE_UINT64, 0, + &is_log); + if (is_log) + return (EIO); + /* * Create the pool if this is the first time we've seen it. */ @@ -1369,7 +1388,7 @@ fzap_list(spa_t *spa, const dnode_phys_t *dnode) */ value = fzap_leaf_value(&zl, zc); - printf("%-32s 0x%llx\n", name, value); + printf("%s 0x%llx\n", name, value); } } diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index 396802656cd..44d2fa6225f 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #endif /* _KERNEL */ @@ -79,7 +80,8 @@ typedef enum { ADA_FLAG_CAN_TRIM = 0x080, ADA_FLAG_OPEN = 0x100, ADA_FLAG_SCTX_INIT = 0x200, - ADA_FLAG_CAN_CFA = 0x400 + ADA_FLAG_CAN_CFA = 0x400, + ADA_FLAG_CAN_POWERMGT = 0x800 } ada_flags; typedef enum { @@ -180,6 +182,10 @@ static void adashutdown(void *arg, int howto); #define ADA_DEFAULT_SEND_ORDERED 1 #endif +#ifndef ADA_DEFAULT_SPINDOWN_SHUTDOWN +#define ADA_DEFAULT_SPINDOWN_SHUTDOWN 1 +#endif + /* * Most platforms map firmware geometry to actual, but some don't. If * not overridden, default to nothing. @@ -191,6 +197,7 @@ static void adashutdown(void *arg, int howto); static int ada_retry_count = ADA_DEFAULT_RETRY; static int ada_default_timeout = ADA_DEFAULT_TIMEOUT; static int ada_send_ordered = ADA_DEFAULT_SEND_ORDERED; +static int ada_spindown_shutdown = ADA_DEFAULT_SPINDOWN_SHUTDOWN; SYSCTL_NODE(_kern_cam, OID_AUTO, ada, CTLFLAG_RD, 0, "CAM Direct Access Disk driver"); @@ -203,6 +210,9 @@ TUNABLE_INT("kern.cam.ada.default_timeout", &ada_default_timeout); SYSCTL_INT(_kern_cam_ada, OID_AUTO, ada_send_ordered, CTLFLAG_RW, &ada_send_ordered, 0, "Send Ordered Tags"); TUNABLE_INT("kern.cam.ada.ada_send_ordered", &ada_send_ordered); +SYSCTL_INT(_kern_cam_ada, OID_AUTO, spindown_shutdown, CTLFLAG_RW, + &ada_spindown_shutdown, 0, "Spin down upon shutdown"); +TUNABLE_INT("kern.cam.ada.spindown_shutdown", &ada_spindown_shutdown); /* * ADA_ORDEREDTAG_INTERVAL determines how often, relative @@ -665,6 +675,8 @@ adaregister(struct cam_periph *periph, void *arg) softc->flags |= ADA_FLAG_CAN_48BIT; if (cgd->ident_data.support.command2 & ATA_SUPPORT_FLUSHCACHE) softc->flags |= ADA_FLAG_CAN_FLUSHCACHE; + if (cgd->ident_data.support.command1 & ATA_SUPPORT_POWERMGT) + softc->flags |= ADA_FLAG_CAN_POWERMGT; if (cgd->ident_data.satacapabilities & ATA_SUPPORT_NCQ && cgd->inq_flags & SID_CmdQue) softc->flags |= ADA_FLAG_CAN_NCQ; @@ -874,7 +886,8 @@ adastart(struct cam_periph *periph, union ccb *start_ccb) } bioq_remove(&softc->bio_queue, bp); - if ((softc->flags & ADA_FLAG_NEED_OTAG) != 0) { + if ((bp->bio_flags & BIO_ORDERED) != 0 + || (softc->flags & ADA_FLAG_NEED_OTAG) != 0) { softc->flags &= ~ADA_FLAG_NEED_OTAG; softc->ordered_tag_count++; tag_code = 0; @@ -1226,6 +1239,56 @@ adashutdown(void * arg, int howto) /*getcount_only*/0); cam_periph_unlock(periph); } + + if (ada_spindown_shutdown == 0 || + (howto & (RB_HALT | RB_POWEROFF)) == 0) + return; + + TAILQ_FOREACH(periph, &adadriver.units, unit_links) { + union ccb ccb; + + /* If we paniced with lock held - not recurse here. */ + if (cam_periph_owned(periph)) + continue; + cam_periph_lock(periph); + softc = (struct ada_softc *)periph->softc; + /* + * We only spin-down the drive if it is capable of it.. + */ + if ((softc->flags & ADA_FLAG_CAN_POWERMGT) == 0) { + cam_periph_unlock(periph); + continue; + } + + if (bootverbose) + xpt_print(periph->path, "spin-down\n"); + + xpt_setup_ccb(&ccb.ccb_h, periph->path, CAM_PRIORITY_NORMAL); + + ccb.ccb_h.ccb_state = ADA_CCB_DUMP; + cam_fill_ataio(&ccb.ataio, + 1, + adadone, + CAM_DIR_NONE, + 0, + NULL, + 0, + ada_default_timeout*1000); + + ata_28bit_cmd(&ccb.ataio, ATA_STANDBY_IMMEDIATE, 0, 0, 0); + xpt_polled_action(&ccb); + + if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) + xpt_print(periph->path, "Spin-down disk failed\n"); + + if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(ccb.ccb_h.path, + /*relsim_flags*/0, + /*reduction*/0, + /*timeout*/0, + /*getcount_only*/0); + cam_periph_unlock(periph); + } } #endif /* _KERNEL */ diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 7fcdb6f83a7..dc16e9f2db8 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -153,10 +152,6 @@ static struct xpt_softc xsoftc; TUNABLE_INT("kern.cam.boot_delay", &xsoftc.boot_delay); SYSCTL_INT(_kern_cam, OID_AUTO, boot_delay, CTLFLAG_RDTUN, &xsoftc.boot_delay, 0, "Bus registration wait time"); -static int xpt_power_down = 0; -TUNABLE_INT("kern.cam.power_down", &xpt_power_down); -SYSCTL_INT(_kern_cam, OID_AUTO, power_down, CTLFLAG_RW, - &xpt_power_down, 0, "Power down devices on shutdown"); /* Queues for our software interrupt handler */ typedef TAILQ_HEAD(cam_isrq, ccb_hdr) cam_isrq_t; @@ -250,7 +245,6 @@ static struct cam_ed* xpt_find_device(struct cam_et *target, lun_id_t lun_id); static void xpt_config(void *arg); static xpt_devicefunc_t xptpassannouncefunc; -static void xpt_shutdown(void *arg, int howto); static void xptaction(struct cam_sim *sim, union ccb *work_ccb); static void xptpoll(struct cam_sim *sim); static void camisr(void *); @@ -2914,7 +2908,7 @@ xpt_polled_action(union ccb *start_ccb) struct cam_ed *dev; - timeout = start_ccb->ccb_h.timeout; + timeout = start_ccb->ccb_h.timeout * 10; sim = start_ccb->ccb_h.path->bus->sim; devq = sim->devq; dev = start_ccb->ccb_h.path->device; @@ -2930,7 +2924,7 @@ xpt_polled_action(union ccb *start_ccb) while(((devq != NULL && devq->send_openings <= 0) || dev->ccbq.dev_openings < 0) && (--timeout > 0)) { - DELAY(1000); + DELAY(100); (*(sim->sim_poll))(sim); camisr_runqueue(&sim->sim_doneq); } @@ -2946,7 +2940,7 @@ xpt_polled_action(union ccb *start_ccb) if ((start_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_INPROG) break; - DELAY(1000); + DELAY(100); } if (timeout == 0) { /* @@ -4538,12 +4532,6 @@ xpt_config(void *arg) #endif /* CAM_DEBUG_BUS */ #endif /* CAMDEBUG */ - /* Register our shutdown event handler */ - if ((EVENTHANDLER_REGISTER(shutdown_final, xpt_shutdown, - NULL, SHUTDOWN_PRI_FIRST)) == NULL) { - printf("xpt_config: failed to register shutdown event.\n"); - } - periphdriver_init(1); xpt_hold_boot(); callout_init(&xsoftc.boot_callout, 1); @@ -4625,87 +4613,6 @@ xpt_finishconfig_task(void *context, int pending) free(context, M_CAMXPT); } -/* - * Power down all devices when we are going to power down the system. - */ -static void -xpt_shutdown_dev_done(struct cam_periph *periph, union ccb *done_ccb) -{ - - /* No-op. We're polling. */ - return; -} - -static int -xpt_shutdown_dev(struct cam_ed *device, void *arg) -{ - union ccb ccb; - struct cam_path path; - - if (device->flags & CAM_DEV_UNCONFIGURED) - return (1); - - if (device->protocol == PROTO_ATA) { - /* Only power down device if it supports power management. */ - if ((device->ident_data.support.command1 & - ATA_SUPPORT_POWERMGT) == 0) - return (1); - } else if (device->protocol != PROTO_SCSI) - return (1); - - xpt_compile_path(&path, - NULL, - device->target->bus->path_id, - device->target->target_id, - device->lun_id); - xpt_setup_ccb(&ccb.ccb_h, &path, CAM_PRIORITY_NORMAL); - if (device->protocol == PROTO_ATA) { - cam_fill_ataio(&ccb.ataio, - 1, - xpt_shutdown_dev_done, - CAM_DIR_NONE, - 0, - NULL, - 0, - 30*1000); - ata_28bit_cmd(&ccb.ataio, ATA_SLEEP, 0, 0, 0); - } else { - scsi_start_stop(&ccb.csio, - /*retries*/1, - xpt_shutdown_dev_done, - MSG_SIMPLE_Q_TAG, - /*start*/FALSE, - /*load/eject*/FALSE, - /*immediate*/TRUE, - SSD_FULL_SIZE, - /*timeout*/50*1000); - } - xpt_polled_action(&ccb); - - if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) - xpt_print(&path, "Device power down failed\n"); - if ((ccb.ccb_h.status & CAM_DEV_QFRZN) != 0) - cam_release_devq(ccb.ccb_h.path, - /*relsim_flags*/0, - /*reduction*/0, - /*timeout*/0, - /*getcount_only*/0); - xpt_release_path(&path); - return (1); -} - -static void -xpt_shutdown(void * arg, int howto) -{ - - if (!xpt_power_down) - return; - if ((howto & RB_POWEROFF) == 0) - return; - - xpt_for_all_devices(xpt_shutdown_dev, NULL); -} - cam_status xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, struct cam_path *path) diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 8f643611c0c..b3b968cc832 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -1354,7 +1354,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) bioq_remove(&softc->bio_queue, bp); - if ((softc->flags & DA_FLAG_NEED_OTAG) != 0) { + if ((bp->bio_flags & BIO_ORDERED) != 0 + || (softc->flags & DA_FLAG_NEED_OTAG) != 0) { softc->flags &= ~DA_FLAG_NEED_OTAG; softc->ordered_tag_count++; tag_code = MSG_ORDERED_Q_TAG; @@ -1368,7 +1369,8 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) /*retries*/da_retry_count, /*cbfcnp*/dadone, /*tag_action*/tag_code, - /*read_op*/bp->bio_cmd == BIO_READ, + /*read_op*/bp->bio_cmd + == BIO_READ, /*byte2*/0, softc->minimum_cmd_size, /*lba*/bp->bio_pblkno, @@ -1377,17 +1379,24 @@ dastart(struct cam_periph *periph, union ccb *start_ccb) /*data_ptr*/ bp->bio_data, /*dxfer_len*/ bp->bio_bcount, /*sense_len*/SSD_FULL_SIZE, - /*timeout*/da_default_timeout*1000); + da_default_timeout * 1000); break; case BIO_FLUSH: + /* + * BIO_FLUSH doesn't currently communicate + * range data, so we synchronize the cache + * over the whole disk. We also force + * ordered tag semantics the flush applies + * to all previously queued I/O. + */ scsi_synchronize_cache(&start_ccb->csio, /*retries*/1, /*cbfcnp*/dadone, - MSG_SIMPLE_Q_TAG, - /*begin_lba*/0,/* Cover the whole disk */ + MSG_ORDERED_Q_TAG, + /*begin_lba*/0, /*lb_count*/0, SSD_FULL_SIZE, - /*timeout*/da_default_timeout*1000); + da_default_timeout*1000); break; } start_ccb->ccb_h.ccb_state = DA_CCB_BUFFER_IO; @@ -1658,7 +1667,10 @@ dadone(struct cam_periph *periph, union ccb *done_ccb) * give them an 'illegal' value we'll avoid that * here. */ - if (block_size >= MAXPHYS || block_size == 0) { + if (block_size == 0 && maxsector == 0) { + snprintf(announce_buf, sizeof(announce_buf), + "0MB (no media?)"); + } else if (block_size >= MAXPHYS || block_size == 0) { xpt_print(periph->path, "unsupportable block size %ju\n", (uintmax_t) block_size); diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c index 9464ca21ce3..dddfc7b7f43 100644 --- a/sys/cam/scsi/scsi_pass.c +++ b/sys/cam/scsi/scsi_pass.c @@ -169,7 +169,11 @@ passcleanup(struct cam_periph *periph) xpt_print(periph->path, "removing device entry\n"); devstat_remove_entry(softc->device_stats); cam_periph_unlock(periph); - destroy_dev(softc->dev); + /* + * passcleanup() is indirectly a d_close method via passclose, + * so using destroy_dev(9) directly can result in deadlock. + */ + destroy_dev_sched(softc->dev); cam_periph_lock(periph); free(softc, M_DEVBUF); } diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h index 245e01b5da3..34b9a63b72d 100644 --- a/sys/cddl/boot/zfs/zfsimpl.h +++ b/sys/cddl/boot/zfs/zfsimpl.h @@ -546,6 +546,7 @@ typedef enum { #define ZPOOL_CONFIG_NPARITY "nparity" #define ZPOOL_CONFIG_HOSTID "hostid" #define ZPOOL_CONFIG_HOSTNAME "hostname" +#define ZPOOL_CONFIG_IS_LOG "is_log" #define ZPOOL_CONFIG_TIMESTAMP "timestamp" /* not stored on disk */ /* diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_cmn_err.c b/sys/cddl/compat/opensolaris/kern/opensolaris_cmn_err.c index 665ef53bf3a..12e1854d2ce 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_cmn_err.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_cmn_err.c @@ -48,7 +48,7 @@ vcmn_err(int ce, const char *fmt, va_list adx) panic("Solaris: unknown severity level"); } if (ce == CE_PANIC) - panic(buf); + panic("%s", buf); if (ce != CE_IGNORE) vprintf(buf, adx); } diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c b/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c index a24ca83e455..5d4ba062a98 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c @@ -112,18 +112,30 @@ zfs_kmem_free(void *buf, size_t size __unused) free(buf, M_SOLARIS); } +static uint64_t kmem_size_val; + +static void +kmem_size_init(void *unused __unused) +{ + + kmem_size_val = (uint64_t)cnt.v_page_count * PAGE_SIZE; + if (kmem_size_val > vm_kmem_size) + kmem_size_val = vm_kmem_size; +} +SYSINIT(kmem_size_init, SI_SUB_KMEM, SI_ORDER_ANY, kmem_size_init, NULL); + uint64_t kmem_size(void) { - return ((uint64_t)vm_kmem_size); + return (kmem_size_val); } uint64_t kmem_used(void) { - return ((uint64_t)kmem_map->size); + return (kmem_map->size); } static int diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c b/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c index 4f46933d017..4ac666dfbe6 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c @@ -38,7 +38,8 @@ __FBSDID("$FreeBSD$"); char hw_serial[11] = "0"; struct opensolaris_utsname utsname = { - .nodename = "unset" + .nodename = "unset", + .sysname = "SunOS" }; int diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c index c6347c25158..3b22c44082e 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c @@ -332,7 +332,7 @@ secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner) } int -secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self) +secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, uid_t owner) { if (secpolicy_fs_owner(vp->v_mount, cred) == 0) diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c b/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c index 29bcd316ab7..f7b31db6f82 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_taskq.c @@ -73,7 +73,7 @@ taskq_create(const char *name, int nthreads, pri_t pri, int minalloc __unused, tq = kmem_alloc(sizeof(*tq), KM_SLEEP); tq->tq_queue = taskqueue_create(name, M_WAITOK, taskqueue_thread_enqueue, &tq->tq_queue); - (void) taskqueue_start_threads(&tq->tq_queue, nthreads, pri, name); + (void) taskqueue_start_threads(&tq->tq_queue, nthreads, pri, "%s", name); return ((taskq_t *)tq); } diff --git a/sys/cddl/compat/opensolaris/sys/misc.h b/sys/cddl/compat/opensolaris/sys/misc.h index 0343f2f959b..20d335b0674 100644 --- a/sys/cddl/compat/opensolaris/sys/misc.h +++ b/sys/cddl/compat/opensolaris/sys/misc.h @@ -46,6 +46,7 @@ #ifdef _KERNEL struct opensolaris_utsname { char *nodename; + char *sysname; }; extern char hw_serial[11]; diff --git a/sys/cddl/compat/opensolaris/sys/policy.h b/sys/cddl/compat/opensolaris/sys/policy.h index 9fd2092fd7d..f61859b557e 100644 --- a/sys/cddl/compat/opensolaris/sys/policy.h +++ b/sys/cddl/compat/opensolaris/sys/policy.h @@ -47,8 +47,7 @@ int secpolicy_zinject(struct ucred *cred); int secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp); int secpolicy_basic_link(struct vnode *vp, struct ucred *cred); int secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner); -int secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, - boolean_t check_self); +int secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, uid_t owner); int secpolicy_vnode_stky_modify(struct ucred *cred); int secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred); int secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, diff --git a/sys/cddl/compat/opensolaris/sys/vnode.h b/sys/cddl/compat/opensolaris/sys/vnode.h index 1d46956629e..926d0349bdd 100644 --- a/sys/cddl/compat/opensolaris/sys/vnode.h +++ b/sys/cddl/compat/opensolaris/sys/vnode.h @@ -69,11 +69,14 @@ vn_is_readonly(vnode_t *vp) #define vn_vfsunlock(vp) do { } while (0) #define vn_ismntpt(vp) ((vp)->v_type == VDIR && (vp)->v_mountedhere != NULL) #define vn_mountedvfs(vp) ((vp)->v_mountedhere) -#define vn_has_cached_data(vp) ((vp)->v_object != NULL && (vp)->v_object->resident_page_count > 0) +#define vn_has_cached_data(vp) \ + ((vp)->v_object != NULL && ((vp)->v_object->resident_page_count > 0 \ + || (vp)->v_object->cache != NULL)) #define vn_exists(vp) do { } while (0) #define vn_invalid(vp) do { } while (0) #define vn_renamepath(tdvp, svp, tnm, lentnm) do { } while (0) #define vn_free(vp) do { } while (0) +#define vn_matchops(vp, vops) ((vp)->v_op == &(vops)) #define VN_HOLD(v) vref(v) #define VN_RELE(v) vrele(v) diff --git a/sys/cddl/contrib/opensolaris/uts/common/Makefile.files b/sys/cddl/contrib/opensolaris/uts/common/Makefile.files index cf49c78a5b0..2aaf5bcdaff 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/Makefile.files +++ b/sys/cddl/contrib/opensolaris/uts/common/Makefile.files @@ -106,3 +106,6 @@ ZFS_OBJS += \ zfs_vfsops.o \ zfs_vnops.o \ zvol.o + +ZUT_OBJS += \ + zut.o diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c index 70282e9a3a2..f7aeecc13b6 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c @@ -551,20 +551,16 @@ static void dtrace_enabling_provide(dtrace_provider_t *); static int dtrace_enabling_match(dtrace_enabling_t *, int *); static void dtrace_enabling_matchall(void); static dtrace_state_t *dtrace_anon_grab(void); -#if defined(sun) static uint64_t dtrace_helper(int, dtrace_mstate_t *, dtrace_state_t *, uint64_t, uint64_t); static dtrace_helpers_t *dtrace_helpers_create(proc_t *); -#endif static void dtrace_buffer_drop(dtrace_buffer_t *); static intptr_t dtrace_buffer_reserve(dtrace_buffer_t *, size_t, size_t, dtrace_state_t *, dtrace_mstate_t *); static int dtrace_state_option(dtrace_state_t *, dtrace_optid_t, dtrace_optval_t); static int dtrace_ecb_create_enable(dtrace_probe_t *, void *); -#if defined(sun) static void dtrace_helper_provider_destroy(dtrace_helper_provider_t *); -#endif uint16_t dtrace_load16(uintptr_t); uint32_t dtrace_load32(uintptr_t); uint64_t dtrace_load64(uintptr_t); @@ -2784,6 +2780,21 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, return (dtrace_getreg(lwp->lwp_regs, ndx)); return (0); } +#else + case DIF_VAR_UREGS: { + struct trapframe *tframe; + + if (!dtrace_priv_proc(state)) + return (0); + + if ((tframe = curthread->td_frame) == NULL) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); + cpu_core[curcpu].cpuc_dtrace_illval = 0; + return (0); + } + + return (dtrace_getreg(tframe, ndx)); + } #endif case DIF_VAR_CURTHREAD: @@ -2839,7 +2850,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_stackdepth); -#if defined(sun) case DIF_VAR_USTACKDEPTH: if (!dtrace_priv_proc(state)) return (0); @@ -2859,7 +2869,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, mstate->dtms_present |= DTRACE_MSTATE_USTACKDEPTH; } return (mstate->dtms_ustackdepth); -#endif case DIF_VAR_CALLER: if (!dtrace_priv_kernel(state)) @@ -2896,7 +2905,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_caller); -#if defined(sun) case DIF_VAR_UCALLER: if (!dtrace_priv_proc(state)) return (0); @@ -2920,7 +2928,6 @@ dtrace_dif_variable(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t v, } return (mstate->dtms_ucaller); -#endif case DIF_VAR_PROBEPROV: ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); @@ -5736,7 +5743,6 @@ dtrace_action_chill(dtrace_mstate_t *mstate, hrtime_t val) cpu->cpu_dtrace_chilled += val; } -#if defined(sun) static void dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t *buf, uint64_t arg) @@ -5849,7 +5855,6 @@ dtrace_action_ustack(dtrace_mstate_t *mstate, dtrace_state_t *state, out: mstate->dtms_scratch_ptr = old; } -#endif /* * If you're looking for the epicenter of DTrace, you just found it. This @@ -6172,7 +6177,6 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, (uint32_t *)arg0); continue; -#if defined(sun) case DTRACEACT_JSTACK: case DTRACEACT_USTACK: if (!dtrace_priv_proc(state)) @@ -6214,7 +6218,6 @@ dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + 1); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); continue; -#endif default: break; @@ -8141,7 +8144,6 @@ dtrace_helper_provide(dof_helper_t *dhp, pid_t pid) dtrace_enabling_matchall(); } -#if defined(sun) static void dtrace_helper_provider_remove_one(dof_helper_t *dhp, dof_sec_t *sec, pid_t pid) { @@ -8189,7 +8191,6 @@ dtrace_helper_provider_remove(dof_helper_t *dhp, pid_t pid) dtrace_helper_provider_remove_one(dhp, sec, pid); } } -#endif /* * DTrace Meta Provider-to-Framework API Functions @@ -8729,7 +8730,6 @@ dtrace_difo_validate(dtrace_difo_t *dp, dtrace_vstate_t *vstate, uint_t nregs, return (err); } -#if defined(sun) /* * Validate a DTrace DIF object that it is to be used as a helper. Helpers * are much more constrained than normal DIFOs. Specifically, they may @@ -8887,7 +8887,6 @@ dtrace_difo_validate_helper(dtrace_difo_t *dp) return (err); } -#endif /* * Returns 1 if the expression in the DIF object can be cached on a per-thread @@ -9219,7 +9218,6 @@ dtrace_difo_init(dtrace_difo_t *dp, dtrace_vstate_t *vstate) dtrace_difo_hold(dp); } -#if defined(sun) static dtrace_difo_t * dtrace_difo_duplicate(dtrace_difo_t *dp, dtrace_vstate_t *vstate) { @@ -9263,7 +9261,6 @@ dtrace_difo_duplicate(dtrace_difo_t *dp, dtrace_vstate_t *vstate) dtrace_difo_init(new, vstate); return (new); } -#endif static void dtrace_difo_destroy(dtrace_difo_t *dp, dtrace_vstate_t *vstate) @@ -13791,7 +13788,6 @@ dtrace_anon_property(void) } } -#if defined(sun) /* * DTrace Helper Functions */ @@ -13855,9 +13851,7 @@ dtrace_helper_trace(dtrace_helper_action_t *helper, ((uint64_t *)(uintptr_t)svar->dtsv_data)[curcpu]; } } -#endif -#if defined(sun) static uint64_t dtrace_helper(int which, dtrace_mstate_t *mstate, dtrace_state_t *state, uint64_t arg0, uint64_t arg1) @@ -13865,7 +13859,7 @@ dtrace_helper(int which, dtrace_mstate_t *mstate, uint16_t *flags = &cpu_core[curcpu].cpuc_dtrace_flags; uint64_t sarg0 = mstate->dtms_arg[0]; uint64_t sarg1 = mstate->dtms_arg[1]; - uint64_t rval; + uint64_t rval = 0; dtrace_helpers_t *helpers = curproc->p_dtrace_helpers; dtrace_helper_action_t *helper; dtrace_vstate_t *vstate; @@ -14056,9 +14050,7 @@ dtrace_helper_destroygen(int gen) return (0); } -#endif -#if defined(sun) static int dtrace_helper_validate(dtrace_helper_action_t *helper) { @@ -14073,9 +14065,7 @@ dtrace_helper_validate(dtrace_helper_action_t *helper) return (err == 0); } -#endif -#if defined(sun) static int dtrace_helper_action_add(int which, dtrace_ecbdesc_t *ep) { @@ -14622,12 +14612,17 @@ dtrace_helpers_create(proc_t *p) return (help); } -static void -dtrace_helpers_destroy(void) +#if defined(sun) +static +#endif +void +dtrace_helpers_destroy(proc_t *p) { dtrace_helpers_t *help; dtrace_vstate_t *vstate; +#if defined(sun) proc_t *p = curproc; +#endif int i; mutex_enter(&dtrace_lock); @@ -14714,7 +14709,10 @@ dtrace_helpers_destroy(void) mutex_exit(&dtrace_lock); } -static void +#if defined(sun) +static +#endif +void dtrace_helpers_duplicate(proc_t *from, proc_t *to) { dtrace_helpers_t *help, *newhelp; @@ -14795,7 +14793,6 @@ dtrace_helpers_duplicate(proc_t *from, proc_t *to) if (hasprovs) dtrace_helper_provider_register(to, newhelp, NULL); } -#endif #if defined(sun) /* @@ -16466,6 +16463,7 @@ _fini(void) #else static d_ioctl_t dtrace_ioctl; +static d_ioctl_t dtrace_ioctl_helper; static void dtrace_load(void *); static int dtrace_unload(void); #if __FreeBSD_version < 800039 @@ -16474,6 +16472,7 @@ static struct clonedevs *dtrace_clones; /* Ptr to the array of cloned devices. static eventhandler_tag eh_tag; /* Event handler tag. */ #else static struct cdev *dtrace_dev; +static struct cdev *helper_dev; #endif void dtrace_invop_init(void); @@ -16488,6 +16487,13 @@ static struct cdevsw dtrace_cdevsw = { .d_name = "dtrace", }; +static struct cdevsw helper_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE | D_NEEDMINOR, + .d_ioctl = dtrace_ioctl_helper, + .d_name = "helper", +}; + #include #if __FreeBSD_version < 800039 #include diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c index 45839cbb8f9..4599a3238b0 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c +++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/fasttrap.c @@ -17,6 +17,10 @@ * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END + * + * Portions Copyright 2010 The FreeBSD Foundation + * + * $FreeBSD$ */ /* @@ -24,7 +28,9 @@ * Use is subject to license terms. */ +#if defined(sun) #pragma ident "%Z%%M% %I% %E% SMI" +#endif #include #include @@ -32,11 +38,15 @@ #include #include #include +#if defined(sun) #include +#endif #include #include #include +#if defined(sun) #include +#endif #include #include #include @@ -44,9 +54,17 @@ #include #include #include -#include #include +#if defined(sun) #include +#endif +#include +#include +#if !defined(sun) +#include +#include +#include +#endif /* * User-Land Trap-Based Tracing @@ -125,11 +143,20 @@ * never hold the provider lock and creation lock simultaneously */ -static dev_info_t *fasttrap_devi; +static d_open_t fasttrap_open; +static d_ioctl_t fasttrap_ioctl; + +static struct cdevsw fasttrap_cdevsw = { + .d_version = D_VERSION, + .d_open = fasttrap_open, + .d_ioctl = fasttrap_ioctl, + .d_name = "fasttrap", +}; +static struct cdev *fasttrap_cdev; static dtrace_meta_provider_id_t fasttrap_meta_id; -static timeout_id_t fasttrap_timeout; -static kmutex_t fasttrap_cleanup_mtx; +static struct callout fasttrap_timeout; +static struct mtx fasttrap_cleanup_mtx; static uint_t fasttrap_cleanup_work; /* @@ -181,6 +208,10 @@ static void fasttrap_proc_release(fasttrap_proc_t *); #define FASTTRAP_PROCS_INDEX(pid) ((pid) & fasttrap_procs.fth_mask) +#if !defined(sun) +static kmutex_t fasttrap_cpuc_pid_lock[MAXCPU]; +#endif + static int fasttrap_highbit(ulong_t i) { @@ -229,6 +260,7 @@ fasttrap_hash_str(const char *p) void fasttrap_sigtrap(proc_t *p, kthread_t *t, uintptr_t pc) { +#if defined(sun) sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); sqp->sq_info.si_signo = SIGTRAP; @@ -241,6 +273,17 @@ fasttrap_sigtrap(proc_t *p, kthread_t *t, uintptr_t pc) if (t != NULL) aston(t); +#else + ksiginfo_t *ksi = kmem_zalloc(sizeof (ksiginfo_t), KM_SLEEP); + + ksiginfo_init(ksi); + ksi->ksi_signo = SIGTRAP; + ksi->ksi_code = TRAP_DTRACE; + ksi->ksi_addr = (caddr_t)pc; + PROC_LOCK(p); + (void) tdksignal(t, SIGTRAP, ksi); + PROC_UNLOCK(p); +#endif } /* @@ -257,9 +300,9 @@ fasttrap_mod_barrier(uint64_t gen) fasttrap_mod_gen++; - for (i = 0; i < NCPU; i++) { - mutex_enter(&cpu_core[i].cpuc_pid_lock); - mutex_exit(&cpu_core[i].cpuc_pid_lock); + CPU_FOREACH(i) { + mutex_enter(&fasttrap_cpuc_pid_lock[i]); + mutex_exit(&fasttrap_cpuc_pid_lock[i]); } } @@ -274,16 +317,15 @@ fasttrap_pid_cleanup_cb(void *data) fasttrap_provider_t **fpp, *fp; fasttrap_bucket_t *bucket; dtrace_provider_id_t provid; - int i, later; + int i, later = 0; static volatile int in = 0; ASSERT(in == 0); in = 1; - mutex_enter(&fasttrap_cleanup_mtx); while (fasttrap_cleanup_work) { fasttrap_cleanup_work = 0; - mutex_exit(&fasttrap_cleanup_mtx); + mtx_unlock(&fasttrap_cleanup_mtx); later = 0; @@ -349,10 +391,12 @@ fasttrap_pid_cleanup_cb(void *data) mutex_exit(&bucket->ftb_mtx); } - mutex_enter(&fasttrap_cleanup_mtx); + mtx_lock(&fasttrap_cleanup_mtx); } +#if 0 ASSERT(fasttrap_timeout != 0); +#endif /* * If we were unable to remove a retired provider, try again after @@ -364,14 +408,17 @@ fasttrap_pid_cleanup_cb(void *data) * get a chance to do that work if and when the timeout is reenabled * (if detach fails). */ - if (later > 0 && fasttrap_timeout != (timeout_id_t)1) - fasttrap_timeout = timeout(&fasttrap_pid_cleanup_cb, NULL, hz); + if (later > 0 && callout_active(&fasttrap_timeout)) + callout_reset(&fasttrap_timeout, hz, &fasttrap_pid_cleanup_cb, + NULL); else if (later > 0) fasttrap_cleanup_work = 1; - else - fasttrap_timeout = 0; + else { +#if !defined(sun) + /* Nothing to be done for FreeBSD */ +#endif + } - mutex_exit(&fasttrap_cleanup_mtx); in = 0; } @@ -381,11 +428,11 @@ fasttrap_pid_cleanup_cb(void *data) static void fasttrap_pid_cleanup(void) { - mutex_enter(&fasttrap_cleanup_mtx); + + mtx_lock(&fasttrap_cleanup_mtx); fasttrap_cleanup_work = 1; - if (fasttrap_timeout == 0) - fasttrap_timeout = timeout(&fasttrap_pid_cleanup_cb, NULL, 1); - mutex_exit(&fasttrap_cleanup_mtx); + callout_reset(&fasttrap_timeout, 1, &fasttrap_pid_cleanup_cb, NULL); + mtx_unlock(&fasttrap_cleanup_mtx); } /* @@ -400,9 +447,35 @@ fasttrap_fork(proc_t *p, proc_t *cp) pid_t ppid = p->p_pid; int i; +#if defined(sun) ASSERT(curproc == p); ASSERT(p->p_proc_flag & P_PR_LOCK); +#else + PROC_LOCK_ASSERT(p, MA_OWNED); +#endif +#if defined(sun) ASSERT(p->p_dtrace_count > 0); +#else + if (p->p_dtrace_helpers) { + /* + * dtrace_helpers_duplicate() allocates memory. + */ + _PHOLD(cp); + PROC_UNLOCK(p); + PROC_UNLOCK(cp); + dtrace_helpers_duplicate(p, cp); + PROC_LOCK(cp); + PROC_LOCK(p); + _PRELE(cp); + } + /* + * This check is purposely here instead of in kern_fork.c because, + * for legal resons, we cannot include the dtrace_cddl.h header + * inside kern_fork.c and insert if-clause there. + */ + if (p->p_dtrace_count == 0) + return; +#endif ASSERT(cp->p_dtrace_count == 0); /* @@ -419,9 +492,13 @@ fasttrap_fork(proc_t *p, proc_t *cp) * We don't have to worry about the child process disappearing * because we're in fork(). */ - mutex_enter(&cp->p_lock); +#if defined(sun) + mtx_lock_spin(&cp->p_slock); sprlock_proc(cp); - mutex_exit(&cp->p_lock); + mtx_unlock_spin(&cp->p_slock); +#else + _PHOLD(cp); +#endif /* * Iterate over every tracepoint looking for ones that belong to the @@ -451,8 +528,12 @@ fasttrap_fork(proc_t *p, proc_t *cp) mutex_exit(&bucket->ftb_mtx); } +#if defined(sun) mutex_enter(&cp->p_lock); sprunlock(cp); +#else + _PRELE(cp); +#endif } /* @@ -463,24 +544,30 @@ fasttrap_fork(proc_t *p, proc_t *cp) static void fasttrap_exec_exit(proc_t *p) { +#if defined(sun) ASSERT(p == curproc); - ASSERT(MUTEX_HELD(&p->p_lock)); - - mutex_exit(&p->p_lock); +#endif + PROC_LOCK_ASSERT(p, MA_OWNED); + _PHOLD(p); + PROC_UNLOCK(p); /* * We clean up the pid provider for this process here; user-land * static probes are handled by the meta-provider remove entry point. */ fasttrap_provider_retire(p->p_pid, FASTTRAP_PID_NAME, 0); - - mutex_enter(&p->p_lock); +#if !defined(sun) + if (p->p_dtrace_helpers) + dtrace_helpers_destroy(p); +#endif + PROC_LOCK(p); + _PRELE(p); } /*ARGSUSED*/ static void -fasttrap_pid_provide(void *arg, const dtrace_probedesc_t *desc) +fasttrap_pid_provide(void *arg, dtrace_probedesc_t *desc) { /* * There are no "default" pid probes. @@ -504,7 +591,9 @@ fasttrap_tracepoint_enable(proc_t *p, fasttrap_probe_t *probe, uint_t index) ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); +#if defined(sun) ASSERT(!(p->p_flag & SVFORK)); +#endif /* * Before we make any modifications, make sure we've imposed a barrier @@ -610,7 +699,9 @@ again: * Increment the count of the number of tracepoints active in * the victim process. */ +#if defined(sun) ASSERT(p->p_proc_flag & P_PR_LOCK); +#endif p->p_dtrace_count++; return (rc); @@ -666,7 +757,7 @@ fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index) fasttrap_bucket_t *bucket; fasttrap_provider_t *provider = probe->ftp_prov; fasttrap_tracepoint_t **pp, *tp; - fasttrap_id_t *id, **idp; + fasttrap_id_t *id, **idp = NULL; pid_t pid; uintptr_t pc; @@ -800,7 +891,9 @@ fasttrap_tracepoint_disable(proc_t *p, fasttrap_probe_t *probe, uint_t index) * Decrement the count of the number of tracepoints active * in the victim process. */ +#if defined(sun) ASSERT(p->p_proc_flag & P_PR_LOCK); +#endif p->p_dtrace_count--; } @@ -851,26 +944,31 @@ fasttrap_enable_callbacks(void) static void fasttrap_disable_callbacks(void) { +#if defined(sun) ASSERT(MUTEX_HELD(&cpu_lock)); +#endif + mutex_enter(&fasttrap_count_mtx); ASSERT(fasttrap_pid_count > 0); fasttrap_pid_count--; if (fasttrap_pid_count == 0) { +#if defined(sun) cpu_t *cur, *cpu = CPU; for (cur = cpu->cpu_next_onln; cur != cpu; cur = cur->cpu_next_onln) { rw_enter(&cur->cpu_ft_lock, RW_WRITER); } - +#endif dtrace_pid_probe_ptr = NULL; dtrace_return_probe_ptr = NULL; - +#if defined(sun) for (cur = cpu->cpu_next_onln; cur != cpu; cur = cur->cpu_next_onln) { rw_exit(&cur->cpu_ft_lock); } +#endif } mutex_exit(&fasttrap_count_mtx); } @@ -880,13 +978,16 @@ static void fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) { fasttrap_probe_t *probe = parg; - proc_t *p; + proc_t *p = NULL; int i, rc; + ASSERT(probe != NULL); ASSERT(!probe->ftp_enabled); ASSERT(id == probe->ftp_id); +#if defined(sun) ASSERT(MUTEX_HELD(&cpu_lock)); +#endif /* * Increment the count of enabled probes on this probe's provider; @@ -911,6 +1012,7 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) * a fork in which the traced process is being born and we're copying * USDT probes. Otherwise, the process is gone so bail. */ +#if defined(sun) if ((p = sprlock(probe->ftp_pid)) == NULL) { if ((curproc->p_flag & SFORKING) == 0) return; @@ -934,12 +1036,23 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) ASSERT(!(p->p_flag & SVFORK)); mutex_exit(&p->p_lock); +#else + if ((p = pfind(probe->ftp_pid)) == NULL) + return; +#endif /* * We have to enable the trap entry point before any user threads have * the chance to execute the trap instruction we're about to place * in their process's text. */ +#ifdef __FreeBSD__ + /* + * pfind() returns a locked process. + */ + _PHOLD(p); + PROC_UNLOCK(p); +#endif fasttrap_enable_callbacks(); /* @@ -967,8 +1080,12 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) i--; } +#if defined(sun) mutex_enter(&p->p_lock); sprunlock(p); +#else + PRELE(p); +#endif /* * Since we're not actually enabling this probe, @@ -978,9 +1095,12 @@ fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) return; } } - +#if defined(sun) mutex_enter(&p->p_lock); sprunlock(p); +#else + PRELE(p); +#endif probe->ftp_enabled = 1; } @@ -996,18 +1116,22 @@ fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg) ASSERT(id == probe->ftp_id); + mutex_enter(&provider->ftp_mtx); + /* * We won't be able to acquire a /proc-esque lock on the process * iff the process is dead and gone. In this case, we rely on the * provider lock as a point of mutual exclusion to prevent other * DTrace consumers from disabling this probe. */ - if ((p = sprlock(probe->ftp_pid)) != NULL) { - ASSERT(!(p->p_flag & SVFORK)); - mutex_exit(&p->p_lock); + if ((p = pfind(probe->ftp_pid)) == NULL) { + mutex_exit(&provider->ftp_mtx); + return; } - - mutex_enter(&provider->ftp_mtx); +#ifdef __FreeBSD__ + _PHOLD(p); + PROC_UNLOCK(p); +#endif /* * Disable all the associated tracepoints (for fully enabled probes). @@ -1030,9 +1154,6 @@ fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg) if (provider->ftp_retired && !provider->ftp_marked) whack = provider->ftp_marked = 1; mutex_exit(&provider->ftp_mtx); - - mutex_enter(&p->p_lock); - sprunlock(p); } else { /* * If the process is dead, we're just waiting for the @@ -1046,12 +1167,17 @@ fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg) if (whack) fasttrap_pid_cleanup(); +#ifdef __FreeBSD__ + PRELE(p); +#endif if (!probe->ftp_enabled) return; probe->ftp_enabled = 0; +#if defined(sun) ASSERT(MUTEX_HELD(&cpu_lock)); +#endif fasttrap_disable_callbacks(); } @@ -1163,6 +1289,7 @@ fasttrap_proc_lookup(pid_t pid) fasttrap_bucket_t *bucket; fasttrap_proc_t *fprc, *new_fprc; + bucket = &fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)]; mutex_enter(&bucket->ftb_mtx); @@ -1189,6 +1316,10 @@ fasttrap_proc_lookup(pid_t pid) new_fprc->ftpc_pid = pid; new_fprc->ftpc_rcount = 1; new_fprc->ftpc_acount = 1; +#if !defined(sun) + mutex_init(&new_fprc->ftpc_mtx, "fasttrap proc mtx", MUTEX_DEFAULT, + NULL); +#endif mutex_enter(&bucket->ftb_mtx); @@ -1311,17 +1442,8 @@ fasttrap_provider_lookup(pid_t pid, const char *name, * Make sure the process exists, isn't a child created as the result * of a vfork(2), and isn't a zombie (but may be in fork). */ - mutex_enter(&pidlock); - if ((p = prfind(pid)) == NULL) { - mutex_exit(&pidlock); + if ((p = pfind(pid)) == NULL) return (NULL); - } - mutex_enter(&p->p_lock); - mutex_exit(&pidlock); - if (p->p_flag & (SVFORK | SEXITING)) { - mutex_exit(&p->p_lock); - return (NULL); - } /* * Increment p_dtrace_probes so that the process knows to inform us @@ -1334,15 +1456,18 @@ fasttrap_provider_lookup(pid_t pid, const char *name, * Grab the credentials for this process so we have * something to pass to dtrace_register(). */ - mutex_enter(&p->p_crlock); - crhold(p->p_cred); - cred = p->p_cred; - mutex_exit(&p->p_crlock); - mutex_exit(&p->p_lock); + PROC_LOCK_ASSERT(p, MA_OWNED); + crhold(p->p_ucred); + cred = p->p_ucred; + PROC_UNLOCK(p); new_fp = kmem_zalloc(sizeof (fasttrap_provider_t), KM_SLEEP); new_fp->ftp_pid = pid; new_fp->ftp_proc = fasttrap_proc_lookup(pid); +#if !defined(sun) + mutex_init(&new_fp->ftp_mtx, "provider mtx", MUTEX_DEFAULT, NULL); + mutex_init(&new_fp->ftp_cmtx, "lock on creating", MUTEX_DEFAULT, NULL); +#endif ASSERT(new_fp->ftp_proc != NULL); @@ -1420,6 +1545,10 @@ fasttrap_provider_free(fasttrap_provider_t *provider) fasttrap_proc_release(provider->ftp_proc); +#if !defined(sun) + mutex_destroy(&provider->ftp_mtx); + mutex_destroy(&provider->ftp_cmtx); +#endif kmem_free(provider, sizeof (fasttrap_provider_t)); /* @@ -1429,17 +1558,14 @@ fasttrap_provider_free(fasttrap_provider_t *provider) * corresponds to this process's hash chain in the provider hash * table. Don't sweat it if we can't find the process. */ - mutex_enter(&pidlock); - if ((p = prfind(pid)) == NULL) { - mutex_exit(&pidlock); + if ((p = pfind(pid)) == NULL) { return; } - mutex_enter(&p->p_lock); - mutex_exit(&pidlock); - p->p_dtrace_probes--; - mutex_exit(&p->p_lock); +#if !defined(sun) + PROC_UNLOCK(p); +#endif } static void @@ -1527,7 +1653,7 @@ fasttrap_add_probe(fasttrap_probe_spec_t *pdata) fasttrap_probe_t *pp; fasttrap_tracepoint_t *tp; char *name; - int i, aframes, whack; + int i, aframes = 0, whack; /* * There needs to be at least one desired trace point. @@ -1715,7 +1841,7 @@ fasttrap_meta_provide(void *arg, dtrace_helper_provdesc_t *dhpv, pid_t pid) */ if (strlen(dhpv->dthpv_provname) + 10 >= sizeof (provider->ftp_name)) { - cmn_err(CE_WARN, "failed to instantiate provider %s: " + printf("failed to instantiate provider %s: " "name too long to accomodate pid", dhpv->dthpv_provname); return (NULL); } @@ -1724,7 +1850,7 @@ fasttrap_meta_provide(void *arg, dtrace_helper_provdesc_t *dhpv, pid_t pid) * Don't let folks spoof the true pid provider. */ if (strcmp(dhpv->dthpv_provname, FASTTRAP_PID_NAME) == 0) { - cmn_err(CE_WARN, "failed to instantiate provider %s: " + printf("failed to instantiate provider %s: " "%s is an invalid name", dhpv->dthpv_provname, FASTTRAP_PID_NAME); return (NULL); @@ -1747,7 +1873,7 @@ fasttrap_meta_provide(void *arg, dtrace_helper_provdesc_t *dhpv, pid_t pid) if ((provider = fasttrap_provider_lookup(pid, dhpv->dthpv_provname, &dhpv->dthpv_pattr)) == NULL) { - cmn_err(CE_WARN, "failed to instantiate provider %s for " + printf("failed to instantiate provider %s for " "process %u", dhpv->dthpv_provname, (uint_t)pid); return (NULL); } @@ -1908,15 +2034,21 @@ static dtrace_mops_t fasttrap_mops = { /*ARGSUSED*/ static int -fasttrap_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) +fasttrap_open(struct cdev *dev __unused, int oflags __unused, + int devtype __unused, struct thread *td __unused) { return (0); } /*ARGSUSED*/ static int -fasttrap_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) +fasttrap_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int fflag, + struct thread *td) { +#ifdef notyet + struct kinfo_proc kp; + const cred_t *cr = td->td_ucred; +#endif if (!dtrace_attached()) return (EAGAIN); @@ -1928,9 +2060,13 @@ fasttrap_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) int ret; char *c; +#if defined(sun) if (copyin(&uprobe->ftps_noffs, &noffs, sizeof (uprobe->ftps_noffs))) return (EFAULT); +#else + noffs = uprobe->ftps_noffs; +#endif /* * Probes must have at least one tracepoint. @@ -1946,10 +2082,19 @@ fasttrap_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) probe = kmem_alloc(size, KM_SLEEP); +#if defined(sun) if (copyin(uprobe, probe, size) != 0) { kmem_free(probe, size); return (EFAULT); } +#else + memcpy(probe, uprobe, sizeof(*probe)); + if (noffs > 1 && copyin(uprobe + 1, probe + 1, size) != 0) { + kmem_free(probe, size); + return (EFAULT); + } +#endif + /* * Verify that the function and module strings contain no @@ -1969,30 +2114,52 @@ fasttrap_ioctl(dev_t dev, int cmd, intptr_t arg, int md, cred_t *cr, int *rv) } } +#ifdef notyet if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { proc_t *p; pid_t pid = probe->ftps_pid; +#if defined(sun) mutex_enter(&pidlock); +#endif /* * Report an error if the process doesn't exist * or is actively being birthed. */ - if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { + p = pfind(pid); + if (p) + fill_kinfo_proc(p, &kp); + if (p == NULL || kp.ki_stat == SIDL) { +#if defined(sun) mutex_exit(&pidlock); +#endif return (ESRCH); } +#if defined(sun) mutex_enter(&p->p_lock); mutex_exit(&pidlock); +#else + PROC_LOCK_ASSERT(p, MA_OWNED); +#endif +#ifdef notyet if ((ret = priv_proc_cred_perm(cr, p, NULL, VREAD | VWRITE)) != 0) { +#if defined(sun) mutex_exit(&p->p_lock); +#else + PROC_UNLOCK(p); +#endif return (ret); } - +#endif /* notyet */ +#if defined(sun) mutex_exit(&p->p_lock); +#else + PROC_UNLOCK(p); +#endif } +#endif /* notyet */ ret = fasttrap_add_probe(probe); err: @@ -2004,35 +2171,62 @@ err: fasttrap_instr_query_t instr; fasttrap_tracepoint_t *tp; uint_t index; +#if defined(sun) int ret; +#endif +#if defined(sun) if (copyin((void *)arg, &instr, sizeof (instr)) != 0) return (EFAULT); +#endif +#ifdef notyet if (!PRIV_POLICY_CHOICE(cr, PRIV_ALL, B_FALSE)) { proc_t *p; pid_t pid = instr.ftiq_pid; +#if defined(sun) mutex_enter(&pidlock); +#endif /* * Report an error if the process doesn't exist * or is actively being birthed. */ - if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) { + p = pfind(pid); + if (p) + fill_kinfo_proc(p, &kp); + if (p == NULL || kp.ki_stat == SIDL) { +#if defined(sun) mutex_exit(&pidlock); +#endif return (ESRCH); } +#if defined(sun) mutex_enter(&p->p_lock); mutex_exit(&pidlock); +#else + PROC_LOCK_ASSERT(p, MA_OWNED); +#endif +#ifdef notyet if ((ret = priv_proc_cred_perm(cr, p, NULL, VREAD)) != 0) { +#if defined(sun) mutex_exit(&p->p_lock); +#else + PROC_UNLOCK(p); +#endif return (ret); } +#endif /* notyet */ +#if defined(sun) mutex_exit(&p->p_lock); +#else + PROC_UNLOCK(p); +#endif } +#endif /* notyet */ index = FASTTRAP_TPOINTS_INDEX(instr.ftiq_pid, instr.ftiq_pc); @@ -2065,84 +2259,45 @@ err: return (EINVAL); } -static struct cb_ops fasttrap_cb_ops = { - fasttrap_open, /* open */ - nodev, /* close */ - nulldev, /* strategy */ - nulldev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - fasttrap_ioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - nochpoll, /* poll */ - ddi_prop_op, /* cb_prop_op */ - 0, /* streamtab */ - D_NEW | D_MP /* Driver compatibility flag */ -}; - -/*ARGSUSED*/ static int -fasttrap_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) -{ - int error; - - switch (infocmd) { - case DDI_INFO_DEVT2DEVINFO: - *result = (void *)fasttrap_devi; - error = DDI_SUCCESS; - break; - case DDI_INFO_DEVT2INSTANCE: - *result = (void *)0; - error = DDI_SUCCESS; - break; - default: - error = DDI_FAILURE; - } - return (error); -} - -static int -fasttrap_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +fasttrap_load(void) { ulong_t nent; + int i; - switch (cmd) { - case DDI_ATTACH: - break; - case DDI_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } + /* Create the /dev/dtrace/fasttrap entry. */ + fasttrap_cdev = make_dev(&fasttrap_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "dtrace/fasttrap"); - if (ddi_create_minor_node(devi, "fasttrap", S_IFCHR, 0, - DDI_PSEUDO, NULL) == DDI_FAILURE) { - ddi_remove_minor_node(devi, NULL); - return (DDI_FAILURE); - } - - ddi_report_dev(devi); - fasttrap_devi = devi; + mtx_init(&fasttrap_cleanup_mtx, "fasttrap clean", "dtrace", MTX_DEF); + callout_init_mtx(&fasttrap_timeout, &fasttrap_cleanup_mtx, 0); + mutex_init(&fasttrap_count_mtx, "fasttrap count mtx", MUTEX_DEFAULT, + NULL); /* * Install our hooks into fork(2), exec(2), and exit(2). */ - dtrace_fasttrap_fork_ptr = &fasttrap_fork; - dtrace_fasttrap_exit_ptr = &fasttrap_exec_exit; - dtrace_fasttrap_exec_ptr = &fasttrap_exec_exit; + dtrace_fasttrap_fork = &fasttrap_fork; + dtrace_fasttrap_exit = &fasttrap_exec_exit; + dtrace_fasttrap_exec = &fasttrap_exec_exit; +#if defined(sun) fasttrap_max = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "fasttrap-max-probes", FASTTRAP_MAX_DEFAULT); +#else + fasttrap_max = FASTTRAP_MAX_DEFAULT; +#endif fasttrap_total = 0; /* * Conjure up the tracepoints hashtable... */ +#if defined(sun) nent = ddi_getprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, "fasttrap-hash-size", FASTTRAP_TPOINTS_DEFAULT_SIZE); +#else + nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; +#endif if (nent == 0 || nent > 0x1000000) nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; @@ -2155,6 +2310,11 @@ fasttrap_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) fasttrap_tpoints.fth_mask = fasttrap_tpoints.fth_nent - 1; fasttrap_tpoints.fth_table = kmem_zalloc(fasttrap_tpoints.fth_nent * sizeof (fasttrap_bucket_t), KM_SLEEP); +#if !defined(sun) + for (i = 0; i < fasttrap_tpoints.fth_nent; i++) + mutex_init(&fasttrap_tpoints.fth_table[i].ftb_mtx, + "tracepoints bucket mtx", MUTEX_DEFAULT, NULL); +#endif /* * ... and the providers hash table... @@ -2168,6 +2328,11 @@ fasttrap_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) fasttrap_provs.fth_mask = fasttrap_provs.fth_nent - 1; fasttrap_provs.fth_table = kmem_zalloc(fasttrap_provs.fth_nent * sizeof (fasttrap_bucket_t), KM_SLEEP); +#if !defined(sun) + for (i = 0; i < fasttrap_provs.fth_nent; i++) + mutex_init(&fasttrap_provs.fth_table[i].ftb_mtx, + "providers bucket mtx", MUTEX_DEFAULT, NULL); +#endif /* * ... and the procs hash table. @@ -2181,27 +2346,27 @@ fasttrap_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) fasttrap_procs.fth_mask = fasttrap_procs.fth_nent - 1; fasttrap_procs.fth_table = kmem_zalloc(fasttrap_procs.fth_nent * sizeof (fasttrap_bucket_t), KM_SLEEP); +#if !defined(sun) + for (i = 0; i < fasttrap_procs.fth_nent; i++) + mutex_init(&fasttrap_procs.fth_table[i].ftb_mtx, + "processes bucket mtx", MUTEX_DEFAULT, NULL); + + CPU_FOREACH(i) { + mutex_init(&fasttrap_cpuc_pid_lock[i], "fasttrap barrier", + MUTEX_DEFAULT, NULL); + } +#endif (void) dtrace_meta_register("fasttrap", &fasttrap_mops, NULL, &fasttrap_meta_id); - return (DDI_SUCCESS); + return (0); } static int -fasttrap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) +fasttrap_unload(void) { int i, fail = 0; - timeout_id_t tmp; - - switch (cmd) { - case DDI_DETACH: - break; - case DDI_SUSPEND: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } /* * Unregister the meta-provider to make sure no new fasttrap- @@ -2212,28 +2377,16 @@ fasttrap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) */ if (fasttrap_meta_id != DTRACE_METAPROVNONE && dtrace_meta_unregister(fasttrap_meta_id) != 0) - return (DDI_FAILURE); + return (-1); /* * Prevent any new timeouts from running by setting fasttrap_timeout * to a non-zero value, and wait for the current timeout to complete. */ - mutex_enter(&fasttrap_cleanup_mtx); + mtx_lock(&fasttrap_cleanup_mtx); fasttrap_cleanup_work = 0; - - while (fasttrap_timeout != (timeout_id_t)1) { - tmp = fasttrap_timeout; - fasttrap_timeout = (timeout_id_t)1; - - if (tmp != 0) { - mutex_exit(&fasttrap_cleanup_mtx); - (void) untimeout(tmp); - mutex_enter(&fasttrap_cleanup_mtx); - } - } - - fasttrap_cleanup_work = 0; - mutex_exit(&fasttrap_cleanup_mtx); + callout_drain(&fasttrap_timeout); + mtx_unlock(&fasttrap_cleanup_mtx); /* * Iterate over all of our providers. If there's still a process @@ -2275,10 +2428,10 @@ fasttrap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) * and start a new timeout if any work has accumulated while * we've been unsuccessfully trying to detach. */ - mutex_enter(&fasttrap_cleanup_mtx); - fasttrap_timeout = 0; + mtx_lock(&fasttrap_cleanup_mtx); work = fasttrap_cleanup_work; - mutex_exit(&fasttrap_cleanup_mtx); + callout_drain(&fasttrap_timeout); + mtx_unlock(&fasttrap_cleanup_mtx); if (work) fasttrap_pid_cleanup(); @@ -2286,7 +2439,7 @@ fasttrap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) (void) dtrace_meta_register("fasttrap", &fasttrap_mops, NULL, &fasttrap_meta_id); - return (DDI_FAILURE); + return (-1); } #ifdef DEBUG @@ -2314,63 +2467,55 @@ fasttrap_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) * be executing code in fasttrap_fork(). Similarly for p_dtrace_probes * and fasttrap_exec() and fasttrap_exit(). */ - ASSERT(dtrace_fasttrap_fork_ptr == &fasttrap_fork); - dtrace_fasttrap_fork_ptr = NULL; + ASSERT(dtrace_fasttrap_fork == &fasttrap_fork); + dtrace_fasttrap_fork = NULL; - ASSERT(dtrace_fasttrap_exec_ptr == &fasttrap_exec_exit); - dtrace_fasttrap_exec_ptr = NULL; + ASSERT(dtrace_fasttrap_exec == &fasttrap_exec_exit); + dtrace_fasttrap_exec = NULL; - ASSERT(dtrace_fasttrap_exit_ptr == &fasttrap_exec_exit); - dtrace_fasttrap_exit_ptr = NULL; + ASSERT(dtrace_fasttrap_exit == &fasttrap_exec_exit); + dtrace_fasttrap_exit = NULL; - ddi_remove_minor_node(devi, NULL); +#if !defined(sun) + destroy_dev(fasttrap_cdev); + mutex_destroy(&fasttrap_count_mtx); + CPU_FOREACH(i) { + mutex_destroy(&fasttrap_cpuc_pid_lock[i]); + } +#endif - return (DDI_SUCCESS); + return (0); } -static struct dev_ops fasttrap_ops = { - DEVO_REV, /* devo_rev */ - 0, /* refcnt */ - fasttrap_info, /* get_dev_info */ - nulldev, /* identify */ - nulldev, /* probe */ - fasttrap_attach, /* attach */ - fasttrap_detach, /* detach */ - nodev, /* reset */ - &fasttrap_cb_ops, /* driver operations */ - NULL, /* bus operations */ - nodev /* dev power */ -}; - -/* - * Module linkage information for the kernel. - */ -static struct modldrv modldrv = { - &mod_driverops, /* module type (this is a pseudo driver) */ - "Fasttrap Tracing", /* name of module */ - &fasttrap_ops, /* driver ops */ -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&modldrv, - NULL -}; - -int -_init(void) +/* ARGSUSED */ +static int +fasttrap_modevent(module_t mod __unused, int type, void *data __unused) { - return (mod_install(&modlinkage)); + int error = 0; + + switch (type) { + case MOD_LOAD: + break; + + case MOD_UNLOAD: + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + } + return (error); } -int -_info(struct modinfo *modinfop) -{ - return (mod_info(&modlinkage, modinfop)); -} +SYSINIT(fasttrap_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, fasttrap_load, + NULL); +SYSUNINIT(fasttrap_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, + fasttrap_unload, NULL); -int -_fini(void) -{ - return (mod_remove(&modlinkage)); -} +DEV_MODULE(fasttrap, fasttrap_modevent, NULL); +MODULE_VERSION(fasttrap, 1); +MODULE_DEPEND(fasttrap, dtrace, 1, 1, 1); +MODULE_DEPEND(fasttrap, opensolaris, 1, 1, 1); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c index 1666e41525b..f34a48ef169 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/arc.c @@ -2155,16 +2155,12 @@ arc_reclaim_needed(void) #ifdef _KERNEL if (needfree) return (1); - if (arc_size > arc_c_max) - return (1); - if (arc_size <= arc_c_min) - return (0); /* - * If pages are needed or we're within 2048 pages - * of needing to page need to reclaim + * Cooperate with pagedaemon when it's time for it to scan + * and reclaim some pages. */ - if (vm_pages_needed || (vm_paging_target() > -2048)) + if (vm_paging_needed()) return (1); #if 0 @@ -2317,12 +2313,12 @@ arc_reclaim_thread(void *dummy __unused) if (arc_eviction_list != NULL) arc_do_user_evicts(); - if (arc_reclaim_needed()) { - needfree = 0; #ifdef _KERNEL + if (needfree) { + needfree = 0; wakeup(&needfree); -#endif } +#endif /* block until needed, or one second, whichever is shorter */ CALLB_CPR_SAFE_BEGIN(&cpr); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scrub.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scrub.c index d11f106f7b6..50cc069a3a7 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scrub.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_scrub.c @@ -351,7 +351,7 @@ traverse_zil_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg) return; /* - * One block ("stumpy") can be allocated a long time ago; we + * One block ("stubby") can be allocated a long time ago; we * want to visit that one because it has been allocated * (on-disk) even if it hasn't been claimed (even though for * plain scrub there's nothing to do to it). diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c index d216154db04..c5ce27cb677 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/metaslab.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ #include @@ -37,7 +36,7 @@ uint64_t metaslab_gang_bang = SPA_MAXBLOCKSIZE + 1; /* force gang blocks */ /* * Minimum size which forces the dynamic allocator to change - * it's allocation strategy. Once the space map cannot satisfy + * it's allocation strategy. Once the space map cannot satisfy * an allocation of this size then it switches to using more * aggressive strategy (i.e search by size rather than offset). */ @@ -49,7 +48,23 @@ uint64_t metaslab_df_alloc_threshold = SPA_MAXBLOCKSIZE; * Once the space_map's free space drops below this level we dynamically * switch to using best-fit allocations. */ -int metaslab_df_free_pct = 30; +int metaslab_df_free_pct = 4; + +/* + * A metaslab is considered "free" if it contains a contiguous + * segment which is greater than metaslab_min_alloc_size. + */ +uint64_t metaslab_min_alloc_size = DMU_MAX_ACCESS; + +/* + * Max number of space_maps to prefetch. + */ +int metaslab_prefetch_limit = SPA_DVAS_PER_BP; + +/* + * Percentage bonus multiplier for metaslabs that are in the bonus area. + */ +int metaslab_smo_bonus_pct = 150; /* * ========================================================================== @@ -218,6 +233,32 @@ metaslab_group_sort(metaslab_group_t *mg, metaslab_t *msp, uint64_t weight) mutex_exit(&mg->mg_lock); } +/* + * ========================================================================== + * Common allocator routines + * ========================================================================== + */ +static int +metaslab_segsize_compare(const void *x1, const void *x2) +{ + const space_seg_t *s1 = x1; + const space_seg_t *s2 = x2; + uint64_t ss_size1 = s1->ss_end - s1->ss_start; + uint64_t ss_size2 = s2->ss_end - s2->ss_start; + + if (ss_size1 < ss_size2) + return (-1); + if (ss_size1 > ss_size2) + return (1); + + if (s1->ss_start < s2->ss_start) + return (-1); + if (s1->ss_start > s2->ss_start) + return (1); + + return (0); +} + /* * This is a helper function that can be used by the allocator to find * a suitable block to allocate. This will search the specified AVL @@ -258,101 +299,8 @@ metaslab_block_picker(avl_tree_t *t, uint64_t *cursor, uint64_t size, return (metaslab_block_picker(t, cursor, size, align)); } -/* - * ========================================================================== - * The first-fit block allocator - * ========================================================================== - */ static void -metaslab_ff_load(space_map_t *sm) -{ - ASSERT(sm->sm_ppd == NULL); - sm->sm_ppd = kmem_zalloc(64 * sizeof (uint64_t), KM_SLEEP); - sm->sm_pp_root = NULL; -} - -static void -metaslab_ff_unload(space_map_t *sm) -{ - kmem_free(sm->sm_ppd, 64 * sizeof (uint64_t)); - sm->sm_ppd = NULL; -} - -static uint64_t -metaslab_ff_alloc(space_map_t *sm, uint64_t size) -{ - avl_tree_t *t = &sm->sm_root; - uint64_t align = size & -size; - uint64_t *cursor = (uint64_t *)sm->sm_ppd + highbit(align) - 1; - - return (metaslab_block_picker(t, cursor, size, align)); -} - -/* ARGSUSED */ -static void -metaslab_ff_claim(space_map_t *sm, uint64_t start, uint64_t size) -{ - /* No need to update cursor */ -} - -/* ARGSUSED */ -static void -metaslab_ff_free(space_map_t *sm, uint64_t start, uint64_t size) -{ - /* No need to update cursor */ -} - -static space_map_ops_t metaslab_ff_ops = { - metaslab_ff_load, - metaslab_ff_unload, - metaslab_ff_alloc, - metaslab_ff_claim, - metaslab_ff_free, - NULL /* maxsize */ -}; - -/* - * Dynamic block allocator - - * Uses the first fit allocation scheme until space get low and then - * adjusts to a best fit allocation method. Uses metaslab_df_alloc_threshold - * and metaslab_df_free_pct to determine when to switch the allocation scheme. - */ - -uint64_t -metaslab_df_maxsize(space_map_t *sm) -{ - avl_tree_t *t = sm->sm_pp_root; - space_seg_t *ss; - - if (t == NULL || (ss = avl_last(t)) == NULL) - return (0ULL); - - return (ss->ss_end - ss->ss_start); -} - -static int -metaslab_df_seg_compare(const void *x1, const void *x2) -{ - const space_seg_t *s1 = x1; - const space_seg_t *s2 = x2; - uint64_t ss_size1 = s1->ss_end - s1->ss_start; - uint64_t ss_size2 = s2->ss_end - s2->ss_start; - - if (ss_size1 < ss_size2) - return (-1); - if (ss_size1 > ss_size2) - return (1); - - if (s1->ss_start < s2->ss_start) - return (-1); - if (s1->ss_start > s2->ss_start) - return (1); - - return (0); -} - -static void -metaslab_df_load(space_map_t *sm) +metaslab_pp_load(space_map_t *sm) { space_seg_t *ss; @@ -360,7 +308,7 @@ metaslab_df_load(space_map_t *sm) sm->sm_ppd = kmem_zalloc(64 * sizeof (uint64_t), KM_SLEEP); sm->sm_pp_root = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); - avl_create(sm->sm_pp_root, metaslab_df_seg_compare, + avl_create(sm->sm_pp_root, metaslab_segsize_compare, sizeof (space_seg_t), offsetof(struct space_seg, ss_pp_node)); for (ss = avl_first(&sm->sm_root); ss; ss = AVL_NEXT(&sm->sm_root, ss)) @@ -368,7 +316,7 @@ metaslab_df_load(space_map_t *sm) } static void -metaslab_df_unload(space_map_t *sm) +metaslab_pp_unload(space_map_t *sm) { void *cookie = NULL; @@ -384,13 +332,82 @@ metaslab_df_unload(space_map_t *sm) sm->sm_pp_root = NULL; } +/* ARGSUSED */ +static void +metaslab_pp_claim(space_map_t *sm, uint64_t start, uint64_t size) +{ + /* No need to update cursor */ +} + +/* ARGSUSED */ +static void +metaslab_pp_free(space_map_t *sm, uint64_t start, uint64_t size) +{ + /* No need to update cursor */ +} + +/* + * Return the maximum contiguous segment within the metaslab. + */ +uint64_t +metaslab_pp_maxsize(space_map_t *sm) +{ + avl_tree_t *t = sm->sm_pp_root; + space_seg_t *ss; + + if (t == NULL || (ss = avl_last(t)) == NULL) + return (0ULL); + + return (ss->ss_end - ss->ss_start); +} + +/* + * ========================================================================== + * The first-fit block allocator + * ========================================================================== + */ +static uint64_t +metaslab_ff_alloc(space_map_t *sm, uint64_t size) +{ + avl_tree_t *t = &sm->sm_root; + uint64_t align = size & -size; + uint64_t *cursor = (uint64_t *)sm->sm_ppd + highbit(align) - 1; + + return (metaslab_block_picker(t, cursor, size, align)); +} + +/* ARGSUSED */ +boolean_t +metaslab_ff_fragmented(space_map_t *sm) +{ + return (B_TRUE); +} + +static space_map_ops_t metaslab_ff_ops = { + metaslab_pp_load, + metaslab_pp_unload, + metaslab_ff_alloc, + metaslab_pp_claim, + metaslab_pp_free, + metaslab_pp_maxsize, + metaslab_ff_fragmented +}; + +/* + * ========================================================================== + * Dynamic block allocator - + * Uses the first fit allocation scheme until space get low and then + * adjusts to a best fit allocation method. Uses metaslab_df_alloc_threshold + * and metaslab_df_free_pct to determine when to switch the allocation scheme. + * ========================================================================== + */ static uint64_t metaslab_df_alloc(space_map_t *sm, uint64_t size) { avl_tree_t *t = &sm->sm_root; uint64_t align = size & -size; uint64_t *cursor = (uint64_t *)sm->sm_ppd + highbit(align) - 1; - uint64_t max_size = metaslab_df_maxsize(sm); + uint64_t max_size = metaslab_pp_maxsize(sm); int free_pct = sm->sm_space * 100 / sm->sm_size; ASSERT(MUTEX_HELD(sm->sm_lock)); @@ -412,30 +429,158 @@ metaslab_df_alloc(space_map_t *sm, uint64_t size) return (metaslab_block_picker(t, cursor, size, 1ULL)); } -/* ARGSUSED */ -static void -metaslab_df_claim(space_map_t *sm, uint64_t start, uint64_t size) +static boolean_t +metaslab_df_fragmented(space_map_t *sm) { - /* No need to update cursor */ -} + uint64_t max_size = metaslab_pp_maxsize(sm); + int free_pct = sm->sm_space * 100 / sm->sm_size; -/* ARGSUSED */ -static void -metaslab_df_free(space_map_t *sm, uint64_t start, uint64_t size) -{ - /* No need to update cursor */ + if (max_size >= metaslab_df_alloc_threshold && + free_pct >= metaslab_df_free_pct) + return (B_FALSE); + + return (B_TRUE); } static space_map_ops_t metaslab_df_ops = { - metaslab_df_load, - metaslab_df_unload, + metaslab_pp_load, + metaslab_pp_unload, metaslab_df_alloc, - metaslab_df_claim, - metaslab_df_free, - metaslab_df_maxsize + metaslab_pp_claim, + metaslab_pp_free, + metaslab_pp_maxsize, + metaslab_df_fragmented }; -space_map_ops_t *zfs_metaslab_ops = &metaslab_df_ops; +/* + * ========================================================================== + * Other experimental allocators + * ========================================================================== + */ +static uint64_t +metaslab_cdf_alloc(space_map_t *sm, uint64_t size) +{ + avl_tree_t *t = &sm->sm_root; + uint64_t *cursor = (uint64_t *)sm->sm_ppd; + uint64_t *extent_end = (uint64_t *)sm->sm_ppd + 1; + uint64_t max_size = metaslab_pp_maxsize(sm); + uint64_t rsize = size; + uint64_t offset = 0; + + ASSERT(MUTEX_HELD(sm->sm_lock)); + ASSERT3U(avl_numnodes(&sm->sm_root), ==, avl_numnodes(sm->sm_pp_root)); + + if (max_size < size) + return (-1ULL); + + ASSERT3U(*extent_end, >=, *cursor); + + /* + * If we're running low on space switch to using the size + * sorted AVL tree (best-fit). + */ + if ((*cursor + size) > *extent_end) { + + t = sm->sm_pp_root; + *cursor = *extent_end = 0; + + if (max_size > 2 * SPA_MAXBLOCKSIZE) + rsize = MIN(metaslab_min_alloc_size, max_size); + offset = metaslab_block_picker(t, extent_end, rsize, 1ULL); + if (offset != -1) + *cursor = offset + size; + } else { + offset = metaslab_block_picker(t, cursor, rsize, 1ULL); + } + ASSERT3U(*cursor, <=, *extent_end); + return (offset); +} + +static boolean_t +metaslab_cdf_fragmented(space_map_t *sm) +{ + uint64_t max_size = metaslab_pp_maxsize(sm); + + if (max_size > (metaslab_min_alloc_size * 10)) + return (B_FALSE); + return (B_TRUE); +} + +static space_map_ops_t metaslab_cdf_ops = { + metaslab_pp_load, + metaslab_pp_unload, + metaslab_cdf_alloc, + metaslab_pp_claim, + metaslab_pp_free, + metaslab_pp_maxsize, + metaslab_cdf_fragmented +}; + +uint64_t metaslab_ndf_clump_shift = 4; + +static uint64_t +metaslab_ndf_alloc(space_map_t *sm, uint64_t size) +{ + avl_tree_t *t = &sm->sm_root; + avl_index_t where; + space_seg_t *ss, ssearch; + uint64_t hbit = highbit(size); + uint64_t *cursor = (uint64_t *)sm->sm_ppd + hbit - 1; + uint64_t max_size = metaslab_pp_maxsize(sm); + + ASSERT(MUTEX_HELD(sm->sm_lock)); + ASSERT3U(avl_numnodes(&sm->sm_root), ==, avl_numnodes(sm->sm_pp_root)); + + if (max_size < size) + return (-1ULL); + + ssearch.ss_start = *cursor; + ssearch.ss_end = *cursor + size; + + ss = avl_find(t, &ssearch, &where); + if (ss == NULL || (ss->ss_start + size > ss->ss_end)) { + t = sm->sm_pp_root; + + ssearch.ss_start = 0; + ssearch.ss_end = MIN(max_size, + 1ULL << (hbit + metaslab_ndf_clump_shift)); + ss = avl_find(t, &ssearch, &where); + if (ss == NULL) + ss = avl_nearest(t, where, AVL_AFTER); + ASSERT(ss != NULL); + } + + if (ss != NULL) { + if (ss->ss_start + size <= ss->ss_end) { + *cursor = ss->ss_start + size; + return (ss->ss_start); + } + } + return (-1ULL); +} + +static boolean_t +metaslab_ndf_fragmented(space_map_t *sm) +{ + uint64_t max_size = metaslab_pp_maxsize(sm); + + if (max_size > (metaslab_min_alloc_size << metaslab_ndf_clump_shift)) + return (B_FALSE); + return (B_TRUE); +} + + +static space_map_ops_t metaslab_ndf_ops = { + metaslab_pp_load, + metaslab_pp_unload, + metaslab_ndf_alloc, + metaslab_pp_claim, + metaslab_pp_free, + metaslab_pp_maxsize, + metaslab_ndf_fragmented +}; + +space_map_ops_t *zfs_metaslab_ops = &metaslab_ndf_ops; /* * ========================================================================== @@ -522,7 +667,6 @@ metaslab_fini(metaslab_t *msp) #define METASLAB_WEIGHT_SECONDARY (1ULL << 62) #define METASLAB_ACTIVE_MASK \ (METASLAB_WEIGHT_PRIMARY | METASLAB_WEIGHT_SECONDARY) -#define METASLAB_SMO_BONUS_MULTIPLIER 2 static uint64_t metaslab_weight(metaslab_t *msp) @@ -555,25 +699,60 @@ metaslab_weight(metaslab_t *msp) ASSERT(weight >= space && weight <= 2 * space); /* - * For locality, assign higher weight to metaslabs we've used before. + * For locality, assign higher weight to metaslabs which have + * a lower offset than what we've already activated. */ - if (smo->smo_object != 0) - weight *= METASLAB_SMO_BONUS_MULTIPLIER; + if (sm->sm_start <= mg->mg_bonus_area) + weight *= (metaslab_smo_bonus_pct / 100); ASSERT(weight >= space && - weight <= 2 * METASLAB_SMO_BONUS_MULTIPLIER * space); + weight <= 2 * (metaslab_smo_bonus_pct / 100) * space); + + if (sm->sm_loaded && !sm->sm_ops->smop_fragmented(sm)) { + /* + * If this metaslab is one we're actively using, adjust its + * weight to make it preferable to any inactive metaslab so + * we'll polish it off. + */ + weight |= (msp->ms_weight & METASLAB_ACTIVE_MASK); + } + return (weight); +} + +static void +metaslab_prefetch(metaslab_group_t *mg) +{ + spa_t *spa = mg->mg_vd->vdev_spa; + metaslab_t *msp; + avl_tree_t *t = &mg->mg_metaslab_tree; + int m; + + mutex_enter(&mg->mg_lock); /* - * If this metaslab is one we're actively using, adjust its weight to - * make it preferable to any inactive metaslab so we'll polish it off. + * Prefetch the next potential metaslabs */ - weight |= (msp->ms_weight & METASLAB_ACTIVE_MASK); + for (msp = avl_first(t), m = 0; msp; msp = AVL_NEXT(t, msp), m++) { + space_map_t *sm = &msp->ms_map; + space_map_obj_t *smo = &msp->ms_smo; - return (weight); + /* If we have reached our prefetch limit then we're done */ + if (m >= metaslab_prefetch_limit) + break; + + if (!sm->sm_loaded && smo->smo_object != 0) { + mutex_exit(&mg->mg_lock); + dmu_prefetch(spa->spa_meta_objset, smo->smo_object, + 0ULL, smo->smo_objsize); + mutex_enter(&mg->mg_lock); + } + } + mutex_exit(&mg->mg_lock); } static int metaslab_activate(metaslab_t *msp, uint64_t activation_weight, uint64_t size) { + metaslab_group_t *mg = msp->ms_group; space_map_t *sm = &msp->ms_map; space_map_ops_t *sm_ops = msp->ms_group->mg_class->mc_ops; @@ -587,6 +766,15 @@ metaslab_activate(metaslab_t *msp, uint64_t activation_weight, uint64_t size) return (error); } + /* + * Track the bonus area as we activate new metaslabs. + */ + if (sm->sm_start > mg->mg_bonus_area) { + mutex_enter(&mg->mg_lock); + mg->mg_bonus_area = sm->sm_start; + mutex_exit(&mg->mg_lock); + } + /* * If we were able to load the map then make sure * that this map is still able to satisfy our request. @@ -773,6 +961,32 @@ metaslab_sync_done(metaslab_t *msp, uint64_t txg) mutex_exit(&msp->ms_lock); } +void +metaslab_sync_reassess(metaslab_group_t *mg) +{ + vdev_t *vd = mg->mg_vd; + + /* + * Re-evaluate all metaslabs which have lower offsets than the + * bonus area. + */ + for (int m = 0; m < vd->vdev_ms_count; m++) { + metaslab_t *msp = vd->vdev_ms[m]; + + if (msp->ms_map.sm_start > mg->mg_bonus_area) + break; + + mutex_enter(&msp->ms_lock); + metaslab_group_sort(mg, msp, metaslab_weight(msp)); + mutex_exit(&msp->ms_lock); + } + + /* + * Prefetch the next potential metaslabs + */ + metaslab_prefetch(mg); +} + static uint64_t metaslab_distance(metaslab_t *msp, dva_t *dva) { @@ -868,7 +1082,7 @@ metaslab_group_alloc(metaslab_group_t *mg, uint64_t size, uint64_t txg, if ((offset = space_map_alloc(&msp->ms_map, size)) != -1ULL) break; - metaslab_passivate(msp, size - 1); + metaslab_passivate(msp, space_map_maxsize(&msp->ms_map)); mutex_exit(&msp->ms_lock); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/rrwlock.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/rrwlock.c index db3b70fc68b..4cef53f9513 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/rrwlock.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/rrwlock.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include #include @@ -159,6 +157,14 @@ static void rrw_enter_read(rrwlock_t *rrl, void *tag) { mutex_enter(&rrl->rr_lock); +#if !defined(DEBUG) && defined(_KERNEL) + if (!rrl->rr_writer && !rrl->rr_writer_wanted) { + rrl->rr_anon_rcount.rc_count++; + mutex_exit(&rrl->rr_lock); + return; + } + DTRACE_PROBE(zfs__rrwfastpath__rdmiss); +#endif ASSERT(rrl->rr_writer != curthread); ASSERT(refcount_count(&rrl->rr_anon_rcount) >= 0); @@ -208,19 +214,28 @@ void rrw_exit(rrwlock_t *rrl, void *tag) { mutex_enter(&rrl->rr_lock); +#if !defined(DEBUG) && defined(_KERNEL) + if (!rrl->rr_writer && rrl->rr_linked_rcount.rc_count == 0) { + rrl->rr_anon_rcount.rc_count--; + if (rrl->rr_anon_rcount.rc_count == 0) + cv_broadcast(&rrl->rr_cv); + mutex_exit(&rrl->rr_lock); + return; + } + DTRACE_PROBE(zfs__rrwfastpath__exitmiss); +#endif ASSERT(!refcount_is_zero(&rrl->rr_anon_rcount) || !refcount_is_zero(&rrl->rr_linked_rcount) || rrl->rr_writer != NULL); if (rrl->rr_writer == NULL) { - if (rrn_find_and_remove(rrl)) { - if (refcount_remove(&rrl->rr_linked_rcount, tag) == 0) - cv_broadcast(&rrl->rr_cv); - - } else { - if (refcount_remove(&rrl->rr_anon_rcount, tag) == 0) - cv_broadcast(&rrl->rr_cv); - } + int64_t count; + if (rrn_find_and_remove(rrl)) + count = refcount_remove(&rrl->rr_linked_rcount, tag); + else + count = refcount_remove(&rrl->rr_anon_rcount, tag); + if (count == 0) + cv_broadcast(&rrl->rr_cv); } else { ASSERT(rrl->rr_writer == curthread); ASSERT(refcount_is_zero(&rrl->rr_anon_rcount) && diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c index cb6f413c640..c04102e17e8 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/spa.c @@ -74,35 +74,38 @@ enum zti_modes { zti_mode_fixed, /* value is # of threads (min 1) */ zti_mode_online_percent, /* value is % of online CPUs */ zti_mode_tune, /* fill from zio_taskq_tune_* */ + zti_mode_null, /* don't create a taskq */ zti_nmodes }; -#define ZTI_THREAD_FIX(n) { zti_mode_fixed, (n) } -#define ZTI_THREAD_PCT(n) { zti_mode_online_percent, (n) } -#define ZTI_THREAD_TUNE { zti_mode_tune, 0 } +#define ZTI_FIX(n) { zti_mode_fixed, (n) } +#define ZTI_PCT(n) { zti_mode_online_percent, (n) } +#define ZTI_TUNE { zti_mode_tune, 0 } +#define ZTI_NULL { zti_mode_null, 0 } -#define ZTI_THREAD_ONE ZTI_THREAD_FIX(1) +#define ZTI_ONE ZTI_FIX(1) typedef struct zio_taskq_info { - const char *zti_name; - struct { - enum zti_modes zti_mode; - uint_t zti_value; - } zti_nthreads[ZIO_TASKQ_TYPES]; + enum zti_modes zti_mode; + uint_t zti_value; } zio_taskq_info_t; static const char *const zio_taskq_types[ZIO_TASKQ_TYPES] = { - "issue", "intr" + "issue", "issue_high", "intr", "intr_high" }; -const zio_taskq_info_t zio_taskqs[ZIO_TYPES] = { - /* ISSUE INTR */ - { "spa_zio_null", { ZTI_THREAD_ONE, ZTI_THREAD_ONE } }, - { "spa_zio_read", { ZTI_THREAD_FIX(8), ZTI_THREAD_TUNE } }, - { "spa_zio_write", { ZTI_THREAD_TUNE, ZTI_THREAD_FIX(8) } }, - { "spa_zio_free", { ZTI_THREAD_ONE, ZTI_THREAD_ONE } }, - { "spa_zio_claim", { ZTI_THREAD_ONE, ZTI_THREAD_ONE } }, - { "spa_zio_ioctl", { ZTI_THREAD_ONE, ZTI_THREAD_ONE } }, +/* + * Define the taskq threads for the following I/O types: + * NULL, READ, WRITE, FREE, CLAIM, and IOCTL + */ +const zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = { + /* ISSUE ISSUE_HIGH INTR INTR_HIGH */ + { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, + { ZTI_FIX(8), ZTI_NULL, ZTI_TUNE, ZTI_NULL }, + { ZTI_TUNE, ZTI_FIX(5), ZTI_FIX(8), ZTI_FIX(5) }, + { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, + { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, + { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, }; enum zti_modes zio_taskq_tune_mode = zti_mode_online_percent; @@ -581,14 +584,14 @@ spa_activate(spa_t *spa, int mode) spa->spa_log_class = metaslab_class_create(zfs_metaslab_ops); for (int t = 0; t < ZIO_TYPES; t++) { - const zio_taskq_info_t *ztip = &zio_taskqs[t]; for (int q = 0; q < ZIO_TASKQ_TYPES; q++) { - enum zti_modes mode = ztip->zti_nthreads[q].zti_mode; - uint_t value = ztip->zti_nthreads[q].zti_value; + const zio_taskq_info_t *ztip = &zio_taskqs[t][q]; + enum zti_modes mode = ztip->zti_mode; + uint_t value = ztip->zti_value; char name[32]; (void) snprintf(name, sizeof (name), - "%s_%s", ztip->zti_name, zio_taskq_types[q]); + "%s_%s", zio_type_name[t], zio_taskq_types[q]); if (mode == zti_mode_tune) { mode = zio_taskq_tune_mode; @@ -613,6 +616,10 @@ spa_activate(spa_t *spa, int mode) TASKQ_PREPOPULATE | TASKQ_THREADS_CPU_PCT); break; + case zti_mode_null: + spa->spa_zio_taskq[t][q] = NULL; + break; + case zti_mode_tune: default: panic("unrecognized mode for " @@ -659,7 +666,8 @@ spa_deactivate(spa_t *spa) for (int t = 0; t < ZIO_TYPES; t++) { for (int q = 0; q < ZIO_TASKQ_TYPES; q++) { - taskq_destroy(spa->spa_zio_taskq[t][q]); + if (spa->spa_zio_taskq[t][q] != NULL) + taskq_destroy(spa->spa_zio_taskq[t][q]); spa->spa_zio_taskq[t][q] = NULL; } } @@ -1101,6 +1109,33 @@ spa_check_removed(vdev_t *vd) } } +/* + * Load the slog device state from the config object since it's possible + * that the label does not contain the most up-to-date information. + */ +void +spa_load_log_state(spa_t *spa) +{ + nvlist_t *nv, *nvroot, **child; + uint64_t is_log; + uint_t children, c; + vdev_t *rvd = spa->spa_root_vdev; + + VERIFY(load_nvlist(spa, spa->spa_config_object, &nv) == 0); + VERIFY(nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); + VERIFY(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, + &child, &children) == 0); + + for (c = 0; c < children; c++) { + vdev_t *tvd = rvd->vdev_child[c]; + + if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG, + &is_log) == 0 && is_log) + vdev_load_log_state(tvd, child[c]); + } + nvlist_free(nv); +} + /* * Check for missing log devices */ @@ -1117,13 +1152,7 @@ spa_check_logs(spa_t *spa) return (1); } break; - - case SPA_LOG_CLEAR: - (void) dmu_objset_find(spa->spa_name, zil_clear_log_chain, NULL, - DS_FIND_CHILDREN); - break; } - spa->spa_log_state = SPA_LOG_GOOD; return (0); } @@ -1447,6 +1476,8 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig) spa_config_exit(spa, SCL_ALL, FTAG); } + spa_load_log_state(spa); + if (spa_check_logs(spa)) { vdev_set_state(rvd, B_TRUE, VDEV_STATE_CANT_OPEN, VDEV_AUX_BAD_LOG); @@ -1534,6 +1565,7 @@ spa_load(spa_t *spa, nvlist_t *config, spa_load_state_t state, int mosconfig) zil_claim, tx, DS_FIND_CHILDREN); dmu_tx_commit(tx); + spa->spa_log_state = SPA_LOG_GOOD; spa->spa_sync_on = B_TRUE; txg_sync_start(spa->spa_dsl_pool); @@ -4220,10 +4252,16 @@ spa_sync(spa_t *spa, uint64_t txg) if (svdcount == SPA_DVAS_PER_BP) break; } - error = vdev_config_sync(svd, svdcount, txg); + error = vdev_config_sync(svd, svdcount, txg, B_FALSE); + if (error != 0) + error = vdev_config_sync(svd, svdcount, txg, + B_TRUE); } else { error = vdev_config_sync(rvd->vdev_child, - rvd->vdev_children, txg); + rvd->vdev_children, txg, B_FALSE); + if (error != 0) + error = vdev_config_sync(rvd->vdev_child, + rvd->vdev_children, txg, B_TRUE); } spa_config_exit(spa, SCL_STATE, FTAG); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c index 75b55d5c1ca..d0251419cbc 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/space_map.c @@ -368,10 +368,8 @@ space_map_unload(space_map_t *sm) uint64_t space_map_maxsize(space_map_t *sm) { - if (sm->sm_loaded && sm->sm_ops != NULL) - return (sm->sm_ops->smop_max(sm)); - else - return (-1ULL); + ASSERT(sm->sm_ops != NULL); + return (sm->sm_ops->smop_max(sm)); } uint64_t diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab.h index 5d3e11c971f..c77b7720549 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab.h @@ -46,6 +46,7 @@ extern metaslab_t *metaslab_init(metaslab_group_t *mg, space_map_obj_t *smo, extern void metaslab_fini(metaslab_t *msp); extern void metaslab_sync(metaslab_t *msp, uint64_t txg); extern void metaslab_sync_done(metaslab_t *msp, uint64_t txg); +extern void metaslab_sync_reassess(metaslab_group_t *mg); #define METASLAB_HINTBP_FAVOR 0x0 #define METASLAB_HINTBP_AVOID 0x1 diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h index d67dea7e975..5f0b77086b0 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/metaslab_impl.h @@ -46,6 +46,7 @@ struct metaslab_group { kmutex_t mg_lock; avl_tree_t mg_metaslab_tree; uint64_t mg_aliquot; + uint64_t mg_bonus_area; int64_t mg_bias; metaslab_class_t *mg_class; vdev_t *mg_vd; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h index f3124b1ecc0..ecb065c3f98 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/spa_impl.h @@ -87,7 +87,9 @@ typedef enum spa_log_state { enum zio_taskq_type { ZIO_TASKQ_ISSUE = 0, + ZIO_TASKQ_ISSUE_HIGH, ZIO_TASKQ_INTERRUPT, + ZIO_TASKQ_INTERRUPT_HIGH, ZIO_TASKQ_TYPES }; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/space_map.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/space_map.h index a682bbd409e..6f935c9db27 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/space_map.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/space_map.h @@ -77,6 +77,7 @@ struct space_map_ops { void (*smop_claim)(space_map_t *sm, uint64_t start, uint64_t size); void (*smop_free)(space_map_t *sm, uint64_t start, uint64_t size); uint64_t (*smop_max)(space_map_t *sm); + boolean_t (*smop_fragmented)(space_map_t *sm); }; /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h index b8313a920dd..93325546426 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -113,7 +113,8 @@ extern void vdev_queue_io_done(zio_t *zio); extern void vdev_config_dirty(vdev_t *vd); extern void vdev_config_clean(vdev_t *vd); -extern int vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg); +extern int vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, + boolean_t); extern void vdev_state_dirty(vdev_t *vd); extern void vdev_state_clean(vdev_t *vd); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h index 1406d154d78..93e41025088 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev_impl.h @@ -259,6 +259,7 @@ extern void vdev_remove_parent(vdev_t *cvd); /* * vdev sync load and sync */ +extern void vdev_load_log_state(vdev_t *vd, nvlist_t *nv); extern void vdev_load(vdev_t *vd); extern void vdev_sync(vdev_t *vd, uint64_t txg); extern void vdev_sync_done(vdev_t *vd, uint64_t txg); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h index 3607e1f3c93..ea150950430 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_acl.h @@ -200,7 +200,9 @@ int zfs_setacl(struct znode *, vsecattr_t *, boolean_t, cred_t *); void zfs_acl_rele(void *); void zfs_oldace_byteswap(ace_t *, int); void zfs_ace_byteswap(void *, size_t, boolean_t); +extern boolean_t zfs_has_access(struct znode *zp, cred_t *cr); extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *); +int zfs_fastaccesschk_execute(struct znode *, cred_t *); extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *); extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *); extern int zfs_acl_access(struct znode *, int, cred_t *); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h index 25348d6460f..19456869564 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ctldir.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _ZFS_CTLDIR_H @@ -48,6 +47,7 @@ void zfsctl_destroy(zfsvfs_t *); vnode_t *zfsctl_root(znode_t *); void zfsctl_init(void); void zfsctl_fini(void); +boolean_t zfsctl_is_node(vnode_t *); int zfsctl_rename_snapshot(const char *from, const char *to); int zfsctl_destroy_snapshot(const char *snapname, int force); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h index 15a4a76c254..bf107d605fa 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h @@ -118,7 +118,7 @@ typedef struct zinject_record { uint32_t zi_error; uint64_t zi_type; uint32_t zi_freq; - uint32_t zi_pad; /* pad out to 64 bit alignment */ + uint32_t zi_failfast; } zinject_record_t; #define ZINJECT_NULL 0x1 diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h index 47072fb3bfd..6f0a4363601 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_znode.h @@ -74,6 +74,7 @@ extern "C" { #define ZFS_ACL_DEFAULTED 0x20 /* ACL should be defaulted */ #define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */ #define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */ +#define ZFS_NO_EXECS_DENIED 0x100 /* exec was given to everyone */ /* * Is ID ephemeral? @@ -202,6 +203,7 @@ typedef struct znode { uint64_t z_gen; /* generation (same as zp_gen) */ uint32_t z_sync_cnt; /* synchronous open count */ kmutex_t z_acl_lock; /* acl data lock */ + zfs_acl_t *z_acl_cached; /* cached acl */ list_node_t z_link_node; /* all znodes in fs link */ /* * These are dmu managed fields. diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h index e992f6ac4ac..efbf65e287e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zil.h @@ -366,9 +366,9 @@ extern uint64_t zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx); extern void zil_commit(zilog_t *zilog, uint64_t seq, uint64_t oid); +extern int zil_vdev_offline(char *osname, void *txarg); extern int zil_claim(char *osname, void *txarg); extern int zil_check_log_chain(char *osname, void *txarg); -extern int zil_clear_log_chain(char *osname, void *txarg); extern void zil_sync(zilog_t *zilog, dmu_tx_t *tx); extern void zil_clean(zilog_t *zilog); extern int zil_is_committed(zilog_t *zilog); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h index d7c0febdfc7..4a4d2865ece 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zio.h @@ -107,40 +107,43 @@ enum zio_compress { #define ZIO_PRIORITY_NOW (zio_priority_table[0]) #define ZIO_PRIORITY_SYNC_READ (zio_priority_table[1]) #define ZIO_PRIORITY_SYNC_WRITE (zio_priority_table[2]) -#define ZIO_PRIORITY_ASYNC_READ (zio_priority_table[3]) -#define ZIO_PRIORITY_ASYNC_WRITE (zio_priority_table[4]) -#define ZIO_PRIORITY_FREE (zio_priority_table[5]) -#define ZIO_PRIORITY_CACHE_FILL (zio_priority_table[6]) -#define ZIO_PRIORITY_LOG_WRITE (zio_priority_table[7]) -#define ZIO_PRIORITY_RESILVER (zio_priority_table[8]) -#define ZIO_PRIORITY_SCRUB (zio_priority_table[9]) -#define ZIO_PRIORITY_TABLE_SIZE 10 +#define ZIO_PRIORITY_LOG_WRITE (zio_priority_table[3]) +#define ZIO_PRIORITY_CACHE_FILL (zio_priority_table[4]) +#define ZIO_PRIORITY_AGG (zio_priority_table[5]) +#define ZIO_PRIORITY_FREE (zio_priority_table[6]) +#define ZIO_PRIORITY_ASYNC_WRITE (zio_priority_table[7]) +#define ZIO_PRIORITY_ASYNC_READ (zio_priority_table[8]) +#define ZIO_PRIORITY_RESILVER (zio_priority_table[9]) +#define ZIO_PRIORITY_SCRUB (zio_priority_table[10]) +#define ZIO_PRIORITY_TABLE_SIZE 11 -#define ZIO_FLAG_MUSTSUCCEED 0x00000 -#define ZIO_FLAG_CANFAIL 0x00001 -#define ZIO_FLAG_SPECULATIVE 0x00002 -#define ZIO_FLAG_CONFIG_WRITER 0x00004 -#define ZIO_FLAG_DONT_RETRY 0x00008 +#define ZIO_FLAG_MUSTSUCCEED 0x000000 +#define ZIO_FLAG_CANFAIL 0x000001 +#define ZIO_FLAG_SPECULATIVE 0x000002 +#define ZIO_FLAG_CONFIG_WRITER 0x000004 +#define ZIO_FLAG_DONT_RETRY 0x000008 -#define ZIO_FLAG_DONT_CACHE 0x00010 -#define ZIO_FLAG_DONT_QUEUE 0x00020 -#define ZIO_FLAG_DONT_AGGREGATE 0x00040 -#define ZIO_FLAG_DONT_PROPAGATE 0x00080 +#define ZIO_FLAG_DONT_CACHE 0x000010 +#define ZIO_FLAG_DONT_QUEUE 0x000020 +#define ZIO_FLAG_DONT_AGGREGATE 0x000040 +#define ZIO_FLAG_DONT_PROPAGATE 0x000080 -#define ZIO_FLAG_IO_BYPASS 0x00100 -#define ZIO_FLAG_IO_REPAIR 0x00200 -#define ZIO_FLAG_IO_RETRY 0x00400 -#define ZIO_FLAG_IO_REWRITE 0x00800 +#define ZIO_FLAG_IO_BYPASS 0x000100 +#define ZIO_FLAG_IO_REPAIR 0x000200 +#define ZIO_FLAG_IO_RETRY 0x000400 +#define ZIO_FLAG_IO_REWRITE 0x000800 -#define ZIO_FLAG_SELF_HEAL 0x01000 -#define ZIO_FLAG_RESILVER 0x02000 -#define ZIO_FLAG_SCRUB 0x04000 -#define ZIO_FLAG_SCRUB_THREAD 0x08000 +#define ZIO_FLAG_SELF_HEAL 0x001000 +#define ZIO_FLAG_RESILVER 0x002000 +#define ZIO_FLAG_SCRUB 0x004000 +#define ZIO_FLAG_SCRUB_THREAD 0x008000 -#define ZIO_FLAG_PROBE 0x10000 -#define ZIO_FLAG_GANG_CHILD 0x20000 -#define ZIO_FLAG_RAW 0x40000 -#define ZIO_FLAG_GODFATHER 0x80000 +#define ZIO_FLAG_PROBE 0x010000 +#define ZIO_FLAG_GANG_CHILD 0x020000 +#define ZIO_FLAG_RAW 0x040000 +#define ZIO_FLAG_GODFATHER 0x080000 + +#define ZIO_FLAG_TRYHARD 0x100000 #define ZIO_FLAG_GANG_INHERIT \ (ZIO_FLAG_CANFAIL | \ @@ -158,7 +161,8 @@ enum zio_compress { (ZIO_FLAG_GANG_INHERIT | \ ZIO_FLAG_IO_REPAIR | \ ZIO_FLAG_IO_RETRY | \ - ZIO_FLAG_PROBE) + ZIO_FLAG_PROBE | \ + ZIO_FLAG_TRYHARD) #define ZIO_FLAG_AGG_INHERIT \ (ZIO_FLAG_DONT_AGGREGATE | \ @@ -439,7 +443,7 @@ extern int zio_inject_list_next(int *id, char *name, size_t buflen, struct zinject_record *record); extern int zio_clear_fault(int id); extern int zio_handle_fault_injection(zio_t *zio, int error); -extern int zio_handle_device_injection(vdev_t *vd, int error); +extern int zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error); extern int zio_handle_label_injection(zio_t *zio, int error); #ifdef __cplusplus diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c index befc8b36bc3..cb43af37f01 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev.c @@ -39,6 +39,7 @@ #include #include #include +#include SYSCTL_DECL(_vfs_zfs); SYSCTL_NODE(_vfs_zfs, OID_AUTO, vdev, CTLFLAG_RW, 0, "ZFS VDEV"); @@ -765,6 +766,15 @@ vdev_metaslab_init(vdev_t *vd, uint64_t txg) if (vd->vdev_ms_shift == 0) /* not being allocated from yet */ return (0); + /* + * Compute the raidz-deflation ratio. Note, we hard-code + * in 128k (1 << 17) because it is the current "typical" blocksize. + * Even if SPA_MAXBLOCKSIZE changes, this algorithm must never change, + * or we will inconsistently account for existing bp's. + */ + vd->vdev_deflate_ratio = (1 << 17) / + (vdev_psize_to_asize(vd, 1 << 17) >> SPA_MINBLOCKSHIFT); + ASSERT(oldc <= newc); if (vd->vdev_islog) @@ -918,7 +928,7 @@ vdev_probe(vdev_t *vd, zio_t *zio) vps->vps_flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_PROBE | ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_AGGREGATE | - ZIO_FLAG_DONT_RETRY; + ZIO_FLAG_TRYHARD; if (spa_config_held(spa, SCL_ZIO, RW_WRITER)) { /* @@ -998,6 +1008,8 @@ vdev_open(vdev_t *vd) vd->vdev_state == VDEV_STATE_OFFLINE); vd->vdev_stat.vs_aux = VDEV_AUX_NONE; + vd->vdev_cant_read = B_FALSE; + vd->vdev_cant_write = B_FALSE; if (!vd->vdev_removed && vd->vdev_faulted) { ASSERT(vd->vdev_children == 0); @@ -1013,7 +1025,7 @@ vdev_open(vdev_t *vd) error = vd->vdev_ops->vdev_op_open(vd, &osize, &ashift); if (zio_injection_enabled && error == 0) - error = zio_handle_device_injection(vd, ENXIO); + error = zio_handle_device_injection(vd, NULL, ENXIO); if (error) { if (vd->vdev_removed && @@ -1112,18 +1124,6 @@ vdev_open(vdev_t *vd) return (error); } - /* - * If this is a top-level vdev, compute the raidz-deflation - * ratio. Note, we hard-code in 128k (1<<17) because it is the - * current "typical" blocksize. Even if SPA_MAXBLOCKSIZE - * changes, this algorithm must never change, or we will - * inconsistently account for existing bp's. - */ - if (vd->vdev_top == vd) { - vd->vdev_deflate_ratio = (1<<17) / - (vdev_psize_to_asize(vd, 1<<17) >> SPA_MINBLOCKSHIFT); - } - /* * If a leaf vdev has a DTL, and seems healthy, then kick off a * resilver. But don't do this if we are doing a reopen for a scrub, @@ -1773,9 +1773,13 @@ void vdev_sync_done(vdev_t *vd, uint64_t txg) { metaslab_t *msp; + boolean_t reassess = !txg_list_empty(&vd->vdev_ms_list, TXG_CLEAN(txg)); while (msp = txg_list_remove(&vd->vdev_ms_list, TXG_CLEAN(txg))) metaslab_sync_done(msp, txg); + + if (reassess) + metaslab_sync_reassess(vd->vdev_mg); } void @@ -1933,7 +1937,8 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate) int vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags) { - vdev_t *vd; + vdev_t *vd, *tvd; + int error; spa_vdev_state_enter(spa); @@ -1943,34 +1948,58 @@ vdev_offline(spa_t *spa, uint64_t guid, uint64_t flags) if (!vd->vdev_ops->vdev_op_leaf) return (spa_vdev_state_exit(spa, NULL, ENOTSUP)); + tvd = vd->vdev_top; + /* * If the device isn't already offline, try to offline it. */ if (!vd->vdev_offline) { /* * If this device has the only valid copy of some data, - * don't allow it to be offlined. + * don't allow it to be offlined. Log devices are always + * expendable. */ - if (vd->vdev_aux == NULL && vdev_dtl_required(vd)) + if (!tvd->vdev_islog && vd->vdev_aux == NULL && + vdev_dtl_required(vd)) return (spa_vdev_state_exit(spa, NULL, EBUSY)); /* * Offline this device and reopen its top-level vdev. - * If this action results in the top-level vdev becoming - * unusable, undo it and fail the request. + * If the top-level vdev is a log device then just offline + * it. Otherwise, if this action results in the top-level + * vdev becoming unusable, undo it and fail the request. */ vd->vdev_offline = B_TRUE; - vdev_reopen(vd->vdev_top); - if (vd->vdev_aux == NULL && vdev_is_dead(vd->vdev_top)) { + vdev_reopen(tvd); + + if (!tvd->vdev_islog && vd->vdev_aux == NULL && + vdev_is_dead(tvd)) { vd->vdev_offline = B_FALSE; - vdev_reopen(vd->vdev_top); + vdev_reopen(tvd); return (spa_vdev_state_exit(spa, NULL, EBUSY)); } } vd->vdev_tmpoffline = !!(flags & ZFS_OFFLINE_TEMPORARY); - return (spa_vdev_state_exit(spa, vd, 0)); + if (!tvd->vdev_islog || !vdev_is_dead(tvd)) + return (spa_vdev_state_exit(spa, vd, 0)); + + (void) spa_vdev_state_exit(spa, vd, 0); + + error = dmu_objset_find(spa_name(spa), zil_vdev_offline, + NULL, DS_FIND_CHILDREN); + if (error) { + (void) vdev_online(spa, guid, 0, NULL); + return (error); + } + /* + * If we successfully offlined the log device then we need to + * sync out the current txg so that the "stubby" block can be + * removed by zil_sync(). + */ + txg_wait_synced(spa->spa_dsl_pool, 0); + return (0); } /* @@ -2178,6 +2207,16 @@ vdev_stat_update(zio_t *zio, uint64_t psize) if (flags & ZIO_FLAG_SPECULATIVE) return; + /* + * If this is an I/O error that is going to be retried, then ignore the + * error. Otherwise, the user may interpret B_FAILFAST I/O errors as + * hard errors, when in reality they can happen for any number of + * innocuous reasons (bus resets, MPxIO link failure, etc). + */ + if (zio->io_error == EIO && + !(zio->io_flags & ZIO_FLAG_IO_RETRY)) + return; + mutex_enter(&vd->vdev_stat_lock); if (type == ZIO_TYPE_READ && !vdev_is_dead(vd)) { if (zio->io_error == ECKSUM) @@ -2275,6 +2314,7 @@ vdev_space_update(vdev_t *vd, int64_t space_delta, int64_t alloc_delta, * childrens', thus not accurate enough for us. */ ASSERT((dspace_delta & (SPA_MINBLOCKSIZE-1)) == 0); + ASSERT(vd->vdev_deflate_ratio != 0 || vd->vdev_isl2cache); dspace_delta = (dspace_delta >> SPA_MINBLOCKSHIFT) * vd->vdev_deflate_ratio; @@ -2627,11 +2667,7 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux) boolean_t vdev_is_bootable(vdev_t *vd) { -#ifdef __FreeBSD_version - return (B_TRUE); -#else - int c; - +#ifdef sun if (!vd->vdev_ops->vdev_op_leaf) { char *vdev_type = vd->vdev_ops->vdev_op_type; @@ -2650,6 +2686,35 @@ vdev_is_bootable(vdev_t *vd) if (!vdev_is_bootable(vd->vdev_child[c])) return (B_FALSE); } +#endif /* sun */ return (B_TRUE); -#endif +} + +void +vdev_load_log_state(vdev_t *vd, nvlist_t *nv) +{ + uint_t c, children; + nvlist_t **child; + uint64_t val; + spa_t *spa = vd->vdev_spa; + + if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, + &child, &children) == 0) { + for (c = 0; c < children; c++) + vdev_load_log_state(vd->vdev_child[c], child[c]); + } + + if (vd->vdev_ops->vdev_op_leaf && nvlist_lookup_uint64(nv, + ZPOOL_CONFIG_OFFLINE, &val) == 0 && val) { + + /* + * It would be nice to call vdev_offline() + * directly but the pool isn't fully loaded and + * the txg threads have not been started yet. + */ + spa_config_enter(spa, SCL_STATE_ALL, FTAG, RW_WRITER); + vd->vdev_offline = val; + vdev_reopen(vd->vdev_top); + spa_config_exit(spa, SCL_STATE_ALL, FTAG); + } } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c index e6d5743efd4..5db7a6aec2f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_disk.c @@ -401,8 +401,9 @@ vdev_disk_io_start(zio_t *zio) bioinit(bp); bp->b_flags = B_BUSY | B_NOCACHE | - (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE) | - ((zio->io_flags & ZIO_FLAG_IO_RETRY) ? 0 : B_FAILFAST); + (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); + if (!(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) + bp->b_flags |= B_FAILFAST; bp->b_bcount = zio->io_size; bp->b_un.b_addr = zio->io_data; bp->b_lblkno = lbtodb(zio->io_offset); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c index 00817bfef24..d0d5137913c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_geom.c @@ -598,6 +598,7 @@ sendreq: break; case ZIO_TYPE_IOCTL: bp->bio_cmd = BIO_FLUSH; + bp->bio_flags |= BIO_ORDERED; bp->bio_data = NULL; bp->bio_offset = cp->provider->mediasize; bp->bio_length = 0; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c index f1f3bb0066c..48d5fc232b3 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c @@ -339,8 +339,8 @@ vdev_label_read_config(vdev_t *vd) nvlist_t *config = NULL; vdev_phys_t *vp; zio_t *zio; - int flags = - ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE; + int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | + ZIO_FLAG_SPECULATIVE; ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL); @@ -349,6 +349,7 @@ vdev_label_read_config(vdev_t *vd) vp = zio_buf_alloc(sizeof (vdev_phys_t)); +retry: for (int l = 0; l < VDEV_LABELS; l++) { zio = zio_root(spa, NULL, NULL, flags); @@ -368,6 +369,11 @@ vdev_label_read_config(vdev_t *vd) } } + if (config == NULL && !(flags & ZIO_FLAG_TRYHARD)) { + flags |= ZIO_FLAG_TRYHARD; + goto retry; + } + zio_buf_free(vp, sizeof (vdev_phys_t)); return (config); @@ -648,6 +654,7 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason) /* * Write everything in parallel. */ +retry: zio = zio_root(spa, NULL, NULL, flags); for (int l = 0; l < VDEV_LABELS; l++) { @@ -674,6 +681,11 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason) error = zio_wait(zio); + if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) { + flags |= ZIO_FLAG_TRYHARD; + goto retry; + } + nvlist_free(label); zio_buf_free(pad2, VDEV_PAD_SIZE); zio_buf_free(ub, VDEV_UBERBLOCK_SIZE(vd)); @@ -760,8 +772,8 @@ vdev_uberblock_load(zio_t *zio, vdev_t *vd, uberblock_t *ubbest) { spa_t *spa = vd->vdev_spa; vdev_t *rvd = spa->spa_root_vdev; - int flags = - ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE; + int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | + ZIO_FLAG_SPECULATIVE | ZIO_FLAG_TRYHARD; if (vd == rvd) { ASSERT(zio == NULL); @@ -999,7 +1011,7 @@ vdev_label_sync_list(spa_t *spa, int l, uint64_t txg, int flags) * at any time, you can just call it again, and it will resume its work. */ int -vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg) +vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard) { spa_t *spa = svd[0]->vdev_spa; uberblock_t *ub = &spa->spa_uberblock; @@ -1008,6 +1020,16 @@ vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg) int error; int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL; + /* + * Normally, we don't want to try too hard to write every label and + * uberblock. If there is a flaky disk, we don't want the rest of the + * sync process to block while we retry. But if we can't write a + * single label out, we should retry with ZIO_FLAG_TRYHARD before + * bailing out and declaring the pool faulted. + */ + if (tryhard) + flags |= ZIO_FLAG_TRYHARD; + ASSERT(ub->ub_txg <= txg); /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c index ac8404e36ac..de3f1db7596 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_queue.c @@ -233,7 +233,7 @@ vdev_queue_io_to_issue(vdev_queue_t *vq, uint64_t pending_limit) ASSERT(size <= zfs_vdev_aggregation_limit); aio = zio_vdev_delegated_io(fio->io_vd, fio->io_offset, - zio_buf_alloc(size), size, fio->io_type, ZIO_PRIORITY_NOW, + zio_buf_alloc(size), size, fio->io_type, ZIO_PRIORITY_AGG, flags | ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE, vdev_queue_agg_io_done, NULL); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c index c42f0941e75..fc25bfe1de1 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_acl.c @@ -91,6 +91,8 @@ #define ZFS_ACL_WIDE_FLAGS (V4_ACL_WIDE_FLAGS|ZFS_ACL_TRIVIAL|ZFS_INHERIT_ACE|\ ZFS_ACL_OBJ_ACE) +#define ALL_MODE_EXECS (S_IXUSR | S_IXGRP | S_IXOTH) + static uint16_t zfs_ace_v0_get_type(void *acep) { @@ -779,6 +781,7 @@ zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp) uint64_t who; uint16_t iflags, type; uint32_t access_mask; + boolean_t an_exec_denied = B_FALSE; mode = (zp->z_phys->zp_mode & (S_IFMT | S_ISUID | S_ISGID | S_ISVTX)); @@ -903,8 +906,32 @@ zfs_mode_compute(znode_t *zp, zfs_acl_t *aclp) } } } + } else { + /* + * Only care if this IDENTIFIER_GROUP or + * USER ACE denies execute access to someone, + * mode is not affected + */ + if ((access_mask & ACE_EXECUTE) && type == DENY) + an_exec_denied = B_TRUE; } } + + /* + * Failure to allow is effectively a deny, so execute permission + * is denied if it was never mentioned or if we explicitly + * weren't allowed it. + */ + if (!an_exec_denied && + ((seen & ALL_MODE_EXECS) != ALL_MODE_EXECS || + (mode & ALL_MODE_EXECS) != ALL_MODE_EXECS)) + an_exec_denied = B_TRUE; + + if (an_exec_denied) + zp->z_phys->zp_flags &= ~ZFS_NO_EXECS_DENIED; + else + zp->z_phys->zp_flags |= ZFS_NO_EXECS_DENIED; + return (mode); } @@ -944,7 +971,8 @@ zfs_acl_node_read_internal(znode_t *zp, boolean_t will_modify) } /* - * Read an external acl object. + * Read an external acl object. If the intent is to modify, always + * create a new acl and leave any cached acl in place. */ static int zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) @@ -958,8 +986,15 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) ASSERT(MUTEX_HELD(&zp->z_acl_lock)); + if (zp->z_acl_cached && !will_modify) { + *aclpp = zp->z_acl_cached; + return (0); + } + if (zp->z_phys->zp_acl.z_acl_extern_obj == 0) { *aclpp = zfs_acl_node_read_internal(zp, will_modify); + if (!will_modify) + zp->z_acl_cached = *aclpp; return (0); } @@ -993,6 +1028,8 @@ zfs_acl_node_read(znode_t *zp, zfs_acl_t **aclpp, boolean_t will_modify) } *aclpp = aclp; + if (!will_modify) + zp->z_acl_cached = aclp; return (0); } @@ -1017,11 +1054,16 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) dmu_buf_will_dirty(zp->z_dbuf, tx); + if (zp->z_acl_cached) { + zfs_acl_free(zp->z_acl_cached); + zp->z_acl_cached = NULL; + } + zphys->zp_mode = zfs_mode_compute(zp, aclp); /* - * Decide which opbject type to use. If we are forced to - * use old ACL format than transform ACL into zfs_oldace_t + * Decide which object type to use. If we are forced to + * use old ACL format then transform ACL into zfs_oldace_t * layout. */ if (!zfsvfs->z_use_fuids) { @@ -1871,7 +1913,6 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, mutex_exit(&dzp->z_acl_lock); acl_ids->z_aclp = zfs_acl_inherit(zfsvfs, vap->va_type, paclp, acl_ids->z_mode, &need_chmod); - zfs_acl_free(paclp); } else { acl_ids->z_aclp = zfs_acl_alloc(zfs_acl_version_zp(dzp)); @@ -1972,8 +2013,6 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (mask & VSA_ACE) { size_t aclsz; - zfs_acl_node_t *aclnode = list_head(&aclp->z_acl); - aclsz = count * sizeof (ace_t) + sizeof (ace_object_t) * largeace; @@ -1984,8 +2023,17 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) zfs_copy_fuid_2_ace(zp->z_zfsvfs, aclp, cr, vsecp->vsa_aclentp, !(mask & VSA_ACE_ALLTYPES)); else { - bcopy(aclnode->z_acldata, vsecp->vsa_aclentp, - count * sizeof (ace_t)); + zfs_acl_node_t *aclnode; + void *start = vsecp->vsa_aclentp; + + for (aclnode = list_head(&aclp->z_acl); aclnode; + aclnode = list_next(&aclp->z_acl, aclnode)) { + bcopy(aclnode->z_acldata, start, + aclnode->z_size); + start = (caddr_t)start + aclnode->z_size; + } + ASSERT((caddr_t)start - (caddr_t)vsecp->vsa_aclentp == + aclp->z_acl_bytes); } } if (mask & VSA_ACE_ACLFLAGS) { @@ -2000,8 +2048,6 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) mutex_exit(&zp->z_acl_lock); - zfs_acl_free(aclp); - return (0); } @@ -2097,11 +2143,6 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) aclp->z_hints |= (zp->z_phys->zp_flags & V4_ACL_WIDE_FLAGS); } top: - if (error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr)) { - zfs_acl_free(aclp); - return (error); - } - mutex_enter(&zp->z_lock); mutex_enter(&zp->z_acl_lock); @@ -2147,6 +2188,7 @@ top: error = zfs_aclset_common(zp, aclp, cr, tx); ASSERT(error == 0); + zp->z_acl_cached = aclp; if (fuid_dirtied) zfs_fuid_sync(zfsvfs, tx); @@ -2156,7 +2198,6 @@ top: if (fuidp) zfs_fuid_info_free(fuidp); - zfs_acl_free(aclp); dmu_tx_commit(tx); done: mutex_exit(&zp->z_acl_lock); @@ -2166,46 +2207,17 @@ done: } /* - * working_mode returns the permissions that were not granted + * Check accesses of interest (AoI) against attributes of the dataset + * such as read-only. Returns zero if no AoI conflict with dataset + * attributes, otherwise an appropriate errno is returned. */ static int -zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, - boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) +zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) { - zfs_acl_t *aclp; - zfsvfs_t *zfsvfs = zp->z_zfsvfs; - int error; - uid_t uid = crgetuid(cr); - uint64_t who; - uint16_t type, iflags; - uint16_t entry_type; - uint32_t access_mask; - uint32_t deny_mask = 0; - zfs_ace_hdr_t *acep = NULL; - boolean_t checkit; - uid_t fowner; - uid_t gowner; - - /* - * Short circuit empty requests - */ - if (v4_mode == 0) - return (0); - - *check_privs = B_TRUE; - - if (zfsvfs->z_replay) { - *working_mode = 0; - return (0); - } - - *working_mode = v4_mode; - if ((v4_mode & WRITE_MASK) && (zp->z_zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) && (!IS_DEVVP(ZTOV(zp)) || (IS_DEVVP(ZTOV(zp)) && (v4_mode & WRITE_MASK_ATTRS)))) { - *check_privs = B_FALSE; return (EROFS); } @@ -2217,14 +2229,12 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, (zp->z_phys->zp_flags & (ZFS_READONLY | ZFS_IMMUTABLE))) || (ZTOV(zp)->v_type == VDIR && (zp->z_phys->zp_flags & ZFS_IMMUTABLE)))) { - *check_privs = B_FALSE; return (EPERM); } #ifdef sun if ((v4_mode & (ACE_DELETE | ACE_DELETE_CHILD)) && (zp->z_phys->zp_flags & ZFS_NOUNLINK)) { - *check_privs = B_FALSE; return (EPERM); } #else @@ -2235,26 +2245,60 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, */ if ((v4_mode & ACE_DELETE) && (zp->z_phys->zp_flags & ZFS_NOUNLINK)) { - *check_privs = B_FALSE; return (EPERM); } #endif if (((v4_mode & (ACE_READ_DATA|ACE_EXECUTE)) && (zp->z_phys->zp_flags & ZFS_AV_QUARANTINED))) { - *check_privs = B_FALSE; return (EACCES); } - /* - * The caller requested that the ACL check be skipped. This - * would only happen if the caller checked VOP_ACCESS() with a - * 32 bit ACE mask and already had the appropriate permissions. - */ - if (skipaclchk) { - *working_mode = 0; - return (0); - } + return (0); +} + +/* + * The primary usage of this function is to loop through all of the + * ACEs in the znode, determining what accesses of interest (AoI) to + * the caller are allowed or denied. The AoI are expressed as bits in + * the working_mode parameter. As each ACE is processed, bits covered + * by that ACE are removed from the working_mode. This removal + * facilitates two things. The first is that when the working mode is + * empty (= 0), we know we've looked at all the AoI. The second is + * that the ACE interpretation rules don't allow a later ACE to undo + * something granted or denied by an earlier ACE. Removing the + * discovered access or denial enforces this rule. At the end of + * processing the ACEs, all AoI that were found to be denied are + * placed into the working_mode, giving the caller a mask of denied + * accesses. Returns: + * 0 if all AoI granted + * EACCESS if the denied mask is non-zero + * other error if abnormal failure (e.g., IO error) + * + * A secondary usage of the function is to determine if any of the + * AoI are granted. If an ACE grants any access in + * the working_mode, we immediately short circuit out of the function. + * This mode is chosen by setting anyaccess to B_TRUE. The + * working_mode is not a denied access mask upon exit if the function + * is used in this manner. + */ +static int +zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, + boolean_t anyaccess, cred_t *cr) +{ + zfsvfs_t *zfsvfs = zp->z_zfsvfs; + zfs_acl_t *aclp; + int error; + uid_t uid = crgetuid(cr); + uint64_t who; + uint16_t type, iflags; + uint16_t entry_type; + uint32_t access_mask; + uint32_t deny_mask = 0; + zfs_ace_hdr_t *acep = NULL; + boolean_t checkit; + uid_t fowner; + uid_t gowner; zfs_fuid_map_ids(zp, cr, &fowner, &gowner); @@ -2268,6 +2312,7 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, while (acep = zfs_acl_next_ace(aclp, acep, &who, &access_mask, &iflags, &type)) { + uint32_t mask_matched; if (!zfs_acl_valid_ace_type(type, iflags)) continue; @@ -2275,6 +2320,11 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, if (ZTOV(zp)->v_type == VDIR && (iflags & ACE_INHERIT_ONLY_ACE)) continue; + /* Skip ACE if it does not affect any AoI */ + mask_matched = (access_mask & *working_mode); + if (!mask_matched) + continue; + entry_type = (iflags & ACE_TYPE_FLAGS); checkit = B_FALSE; @@ -2306,21 +2356,29 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, checkit = B_TRUE; break; } else { - zfs_acl_free(aclp); mutex_exit(&zp->z_acl_lock); return (EIO); } } if (checkit) { - uint32_t mask_matched = (access_mask & *working_mode); - - if (mask_matched) { - if (type == DENY) - deny_mask |= mask_matched; - - *working_mode &= ~mask_matched; + if (type == DENY) { + DTRACE_PROBE3(zfs__ace__denies, + znode_t *, zp, + zfs_ace_hdr_t *, acep, + uint32_t, mask_matched); + deny_mask |= mask_matched; + } else { + DTRACE_PROBE3(zfs__ace__allows, + znode_t *, zp, + zfs_ace_hdr_t *, acep, + uint32_t, mask_matched); + if (anyaccess) { + mutex_exit(&zp->z_acl_lock); + return (0); + } } + *working_mode &= ~mask_matched; } /* Are we done? */ @@ -2329,7 +2387,6 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, } mutex_exit(&zp->z_acl_lock); - zfs_acl_free(aclp); /* Put the found 'denies' back on the working mode */ if (deny_mask) { @@ -2342,6 +2399,68 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, return (0); } +/* + * Return true if any access whatsoever granted, we don't actually + * care what access is granted. + */ +boolean_t +zfs_has_access(znode_t *zp, cred_t *cr) +{ + uint32_t have = ACE_ALL_PERMS; + + if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { + uid_t owner; + + owner = zfs_fuid_map_id(zp->z_zfsvfs, + zp->z_phys->zp_uid, cr, ZFS_OWNER); + + return ( + secpolicy_vnode_access(cr, ZTOV(zp), owner, VREAD) == 0 || + secpolicy_vnode_access(cr, ZTOV(zp), owner, VWRITE) == 0 || + secpolicy_vnode_access(cr, ZTOV(zp), owner, VEXEC) == 0 || + secpolicy_vnode_chown(ZTOV(zp), cr, owner) == 0 || + secpolicy_vnode_setdac(ZTOV(zp), cr, owner) == 0 || + secpolicy_vnode_remove(ZTOV(zp), cr) == 0); + } + return (B_TRUE); +} + +static int +zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, + boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) +{ + zfsvfs_t *zfsvfs = zp->z_zfsvfs; + int err; + + *working_mode = v4_mode; + *check_privs = B_TRUE; + + /* + * Short circuit empty requests + */ + if (v4_mode == 0 || zfsvfs->z_replay) { + *working_mode = 0; + return (0); + } + + if ((err = zfs_zaccess_dataset_check(zp, v4_mode)) != 0) { + *check_privs = B_FALSE; + return (err); + } + + /* + * The caller requested that the ACL check be skipped. This + * would only happen if the caller checked VOP_ACCESS() with a + * 32 bit ACE mask and already had the appropriate permissions. + */ + if (skipaclchk) { + *working_mode = 0; + return (0); + } + + return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); +} + static int zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, cred_t *cr) @@ -2353,6 +2472,78 @@ zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, check_privs, B_FALSE, cr)); } +int +zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) +{ + boolean_t owner = B_FALSE; + boolean_t groupmbr = B_FALSE; + boolean_t is_attr; + uid_t fowner; + uid_t gowner; + uid_t uid = crgetuid(cr); + int error; + + if (zdp->z_phys->zp_flags & ZFS_AV_QUARANTINED) + return (EACCES); + + is_attr = ((zdp->z_phys->zp_flags & ZFS_XATTR) && + (ZTOV(zdp)->v_type == VDIR)); + if (is_attr) + goto slow; + + mutex_enter(&zdp->z_acl_lock); + + if (zdp->z_phys->zp_flags & ZFS_NO_EXECS_DENIED) { + mutex_exit(&zdp->z_acl_lock); + return (0); + } + + if (FUID_INDEX(zdp->z_phys->zp_uid) != 0 || + FUID_INDEX(zdp->z_phys->zp_gid) != 0) { + mutex_exit(&zdp->z_acl_lock); + goto slow; + } + + fowner = (uid_t)zdp->z_phys->zp_uid; + gowner = (uid_t)zdp->z_phys->zp_gid; + + if (uid == fowner) { + owner = B_TRUE; + if (zdp->z_phys->zp_mode & S_IXUSR) { + mutex_exit(&zdp->z_acl_lock); + return (0); + } else { + mutex_exit(&zdp->z_acl_lock); + goto slow; + } + } + if (groupmember(gowner, cr)) { + groupmbr = B_TRUE; + if (zdp->z_phys->zp_mode & S_IXGRP) { + mutex_exit(&zdp->z_acl_lock); + return (0); + } else { + mutex_exit(&zdp->z_acl_lock); + goto slow; + } + } + if (!owner && !groupmbr) { + if (zdp->z_phys->zp_mode & S_IXOTH) { + mutex_exit(&zdp->z_acl_lock); + return (0); + } + } + + mutex_exit(&zdp->z_acl_lock); + +slow: + DTRACE_PROBE(zfs__fastpath__execute__access__miss); + ZFS_ENTER(zdp->z_zfsvfs); + error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); + ZFS_EXIT(zdp->z_zfsvfs); + return (error); +} + /* * Determine whether Access should be granted/denied, invoking least * priv subsytem when a deny is determined. @@ -2457,7 +2648,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) owner, checkmode); if (error == 0 && (working_mode & ACE_WRITE_OWNER)) - error = secpolicy_vnode_chown(ZTOV(check_zp), cr, B_TRUE); + error = secpolicy_vnode_chown(ZTOV(check_zp), cr, owner); if (error == 0 && (working_mode & ACE_WRITE_ACL)) error = secpolicy_vnode_setdac(ZTOV(check_zp), cr, owner); @@ -2466,7 +2657,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) error = secpolicy_vnode_remove(ZTOV(check_zp), cr); if (error == 0 && (working_mode & ACE_SYNCHRONIZE)) { - error = secpolicy_vnode_chown(ZTOV(check_zp), cr, B_FALSE); + error = secpolicy_vnode_chown(ZTOV(check_zp), cr, owner); } if (error == 0) { /* diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c index 361b17d0763..48c3ebf78a5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -152,6 +151,17 @@ zfsctl_fini(void) { } +boolean_t +zfsctl_is_node(vnode_t *vp) +{ + return (vn_matchops(vp, zfsctl_ops_root) || + vn_matchops(vp, zfsctl_ops_snapdir) || + vn_matchops(vp, zfsctl_ops_snapshot) || + vn_matchops(vp, zfsctl_ops_shares) || + vn_matchops(vp, zfsctl_ops_shares_dir)); + +} + /* * Return the inode number associated with the 'snapshot' or * 'shares' directory. @@ -965,9 +975,10 @@ zfsctl_snapdir_lookup(ap) dmu_objset_close(snap); domount: mountpoint_len = strlen(dvp->v_vfsp->mnt_stat.f_mntonname) + - strlen("/.zfs/snapshot/") + strlen(nm) + 1; + strlen("/" ZFS_CTLDIR_NAME "/snapshot/") + strlen(nm) + 1; mountpoint = kmem_alloc(mountpoint_len, KM_SLEEP); - (void) snprintf(mountpoint, mountpoint_len, "%s/.zfs/snapshot/%s", + (void) snprintf(mountpoint, mountpoint_len, + "%s/" ZFS_CTLDIR_NAME "/snapshot/%s", dvp->v_vfsp->mnt_stat.f_mntonname, nm); err = mount_snapshot(curthread, vpp, "zfs", mountpoint, snapname, 0); kmem_free(mountpoint, mountpoint_len); @@ -1100,8 +1111,9 @@ zfsctl_shares_readdir(ap) return (ENOTSUP); } if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { + vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); error = VOP_READDIR(ZTOV(dzp), uiop, cr, eofp, ap->a_ncookies, ap->a_cookies); - VN_RELE(ZTOV(dzp)); + VN_URELE(ZTOV(dzp)); } else { *eofp = 1; error = ENOENT; @@ -1148,6 +1160,7 @@ zfsctl_mknode_shares(vnode_t *pvp) NULL, NULL); sdp = vp->v_data; sdp->zc_cmtime = ((zfsctl_node_t *)pvp->v_data)->zc_cmtime; + VOP_UNLOCK(vp, 0); return (vp); } @@ -1175,8 +1188,9 @@ zfsctl_shares_getattr(ap) return (ENOTSUP); } if ((error = zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp)) == 0) { + vn_lock(ZTOV(dzp), LK_SHARED | LK_RETRY); error = VOP_GETATTR(ZTOV(dzp), vap, cr); - VN_RELE(ZTOV(dzp)); + VN_URELE(ZTOV(dzp)); } ZFS_EXIT(zfsvfs); return (error); @@ -1252,6 +1266,20 @@ static struct vop_vector zfsctl_ops_snapdir = { .vop_fid = zfsctl_common_fid, }; +static struct vop_vector zfsctl_ops_shares = { + .vop_default = &default_vnodeops, + .vop_open = zfsctl_common_open, + .vop_close = zfsctl_common_close, + .vop_ioctl = VOP_EINVAL, + .vop_getattr = zfsctl_shares_getattr, + .vop_access = zfsctl_common_access, + .vop_readdir = zfsctl_shares_readdir, + .vop_lookup = zfsctl_shares_lookup, + .vop_inactive = gfs_vop_inactive, + .vop_reclaim = zfsctl_common_reclaim, + .vop_fid = zfsctl_shares_fid, +}; + /* * pvp is the GFS vnode '.zfs/snapshot'. * diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_fm.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_fm.c index 63ae13ac856..4b27ec324c9 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_fm.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_fm.c @@ -101,6 +101,7 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio, char buf[1024]; struct sbuf sb; struct timespec ts; + int error; /* * If we are doing a spa_tryimport(), ignore errors. @@ -133,6 +134,15 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio, if (zio->io_flags & ZIO_FLAG_SPECULATIVE) return; + /* + * If this I/O is not a retry I/O, don't post an ereport. + * Otherwise, we risk making bad diagnoses based on B_FAILFAST + * I/Os. + */ + if (zio->io_error == EIO && + !(zio->io_flags & ZIO_FLAG_IO_RETRY)) + return; + if (vd != NULL) { /* * If the vdev has already been marked as failing due @@ -315,9 +325,9 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio, } mutex_exit(&spa->spa_errlist_lock); - sbuf_finish(&sb); + error = sbuf_finish(&sb); devctl_notify("ZFS", spa->spa_name, subclass, sbuf_data(&sb)); - if (sbuf_overflowed(&sb)) + if (error != 0) printf("ZFS WARNING: sbuf overflowed\n"); sbuf_delete(&sb); #endif @@ -331,6 +341,7 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name) char class[64]; struct sbuf sb; struct timespec ts; + int error; nanotime(&ts); @@ -339,17 +350,17 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name) snprintf(class, sizeof(class), "%s.%s.%s", FM_RSRC_RESOURCE, ZFS_ERROR_CLASS, name); - sbuf_printf(&sb, " %s=%hhu", FM_VERSION, FM_RSRC_VERSION); + sbuf_printf(&sb, " %s=%d", FM_VERSION, FM_RSRC_VERSION); sbuf_printf(&sb, " %s=%s", FM_CLASS, class); sbuf_printf(&sb, " %s=%ju", FM_EREPORT_PAYLOAD_ZFS_POOL_GUID, spa_guid(spa)); if (vd) sbuf_printf(&sb, " %s=%ju", FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vd->vdev_guid); - sbuf_finish(&sb); + error = sbuf_finish(&sb); ZFS_LOG(1, "%s", sbuf_data(&sb)); devctl_notify("ZFS", spa->spa_name, class, sbuf_data(&sb)); - if (sbuf_overflowed(&sb)) + if (error != 0) printf("ZFS WARNING: sbuf overflowed\n"); sbuf_delete(&sb); #endif diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index 764b577b0ae..430a1b934ae 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c @@ -1217,8 +1217,12 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc) { spa_t *spa; int error; +#ifdef sun nvlist_t *config, **l2cache, **spares; uint_t nl2cache = 0, nspares = 0; +#else + nvlist_t *config; +#endif error = spa_open(zc->zc_name, &spa, FTAG); if (error != 0) @@ -1226,6 +1230,7 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc) error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size, &config); +#ifdef sun (void) nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache); @@ -1246,6 +1251,7 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc) spa_close(spa, FTAG); return (EDOM); } +#endif if (error == 0) { error = spa_vdev_add(spa, config); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index d2bd7ad0b7b..30a1b315b3f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -994,6 +994,7 @@ zfs_set_fuid_feature(zfsvfs_t *zfsvfs) vfs_set_feature(zfsvfs->z_vfs, VFSFT_SYSATTR_VIEWS); vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACEMASKONACCESS); vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACLONCREATE); + vfs_set_feature(zfsvfs->z_vfs, VFSFT_ACCESS_FILTER); } } @@ -1162,8 +1163,7 @@ zfs_mount(vfs_t *vfsp) */ error = secpolicy_fs_mount(cr, mvp, vfsp); if (error) { - error = dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr); - if (error != 0) + if (dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr) != 0) goto out; if (!(vfsp->vfs_flag & MS_REMOUNT)) { @@ -1177,7 +1177,7 @@ zfs_mount(vfs_t *vfsp) vattr.va_mask = AT_UID; vn_lock(mvp, LK_SHARED | LK_RETRY); - if (error = VOP_GETATTR(mvp, &vattr, cr)) { + if (VOP_GETATTR(mvp, &vattr, cr)) { VOP_UNLOCK(mvp, 0); goto out; } @@ -1225,13 +1225,6 @@ zfs_mount(vfs_t *vfsp) if (error == 0 && ((zfsvfs_t *)vfsp->vfs_data)->z_issnap) VFS_HOLD(mvp->v_vfsp); - /* - * Add an extra VFS_HOLD on our parent vfs so that it can't - * disappear due to a forced unmount. - */ - if (error == 0 && ((zfsvfs_t *)vfsp->vfs_data)->z_issnap) - VFS_HOLD(mvp->v_vfsp); - out: return (error); } @@ -1439,9 +1432,8 @@ zfs_umount(vfs_t *vfsp, int fflag) ret = secpolicy_fs_unmount(cr, vfsp); if (ret) { - ret = dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), - ZFS_DELEG_PERM_MOUNT, cr); - if (ret) + if (dsl_deleg_access((char *)refstr_value(vfsp->vfs_resource), + ZFS_DELEG_PERM_MOUNT, cr)) return (ret); } /* @@ -1563,15 +1555,9 @@ zfs_vget(vfs_t *vfsp, ino_t ino, int flags, vnode_t **vpp) int err; /* - * XXXPJD: zfs_zget() can't operate on virtual entires like .zfs/ or - * .zfs/snapshot/ directories, so for now just return EOPNOTSUPP. - * This will make NFS to fall back to using READDIR instead of - * READDIRPLUS. - * Also snapshots are stored in AVL tree, but based on their names, - * not inode numbers, so it will be very inefficient to iterate - * over all snapshots to find the right one. - * Note that OpenSolaris READDIRPLUS implementation does LOOKUP on - * d_name, and not VGET on d_fileno as we do. + * zfs_zget() can't operate on virtual entires like .zfs/ or + * .zfs/snapshot/ directories, that's why we return EOPNOTSUPP. + * This will make NFS to switch to LOOKUP instead of using VGET. */ if (ino == ZFSCTL_INO_ROOT || ino == ZFSCTL_INO_SNAPDIR) return (EOPNOTSUPP); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 8ba0843161a..bcbe514ad7a 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Portions Copyright 2007 Jeremy Teo */ @@ -323,12 +322,19 @@ page_lookup(vnode_t *vp, int64_t start, int64_t off, int64_t nbytes) for (;;) { if ((pp = vm_page_lookup(obj, OFF_TO_IDX(start))) != NULL && vm_page_is_valid(pp, (vm_offset_t)off, nbytes)) { - if (vm_page_sleep_if_busy(pp, FALSE, "zfsmwb")) + if ((pp->oflags & VPO_BUSY) != 0) { + /* + * Reference the page before unlocking and + * sleeping so that the page daemon is less + * likely to reclaim it. + */ + vm_page_lock_queues(); + vm_page_flag_set(pp, PG_REFERENCED); + vm_page_sleep(pp, "zfsmwb"); continue; + } vm_page_busy(pp); - vm_page_lock_queues(); vm_page_undirty(pp); - vm_page_unlock_queues(); } else { if (__predict_false(obj->cache != NULL)) { vm_page_cache_free(obj, OFF_TO_IDX(start), @@ -352,8 +358,7 @@ static caddr_t zfs_map_page(vm_page_t pp, struct sf_buf **sfp) { - sched_pin(); - *sfp = sf_buf_alloc(pp, SFB_CPUPRIVATE); + *sfp = sf_buf_alloc(pp, 0); return ((caddr_t)sf_buf_kva(*sfp)); } @@ -362,7 +367,6 @@ zfs_unmap_page(struct sf_buf *sf) { sf_buf_free(sf); - sched_unpin(); } @@ -380,7 +384,7 @@ update_pages(vnode_t *vp, int64_t start, int len, objset_t *os, uint64_t oid, { vm_object_t obj; struct sf_buf *sf; - int64_t off; + int off; ASSERT(vp->v_mount != NULL); obj = vp->v_object; @@ -390,7 +394,7 @@ update_pages(vnode_t *vp, int64_t start, int len, objset_t *os, uint64_t oid, VM_OBJECT_LOCK(obj); for (start &= PAGEMASK; len > 0; start += PAGESIZE) { vm_page_t pp; - uint64_t nbytes = MIN(PAGESIZE - off, len); + int nbytes = MIN(PAGESIZE - off, len); if ((pp = page_lookup(vp, start, off, nbytes)) != NULL) { caddr_t va; @@ -433,9 +437,10 @@ mappedread(vnode_t *vp, int nbytes, uio_t *uio) vm_object_t obj; vm_page_t m; struct sf_buf *sf; - int64_t start, off; + int64_t start; caddr_t va; int len = nbytes; + int off; int error = 0; uint64_t dirbytes; @@ -448,13 +453,23 @@ mappedread(vnode_t *vp, int nbytes, uio_t *uio) dirbytes = 0; VM_OBJECT_LOCK(obj); for (start &= PAGEMASK; len > 0; start += PAGESIZE) { - uint64_t bytes = MIN(PAGESIZE - off, len); + int bytes = MIN(PAGESIZE - off, len); again: if ((m = vm_page_lookup(obj, OFF_TO_IDX(start))) != NULL && - vm_page_is_valid(m, (vm_offset_t)off, bytes)) { - if (vm_page_sleep_if_busy(m, FALSE, "zfsmrb")) + vm_page_is_valid(m, off, bytes)) { + if ((m->oflags & VPO_BUSY) != 0) { + /* + * Reference the page before unlocking and + * sleeping so that the page daemon is less + * likely to reclaim it. + */ + vm_page_lock_queues(); + vm_page_flag_set(m, PG_REFERENCED); + vm_page_sleep(m, "zfsmrb"); goto again; + } + vm_page_busy(m); VM_OBJECT_UNLOCK(obj); if (dirbytes > 0) { @@ -462,14 +477,8 @@ again: dirbytes); dirbytes = 0; } - if (error == 0) { - sched_pin(); - sf = sf_buf_alloc(m, SFB_CPUPRIVATE); - va = (caddr_t)sf_buf_kva(sf); - error = uiomove(va + off, bytes, UIO_READ, uio); - sf_buf_free(sf); - sched_unpin(); - } + if (error == 0) + uiomove_fromphys(&m, off, bytes, uio); VM_OBJECT_LOCK(obj); vm_page_wakeup(m); } else if (m != NULL && uio->uio_segflg == UIO_NOCOPY) { @@ -480,8 +489,19 @@ again: * but it pessimize performance of sendfile/UFS, that's * why I handle this special case in ZFS code. */ - if (vm_page_sleep_if_busy(m, FALSE, "zfsmrb")) + KASSERT(off == 0, + ("unexpected offset in mappedread for sendfile")); + if ((m->oflags & VPO_BUSY) != 0) { + /* + * Reference the page before unlocking and + * sleeping so that the page daemon is less + * likely to reclaim it. + */ + vm_page_lock_queues(); + vm_page_flag_set(m, PG_REFERENCED); + vm_page_sleep(m, "zfsmrb"); goto again; + } vm_page_busy(m); VM_OBJECT_UNLOCK(obj); if (dirbytes > 0) { @@ -490,19 +510,21 @@ again: dirbytes = 0; } if (error == 0) { - sched_pin(); - sf = sf_buf_alloc(m, SFB_CPUPRIVATE); - va = (caddr_t)sf_buf_kva(sf); - error = dmu_read(os, zp->z_id, start + off, - bytes, (void *)(va + off), + va = zfs_map_page(m, &sf); + error = dmu_read(os, zp->z_id, start, bytes, va, DMU_READ_PREFETCH); - sf_buf_free(sf); - sched_unpin(); + if (bytes != PAGE_SIZE) + bzero(va + bytes, PAGE_SIZE - bytes); + zfs_unmap_page(sf); } VM_OBJECT_LOCK(obj); - vm_page_wakeup(m); if (error == 0) + m->valid = VM_PAGE_BITS_ALL; + vm_page_wakeup(m); + if (error == 0) { uio->uio_resid -= bytes; + uio->uio_offset += bytes; + } } else { dirbytes += bytes; } @@ -686,7 +708,7 @@ zfs_prefault_write(ssize_t n, struct uio *uio) * IN: vp - vnode of file to be written to. * uio - structure supplying write location, range info, * and data buffer. - * ioflag - IO_APPEND flag set if in append mode. + * ioflag - FAPPEND flag set if in append mode. * cr - credentials of caller. * ct - caller context (NFS/CIFS fem monitor only) * @@ -753,7 +775,7 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct) /* * If in append mode, set the io offset pointer to eof. */ - if (ioflag & IO_APPEND) { + if (ioflag & FAPPEND) { /* * Range lock for a file append: * The value for the start of range will be determined by @@ -910,17 +932,7 @@ again: uioskip(uio, tx_bytes); } - /* - * XXXPJD: There are some cases (triggered by fsx) where - * vn_has_cached_data(vp) returns false when it should - * return true. This should be investigated. - */ -#if 0 - if (tx_bytes && vn_has_cached_data(vp)) -#else - if (tx_bytes && vp->v_object != NULL) -#endif - { + if (tx_bytes && vn_has_cached_data(vp)) { update_pages(vp, woff, tx_bytes, zfsvfs->z_os, zp->z_id, uio->uio_segflg, tx); } @@ -1163,6 +1175,27 @@ zfs_access(vnode_t *vp, int mode, int flag, cred_t *cr, return (error); } +/* + * If vnode is for a device return a specfs vnode instead. + */ +static int +specvp_check(vnode_t **vpp, cred_t *cr) +{ + int error = 0; + + if (IS_DEVVP(*vpp)) { + struct vnode *svp; + + svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); + VN_RELE(*vpp); + if (svp == NULL) + error = ENOSYS; + *vpp = svp; + } + return (error); +} + + /* * Lookup an entry in a directory, or an extended attribute directory. * If it exists, return a held vnode reference for it. @@ -1192,10 +1225,49 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct componentname *cnp, { znode_t *zdp = VTOZ(dvp); zfsvfs_t *zfsvfs = zdp->z_zfsvfs; - int error; + int error = 0; int *direntflags = NULL; void *realpnp = NULL; + /* fast path */ + if (!(flags & (LOOKUP_XATTR | FIGNORECASE))) { + + if (dvp->v_type != VDIR) { + return (ENOTDIR); + } else if (zdp->z_dbuf == NULL) { + return (EIO); + } + + if (nm[0] == 0 || (nm[0] == '.' && nm[1] == '\0')) { + error = zfs_fastaccesschk_execute(zdp, cr); + if (!error) { + *vpp = dvp; + VN_HOLD(*vpp); + return (0); + } + return (error); + } else { + vnode_t *tvp = dnlc_lookup(dvp, nm); + + if (tvp) { + error = zfs_fastaccesschk_execute(zdp, cr); + if (error) { + VN_RELE(tvp); + return (error); + } + if (tvp == DNLC_NO_VNODE) { + VN_RELE(tvp); + return (ENOENT); + } else { + *vpp = tvp; + return (specvp_check(vpp, cr)); + } + } + } + } + + DTRACE_PROBE2(zfs__fastpath__lookup__miss, vnode_t *, dvp, char *, nm); + ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zdp); @@ -1261,21 +1333,8 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct componentname *cnp, } error = zfs_dirlook(zdp, nm, vpp, flags, direntflags, realpnp); - if (error == 0) { - /* - * Convert device special files - */ - if (IS_DEVVP(*vpp)) { - vnode_t *svp; - - svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); - VN_RELE(*vpp); - if (svp == NULL) - error = ENOSYS; - else - *vpp = svp; - } - } + if (error == 0) + error = specvp_check(vpp, cr); /* Translate errors and add SAVENAME when needed. */ if (cnp->cn_flags & ISLASTCN) { @@ -1468,6 +1527,7 @@ top: &acl_ids)) != 0) goto out; if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { + zfs_acl_ids_free(&acl_ids); error = EDQUOT; goto out; } @@ -1564,19 +1624,7 @@ out: VN_RELE(ZTOV(zp)); } else { *vpp = ZTOV(zp); - /* - * If vnode is for a device return a specfs vnode instead. - */ - if (IS_DEVVP(*vpp)) { - struct vnode *svp; - - svp = specvp(*vpp, (*vpp)->v_rdev, (*vpp)->v_type, cr); - VN_RELE(*vpp); - if (svp == NULL) { - error = ENOSYS; - } - *vpp = svp; - } + error = specvp_check(vpp, cr); } ZFS_EXIT(zfsvfs); @@ -1883,6 +1931,7 @@ top: return (error); } if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) { + zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); ZFS_EXIT(zfsvfs); return (EDQUOT); @@ -2274,6 +2323,21 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, int *ncookies, u_lon } } + if (flags & V_RDDIR_ACCFILTER) { + /* + * If we have no access at all, don't include + * this entry in the returned information + */ + znode_t *ezp; + if (zfs_zget(zp->z_zfsvfs, objnum, &ezp) != 0) + goto skip_entry; + if (!zfs_has_access(ezp, cr)) { + VN_RELE(ZTOV(ezp)); + goto skip_entry; + } + VN_RELE(ZTOV(ezp)); + } + if (flags & V_RDDIR_ENTFLAGS) reclen = EDIRENT_RECLEN(strlen(zap.za_name)); else @@ -2324,6 +2388,7 @@ zfs_readdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, int *ncookies, u_lon if (prefetch) dmu_prefetch(os, objnum, 0, 0); + skip_entry: /* * Move to the next entry, fill in the previous offset. */ @@ -2712,6 +2777,7 @@ zfs_setattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, top: attrzp = NULL; + /* Can this be moved to before the top label? */ if (zfsvfs->z_vfs->vfs_flag & VFS_RDONLY) { ZFS_EXIT(zfsvfs); return (EROFS); @@ -3036,6 +3102,8 @@ top: zp->z_phys->zp_mode = new_mode; err = zfs_aclset_common(zp, aclp, cr, tx); ASSERT3U(err, ==, 0); + zp->z_acl_cached = aclp; + aclp = NULL; mutex_exit(&zp->z_acl_lock); } @@ -3127,10 +3195,8 @@ out: if (attrzp) VN_RELE(ZTOV(attrzp)); - if (aclp) { + if (aclp) zfs_acl_free(aclp); - aclp = NULL; - } if (fuidp) { zfs_fuid_info_free(fuidp); @@ -3290,7 +3356,7 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, if (VOP_REALVP(tdvp, &realvp, ct) == 0) tdvp = realvp; - if (tdvp->v_vfsp != sdvp->v_vfsp) { + if (tdvp->v_vfsp != sdvp->v_vfsp || zfsctl_is_node(tdvp)) { ZFS_EXIT(zfsvfs); return (EXDEV); } @@ -3808,6 +3874,7 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, vnode_t *realvp; int error; int zf = ZNEW; + uint64_t parent; uid_t owner; ASSERT(tdvp->v_type == VDIR); @@ -3819,13 +3886,30 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, if (VOP_REALVP(svp, &realvp, ct) == 0) svp = realvp; - if (svp->v_vfsp != tdvp->v_vfsp) { + /* + * POSIX dictates that we return EPERM here. + * Better choices include ENOTSUP or EISDIR. + */ + if (svp->v_type == VDIR) { + ZFS_EXIT(zfsvfs); + return (EPERM); + } + + if (svp->v_vfsp != tdvp->v_vfsp || zfsctl_is_node(svp)) { ZFS_EXIT(zfsvfs); return (EXDEV); } + szp = VTOZ(svp); ZFS_VERIFY_ZP(szp); + /* Prevent links to .zfs/shares files */ + + if (szp->z_phys->zp_parent == zfsvfs->z_shares_dir) { + ZFS_EXIT(zfsvfs); + return (EPERM); + } + if (zfsvfs->z_utf8 && u8_validate(name, strlen(name), NULL, U8_VALIDATE_ENTIRE, &error) < 0) { ZFS_EXIT(zfsvfs); @@ -3834,7 +3918,6 @@ zfs_link(vnode_t *tdvp, vnode_t *svp, char *name, cred_t *cr, if (flags & FIGNORECASE) zf |= ZCILOOK; -top: /* * We do not support links between attributes and non-attributes * because of the potential security risk of creating links @@ -3847,14 +3930,6 @@ top: return (EINVAL); } - /* - * POSIX dictates that we return EPERM here. - * Better choices include ENOTSUP or EISDIR. - */ - if (svp->v_type == VDIR) { - ZFS_EXIT(zfsvfs); - return (EPERM); - } owner = zfs_fuid_map_id(zfsvfs, szp->z_phys->zp_uid, cr, ZFS_OWNER); if (owner != crgetuid(cr) && @@ -3868,6 +3943,7 @@ top: return (error); } +top: /* * Attempt to lock directory; fail if entry already exists. */ @@ -4107,6 +4183,111 @@ zfs_setsecattr(vnode_t *vp, vsecattr_t *vsecp, int flag, cred_t *cr, return (error); } +static int +ioflags(int ioflags) +{ + int flags = 0; + + if (ioflags & IO_APPEND) + flags |= FAPPEND; + if (ioflags & IO_NDELAY) + flags |= FNONBLOCK; + if (ioflags & IO_SYNC) + flags |= (FSYNC | FDSYNC | FRSYNC); + + return (flags); +} + +static int +zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage) +{ + znode_t *zp = VTOZ(vp); + zfsvfs_t *zfsvfs = zp->z_zfsvfs; + objset_t *os = zp->z_zfsvfs->z_os; + vm_page_t mreq; + vm_object_t object; + caddr_t va; + struct sf_buf *sf; + int i, error; + int pcount, size; + + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(zp); + + pcount = round_page(count) / PAGE_SIZE; + mreq = m[reqpage]; + object = mreq->object; + error = 0; + + KASSERT(vp->v_object == object, ("mismatching object")); + + VM_OBJECT_LOCK(object); + + for (i = 0; i < pcount; i++) { + if (i != reqpage) { + vm_page_lock(m[i]); + vm_page_free(m[i]); + vm_page_unlock(m[i]); + } + } + + if (mreq->valid) { + if (mreq->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(mreq, TRUE); + VM_OBJECT_UNLOCK(object); + ZFS_EXIT(zfsvfs); + return (VM_PAGER_OK); + } + + PCPU_INC(cnt.v_vnodein); + PCPU_INC(cnt.v_vnodepgsin); + + if (IDX_TO_OFF(mreq->pindex) >= object->un_pager.vnp.vnp_size) { + VM_OBJECT_UNLOCK(object); + ZFS_EXIT(zfsvfs); + return (VM_PAGER_BAD); + } + + size = PAGE_SIZE; + if (IDX_TO_OFF(mreq->pindex) + size > object->un_pager.vnp.vnp_size) + size = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mreq->pindex); + + VM_OBJECT_UNLOCK(object); + + va = zfs_map_page(mreq, &sf); + error = dmu_read(os, zp->z_id, IDX_TO_OFF(mreq->pindex), + size, va, DMU_READ_PREFETCH); + if (size != PAGE_SIZE) + bzero(va + size, PAGE_SIZE - size); + zfs_unmap_page(sf); + + VM_OBJECT_LOCK(object); + + if (!error) + mreq->valid = VM_PAGE_BITS_ALL; + KASSERT(mreq->dirty == 0, ("zfs_getpages: page %p is dirty", mreq)); + + VM_OBJECT_UNLOCK(object); + + ZFS_ACCESSTIME_STAMP(zfsvfs, zp); + ZFS_EXIT(zfsvfs); + return (error ? VM_PAGER_ERROR : VM_PAGER_OK); +} + +static int +zfs_freebsd_getpages(ap) + struct vop_getpages_args /* { + struct vnode *a_vp; + vm_page_t *a_m; + int a_count; + int a_reqpage; + vm_ooffset_t a_offset; + } */ *ap; +{ + + return (zfs_getpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_reqpage)); +} + static int zfs_freebsd_open(ap) struct vop_open_args /* { @@ -4165,7 +4346,8 @@ zfs_freebsd_read(ap) } */ *ap; { - return (zfs_read(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred, NULL)); + return (zfs_read(ap->a_vp, ap->a_uio, ioflags(ap->a_ioflag), + ap->a_cred, NULL)); } static int @@ -4181,7 +4363,8 @@ zfs_freebsd_write(ap) if (vn_rlimit_fsize(ap->a_vp, ap->a_uio, ap->a_uio->uio_td)) return (EFBIG); - return (zfs_write(ap->a_vp, ap->a_uio, ap->a_ioflag, ap->a_cred, NULL)); + return (zfs_write(ap->a_vp, ap->a_uio, ioflags(ap->a_ioflag), + ap->a_cred, NULL)); } static int @@ -4193,6 +4376,9 @@ zfs_freebsd_access(ap) struct thread *a_td; } */ *ap; { + vnode_t *vp = ap->a_vp; + znode_t *zp = VTOZ(vp); + znode_phys_t *zphys = zp->z_phys; accmode_t accmode; int error = 0; @@ -4209,16 +4395,20 @@ zfs_freebsd_access(ap) if (error == 0) { accmode = ap->a_accmode & ~(VREAD|VWRITE|VEXEC|VAPPEND); if (accmode != 0) { - vnode_t *vp = ap->a_vp; - znode_t *zp = VTOZ(vp); - znode_phys_t *zphys = zp->z_phys; - error = vaccess(vp->v_type, zphys->zp_mode, zphys->zp_uid, zphys->zp_gid, accmode, ap->a_cred, NULL); } } + /* + * For VEXEC, ensure that at least one execute bit is set for + * non-directories. + */ + if (error == 0 && (ap->a_accmode & VEXEC) != 0 && vp->v_type != VDIR && + (zphys->zp_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) + error = EACCES; + return (error); } @@ -5214,6 +5404,7 @@ struct vop_vector zfs_vnodeops = { .vop_getacl = zfs_freebsd_getacl, .vop_setacl = zfs_freebsd_setacl, .vop_aclcheck = zfs_freebsd_aclcheck, + .vop_getpages = zfs_freebsd_getpages, }; struct vop_vector zfs_fifoops = { diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c index 7b50f242e1d..dbee467dbc2 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c @@ -177,6 +177,7 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags) zp->z_dbuf = NULL; zp->z_dirlocks = NULL; + zp->z_acl_cached = NULL; return (0); } @@ -199,6 +200,7 @@ zfs_znode_cache_destructor(void *buf, void *arg) ASSERT(zp->z_dbuf == NULL); ASSERT(zp->z_dirlocks == NULL); + ASSERT(zp->z_acl_cached == NULL); } #ifdef ZNODE_STATS @@ -244,6 +246,15 @@ zfs_znode_move_impl(znode_t *ozp, znode_t *nzp) nzp->z_phys = ozp->z_phys; nzp->z_dbuf = ozp->z_dbuf; + /* + * Since this is just an idle znode and kmem is already dealing with + * memory pressure, release any cached ACL. + */ + if (ozp->z_acl_cached) { + zfs_acl_free(ozp->z_acl_cached); + ozp->z_acl_cached = NULL; + } + /* Update back pointers. */ (void) dmu_buf_update_user(nzp->z_dbuf, ozp, nzp, &nzp->z_phys, znode_evict_error); @@ -497,6 +508,7 @@ zfs_znode_dmu_init(zfsvfs_t *zfsvfs, znode_t *zp, dmu_buf_t *db) mutex_enter(&zp->z_lock); ASSERT(zp->z_dbuf == NULL); + ASSERT(zp->z_acl_cached == NULL); zp->z_dbuf = db; nzp = dmu_buf_set_user_ie(db, zp, &zp->z_phys, znode_evict_error); @@ -980,6 +992,13 @@ zfs_rezget(znode_t *zp) return (EIO); } + mutex_enter(&zp->z_acl_lock); + if (zp->z_acl_cached) { + zfs_acl_free(zp->z_acl_cached); + zp->z_acl_cached = NULL; + } + mutex_exit(&zp->z_acl_lock); + zfs_znode_dmu_init(zfsvfs, zp, db); zp->z_unlinked = (zp->z_phys->zp_links == 0); zp->z_blksz = doi.doi_data_block_size; @@ -1065,6 +1084,11 @@ zfs_znode_free(znode_t *zp) list_remove(&zfsvfs->z_all_znodes, zp); mutex_exit(&zfsvfs->z_znodes_lock); + if (zp->z_acl_cached) { + zfs_acl_free(zp->z_acl_cached); + zp->z_acl_cached = NULL; + } + kmem_cache_free(znode_cache, zp); VFS_RELE(zfsvfs->z_vfs); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c index 78397132027..1dd8ea0980a 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -515,6 +516,13 @@ zil_claim(char *osname, void *txarg) zilog = dmu_objset_zil(os); zh = zil_header_in_syncing_context(zilog); + if (zilog->zl_spa->spa_log_state == SPA_LOG_CLEAR) { + if (!BP_IS_HOLE(&zh->zh_log)) + zio_free_blk(zilog->zl_spa, &zh->zh_log, first_txg); + BP_ZERO(&zh->zh_log); + dsl_dataset_dirty(dmu_objset_ds(os), tx); + } + /* * Record here whether the zil has any records to replay. * If the header block pointer is null or the block points @@ -527,8 +535,10 @@ zil_claim(char *osname, void *txarg) * Note, the intent log can be empty but still need the * stubby to be claimed. */ - if (!zil_empty(zilog)) + if (!zil_empty(zilog)) { zh->zh_flags |= ZIL_REPLAY_NEEDED; + dsl_dataset_dirty(dmu_objset_ds(os), tx); + } /* * Claim all log blocks if we haven't already done so, and remember @@ -597,36 +607,6 @@ zil_check_log_chain(char *osname, void *txarg) return (error); } -/* - * Clear a log chain - */ -/* ARGSUSED */ -int -zil_clear_log_chain(char *osname, void *txarg) -{ - zilog_t *zilog; - zil_header_t *zh; - objset_t *os; - dmu_tx_t *tx; - int error; - - error = dmu_objset_open(osname, DMU_OST_ANY, DS_MODE_USER, &os); - if (error) { - cmn_err(CE_WARN, "can't open objset for %s", osname); - return (0); - } - - zilog = dmu_objset_zil(os); - tx = dmu_tx_create(zilog->zl_os); - (void) dmu_tx_assign(tx, TXG_WAIT); - zh = zil_header_in_syncing_context(zilog); - BP_ZERO(&zh->zh_log); - dsl_dataset_dirty(dmu_objset_ds(os), tx); - dmu_tx_commit(tx); - dmu_objset_close(os); - return (0); -} - static int zil_vdev_compare(const void *x1, const void *x2) { @@ -771,9 +751,9 @@ zil_lwb_write_init(zilog_t *zilog, lwb_t *lwb) } if (lwb->lwb_zio == NULL) { lwb->lwb_zio = zio_rewrite(zilog->zl_root_zio, zilog->zl_spa, - 0, &lwb->lwb_blk, lwb->lwb_buf, - lwb->lwb_sz, zil_lwb_write_done, lwb, - ZIO_PRIORITY_LOG_WRITE, ZIO_FLAG_CANFAIL, &zb); + 0, &lwb->lwb_blk, lwb->lwb_buf, lwb->lwb_sz, + zil_lwb_write_done, lwb, ZIO_PRIORITY_LOG_WRITE, + ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE, &zb); } } @@ -1270,12 +1250,7 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx) } } - for (;;) { - lwb = list_head(&zilog->zl_lwb_list); - if (lwb == NULL) { - mutex_exit(&zilog->zl_lock); - return; - } + while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) { zh->zh_log = lwb->lwb_blk; if (lwb->lwb_buf != NULL || lwb->lwb_max_txg > txg) break; @@ -1692,3 +1667,24 @@ out: mutex_exit(&zilog->zl_lock); return (ret); } + +/* ARGSUSED */ +int +zil_vdev_offline(char *osname, void *arg) +{ + objset_t *os; + zilog_t *zilog; + int error; + + error = dmu_objset_open(osname, DMU_OST_ANY, DS_MODE_USER, &os); + if (error) + return (error); + + zilog = dmu_objset_zil(os); + if (zil_suspend(zilog) != 0) + error = EEXIST; + else + zil_resume(zilog); + dmu_objset_close(os); + return (error); +} diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c index 75b76171156..b4775636aa2 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio.c @@ -49,11 +49,12 @@ uint8_t zio_priority_table[ZIO_PRIORITY_TABLE_SIZE] = { 0, /* ZIO_PRIORITY_NOW */ 0, /* ZIO_PRIORITY_SYNC_READ */ 0, /* ZIO_PRIORITY_SYNC_WRITE */ - 6, /* ZIO_PRIORITY_ASYNC_READ */ - 4, /* ZIO_PRIORITY_ASYNC_WRITE */ - 4, /* ZIO_PRIORITY_FREE */ - 0, /* ZIO_PRIORITY_CACHE_FILL */ 0, /* ZIO_PRIORITY_LOG_WRITE */ + 1, /* ZIO_PRIORITY_CACHE_FILL */ + 1, /* ZIO_PRIORITY_AGG */ + 4, /* ZIO_PRIORITY_FREE */ + 4, /* ZIO_PRIORITY_ASYNC_WRITE */ + 6, /* ZIO_PRIORITY_ASYNC_READ */ 10, /* ZIO_PRIORITY_RESILVER */ 20, /* ZIO_PRIORITY_SCRUB */ }; @@ -64,7 +65,9 @@ uint8_t zio_priority_table[ZIO_PRIORITY_TABLE_SIZE] = { * ========================================================================== */ char *zio_type_name[ZIO_TYPES] = { - "null", "read", "write", "free", "claim", "ioctl" }; + "zio_null", "zio_read", "zio_write", "zio_free", "zio_claim", + "zio_ioctl" +}; #define SYNC_PASS_DEFERRED_FREE 1 /* defer frees after this pass */ #define SYNC_PASS_DONT_COMPRESS 4 /* don't compress after this pass */ @@ -942,6 +945,7 @@ zio_write_bp_init(zio_t *zio) static void zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q) { + spa_t *spa = zio->io_spa; zio_type_t t = zio->io_type; /* @@ -958,7 +962,15 @@ zio_taskq_dispatch(zio_t *zio, enum zio_taskq_type q) if (t == ZIO_TYPE_WRITE && zio->io_vd && zio->io_vd->vdev_aux) t = ZIO_TYPE_NULL; - (void) taskq_dispatch_safe(zio->io_spa->spa_zio_taskq[t][q], + /* + * If this is a high priority I/O, then use the high priority taskq. + */ + if (zio->io_priority == ZIO_PRIORITY_NOW && + spa->spa_zio_taskq[t][q + 1] != NULL) + q++; + + ASSERT3U(q, <, ZIO_TASKQ_TYPES); + (void) taskq_dispatch_safe(spa->spa_zio_taskq[t][q], (task_func_t *)zio_execute, zio, &zio->io_task); } @@ -1858,7 +1870,8 @@ zio_vdev_io_done(zio_t *zio) vdev_cache_write(zio); if (zio_injection_enabled && zio->io_error == 0) - zio->io_error = zio_handle_device_injection(vd, EIO); + zio->io_error = zio_handle_device_injection(vd, + zio, EIO); if (zio_injection_enabled && zio->io_error == 0) zio->io_error = zio_handle_label_injection(zio, EIO); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_inject.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_inject.c index b3469fdd5c2..f8e6880c90f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_inject.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zio_inject.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -195,7 +195,7 @@ zio_handle_label_injection(zio_t *zio, int error) int -zio_handle_device_injection(vdev_t *vd, int error) +zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error) { inject_handler_t *handler; int ret = 0; @@ -210,6 +210,12 @@ zio_handle_device_injection(vdev_t *vd, int error) continue; if (vd->vdev_guid == handler->zi_record.zi_guid) { + if (handler->zi_record.zi_failfast && + (zio == NULL || (zio->io_flags & + (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)))) { + continue; + } + if (handler->zi_record.zi_error == error) { /* * For a failed open, pretend like the device diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h index 82b97a37368..3bd8803615c 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h @@ -1322,15 +1322,24 @@ typedef struct { * helpers and should no longer be used. No other ioctls are valid on the * helper minor node. */ +#if defined(sun) #define DTRACEHIOC (('d' << 24) | ('t' << 16) | ('h' << 8)) #define DTRACEHIOC_ADD (DTRACEHIOC | 1) /* add helper */ #define DTRACEHIOC_REMOVE (DTRACEHIOC | 2) /* remove helper */ #define DTRACEHIOC_ADDDOF (DTRACEHIOC | 3) /* add helper DOF */ +#else +#define DTRACEHIOC_ADD _IOWR('z', 1, dof_hdr_t)/* add helper */ +#define DTRACEHIOC_REMOVE _IOW('z', 2, int) /* remove helper */ +#define DTRACEHIOC_ADDDOF _IOWR('z', 3, dof_helper_t)/* add helper DOF */ +#endif typedef struct dof_helper { char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */ uint64_t dofhp_addr; /* base address of object */ uint64_t dofhp_dof; /* address of helper DOF */ +#if !defined(sun) + int gen; +#endif } dof_helper_t; #define DTRACEMNR_DTRACE "dtrace" /* node for DTrace ops */ @@ -2219,10 +2228,11 @@ extern void dtrace_vtime_enable(void); extern void dtrace_vtime_disable(void); struct regs; +struct reg; #if defined(sun) -extern int (*dtrace_pid_probe_ptr)(struct regs *); -extern int (*dtrace_return_probe_ptr)(struct regs *); +extern int (*dtrace_pid_probe_ptr)(struct reg *); +extern int (*dtrace_return_probe_ptr)(struct reg *); extern void (*dtrace_fasttrap_fork_ptr)(proc_t *, proc_t *); extern void (*dtrace_fasttrap_exec_ptr)(proc_t *); extern void (*dtrace_fasttrap_exit_ptr)(proc_t *); @@ -2279,6 +2289,11 @@ extern int dtrace_blksuword32(uintptr_t, uint32_t *, int); extern void dtrace_getfsr(uint64_t *); #endif +#if !defined(sun) +extern void dtrace_helpers_duplicate(proc_t *, proc_t *); +extern void dtrace_helpers_destroy(proc_t *); +#endif + #define DTRACE_CPUFLAG_ISSET(flag) \ (cpu_core[curcpu].cpuc_dtrace_flags & (flag)) diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h index 369d41a35ed..6870a0b2b2e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace_impl.h @@ -1268,7 +1268,7 @@ extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, volatile uint16_t *); extern void dtrace_copyoutstr(uintptr_t, uintptr_t, size_t, volatile uint16_t *); extern void dtrace_getpcstack(pc_t *, int, int, uint32_t *); -extern ulong_t dtrace_getreg(struct regs *, uint_t); +extern ulong_t dtrace_getreg(struct trapframe *, uint_t); extern int dtrace_getstackdepth(int); extern void dtrace_getupcstack(uint64_t *, int); extern void dtrace_getufpstack(uint64_t *, uint64_t *, int); diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap.h b/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap.h index 7f803144bcf..58967fd6c12 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap.h @@ -37,9 +37,14 @@ extern "C" { #endif +#if defined(sun) #define FASTTRAPIOC (('m' << 24) | ('r' << 16) | ('f' << 8)) #define FASTTRAPIOC_MAKEPROBE (FASTTRAPIOC | 1) #define FASTTRAPIOC_GETINSTR (FASTTRAPIOC | 2) +#else +#define FASTTRAPIOC_MAKEPROBE _IOW('f', 1, fasttrap_probe_spec_t) +#define FASTTRAPIOC_GETINSTR _IOWR('f', 2, uint8_t) +#endif typedef enum fasttrap_probe_type { DTFTP_NONE = 0, diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap_impl.h b/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap_impl.h index 232b5f63330..a4e51fd04d6 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap_impl.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fasttrap_impl.h @@ -158,10 +158,16 @@ typedef struct fasttrap_hash { */ #define fasttrap_copyout copyout #define fasttrap_fuword32 fuword32 -#define fasttrap_suword32 suword32 +#define fasttrap_suword32(_k, _u) copyout((_k), (_u), sizeof(uint32_t)) +#define fasttrap_suword64(_k, _u) copyout((_k), (_u), sizeof(uint64_t)) -#define fasttrap_fulword fulword -#define fasttrap_sulword sulword +#ifdef __amd64__ +#define fasttrap_fulword fuword64 +#define fasttrap_sulword fasttrap_suword64 +#else +#define fasttrap_fulword fuword32 +#define fasttrap_sulword fasttrap_suword32 +#endif extern void fasttrap_sigtrap(proc_t *, kthread_t *, uintptr_t); @@ -179,8 +185,9 @@ extern int fasttrap_tracepoint_init(proc_t *, fasttrap_tracepoint_t *, extern int fasttrap_tracepoint_install(proc_t *, fasttrap_tracepoint_t *); extern int fasttrap_tracepoint_remove(proc_t *, fasttrap_tracepoint_t *); -extern int fasttrap_pid_probe(struct regs *); -extern int fasttrap_return_probe(struct regs *); +struct reg; +extern int fasttrap_pid_probe(struct reg *); +extern int fasttrap_return_probe(struct reg *); extern uint64_t fasttrap_pid_getarg(void *, dtrace_id_t, void *, int, int); extern uint64_t fasttrap_usdt_getarg(void *, dtrace_id_t, void *, int, int); diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/isa_defs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/isa_defs.h index 137cd971dbb..19faf42f731 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/isa_defs.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/isa_defs.h @@ -403,6 +403,25 @@ extern "C" { #define _INT_ALIGNMENT 4 #define _FLOAT_ALIGNMENT 4 #define _FLOAT_COMPLEX_ALIGNMENT 4 +#if defined(__mips_n64) +#define _LONG_ALIGNMENT 8 +#define _LONG_LONG_ALIGNMENT 8 +#define _DOUBLE_ALIGNMENT 8 +#define _DOUBLE_COMPLEX_ALIGNMENT 8 +#define _LONG_DOUBLE_ALIGNMENT 8 +#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 8 +#define _POINTER_ALIGNMENT 8 +#define _MAX_ALIGNMENT 8 +#define _ALIGNMENT_REQUIRED 0 + +#define _LONG_LONG_ALIGNMENT_32 _INT_ALIGNMENT +/* + * Define the appropriate "implementation choices". + */ +#if !defined(_LP64) +#define _LP64 +#endif +#else #define _LONG_ALIGNMENT 4 #define _LONG_LONG_ALIGNMENT 4 #define _DOUBLE_ALIGNMENT 4 @@ -422,6 +441,7 @@ extern "C" { #if !defined(_I32LPx) && defined(_KERNEL) #define _I32LPx #endif +#endif #define _SUNOS_VTOC_16 #define _DMA_USES_PHYSADDR #define _FIRMWARE_NEEDS_FDISK diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h b/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h index 5a7c9e628e3..ab95b99b9ce 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/vnode.h @@ -378,6 +378,7 @@ struct taskq; * Flags for VOP_READDIR */ #define V_RDDIR_ENTFLAGS 0x01 /* request dirent flags */ +#define V_RDDIR_ACCFILTER 0x02 /* filter out inaccessible dirents */ /* * Public vnode manipulation functions. diff --git a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c index 1b93869a735..85d9649f674 100644 --- a/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c +++ b/sys/cddl/contrib/opensolaris/uts/intel/dtrace/fasttrap_isa.c @@ -17,6 +17,10 @@ * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END + * + * Portions Copyright 2010 The FreeBSD Foundation + * + * $FreeBSD$ */ /* @@ -24,20 +28,83 @@ * Use is subject to license terms. */ +#if defined(sun) #pragma ident "%Z%%M% %I% %E% SMI" +#endif #include #include #include #include #include +#if defined(sun) #include #include #include #include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif #include +#if defined(sun) #include #include +#else +#include + +static int +proc_ops(int op, proc_t *p, void *kaddr, off_t uaddr, size_t len) +{ + struct iovec iov; + struct uio uio; + + iov.iov_base = kaddr; + iov.iov_len = len; + uio.uio_offset = uaddr; + uio.uio_iov = &iov; + uio.uio_resid = len; + uio.uio_iovcnt = 1; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_td = curthread; + uio.uio_rw = op; + PHOLD(p); + if (proc_rwmem(p, &uio) < 0) { + PRELE(p); + return (-1); + } + PRELE(p); + + return (0); +} + +static int +uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) +{ + + return (proc_ops(UIO_READ, p, kaddr, uaddr, len)); +} + +static int +uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) +{ + + return (proc_ops(UIO_WRITE, p, kaddr, uaddr, len)); +} +#endif +#ifdef __i386__ +#define r_rax r_eax +#define r_rbx r_ebx +#define r_rip r_eip +#define r_rflags r_eflags +#define r_rsp r_esp +#endif /* * Lossless User-Land Tracing on x86 @@ -188,12 +255,12 @@ static const uint8_t regmap[8] = { }; #endif -static ulong_t fasttrap_getreg(struct regs *, uint_t); +static ulong_t fasttrap_getreg(struct reg *, uint_t); static uint64_t -fasttrap_anarg(struct regs *rp, int function_entry, int argno) +fasttrap_anarg(struct reg *rp, int function_entry, int argno) { - uint64_t value; + uint64_t value = 0; int shift = function_entry ? 1 : 0; #ifdef __amd64 @@ -207,16 +274,18 @@ fasttrap_anarg(struct regs *rp, int function_entry, int argno) if (argno < 6) return ((&rp->r_rdi)[argno]); - stack = (uintptr_t *)rp->r_sp; + stack = (uintptr_t *)rp->r_rsp; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); value = dtrace_fulword(&stack[argno - 6 + shift]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); } else { #endif - uint32_t *stack = (uint32_t *)rp->r_sp; +#ifdef __i386 + uint32_t *stack = (uint32_t *)rp->r_esp; DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); value = dtrace_fuword32(&stack[argno + shift]); DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); +#endif #ifdef __amd64 } #endif @@ -637,35 +706,41 @@ fasttrap_fulword_noerr(const void *uaddr) { uintptr_t ret; - if (fasttrap_fulword(uaddr, &ret) == 0) + if ((ret = fasttrap_fulword(uaddr)) != -1) return (ret); return (0); } #endif +#ifdef __i386__ static uint32_t fasttrap_fuword32_noerr(const void *uaddr) { uint32_t ret; - if (fasttrap_fuword32(uaddr, &ret) == 0) + if ((ret = fasttrap_fuword32(uaddr)) != -1) return (ret); return (0); } +#endif static void -fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, +fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid, uintptr_t new_pc) { fasttrap_tracepoint_t *tp; fasttrap_bucket_t *bucket; fasttrap_id_t *id; +#if defined(sun) kmutex_t *pid_mtx; +#endif +#if defined(sun) pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); +#endif bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { @@ -680,7 +755,9 @@ fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, * is not essential to the correct execution of the process. */ if (tp == NULL) { +#if defined(sun) mutex_exit(pid_mtx); +#endif return; } @@ -698,15 +775,18 @@ fasttrap_return_common(struct regs *rp, uintptr_t pc, pid_t pid, dtrace_probe(id->fti_probe->ftp_id, pc - id->fti_probe->ftp_faddr, - rp->r_r0, rp->r_r1, 0, 0); + rp->r_rax, rp->r_rbx, 0, 0); } +#if defined(sun) mutex_exit(pid_mtx); +#endif } static void fasttrap_sigsegv(proc_t *p, kthread_t *t, uintptr_t addr) { +#if defined(sun) sigqueue_t *sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP); sqp->sq_info.si_signo = SIGSEGV; @@ -719,15 +799,24 @@ fasttrap_sigsegv(proc_t *p, kthread_t *t, uintptr_t addr) if (t != NULL) aston(t); +#else + ksiginfo_t *ksi = kmem_zalloc(sizeof (ksiginfo_t), KM_SLEEP); + + ksiginfo_init(ksi); + ksi->ksi_signo = SIGSEGV; + ksi->ksi_code = SEGV_MAPERR; + ksi->ksi_addr = (caddr_t)addr; + (void) tdksignal(t, SIGSEGV, ksi); +#endif } #ifdef __amd64 static void -fasttrap_usdt_args64(fasttrap_probe_t *probe, struct regs *rp, int argc, +fasttrap_usdt_args64(fasttrap_probe_t *probe, struct reg *rp, int argc, uintptr_t *argv) { int i, x, cap = MIN(argc, probe->ftp_nargs); - uintptr_t *stack = (uintptr_t *)rp->r_sp; + uintptr_t *stack = (uintptr_t *)rp->r_rsp; for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; @@ -744,12 +833,13 @@ fasttrap_usdt_args64(fasttrap_probe_t *probe, struct regs *rp, int argc, } #endif +#ifdef __i386__ static void -fasttrap_usdt_args32(fasttrap_probe_t *probe, struct regs *rp, int argc, +fasttrap_usdt_args32(fasttrap_probe_t *probe, struct reg *rp, int argc, uint32_t *argv) { int i, x, cap = MIN(argc, probe->ftp_nargs); - uint32_t *stack = (uint32_t *)rp->r_sp; + uint32_t *stack = (uint32_t *)rp->r_rsp; for (i = 0; i < cap; i++) { x = probe->ftp_argmap[i]; @@ -761,13 +851,18 @@ fasttrap_usdt_args32(fasttrap_probe_t *probe, struct regs *rp, int argc, argv[i] = 0; } } +#endif static int -fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) +fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct reg *rp, uintptr_t *addr) { proc_t *p = curproc; - user_desc_t *desc; - uint16_t sel, ndx, type; +#ifdef __i386__ + struct segment_descriptor *desc; +#else + struct user_segment_descriptor *desc; +#endif + uint16_t sel = 0, ndx, type; uintptr_t limit; switch (tp->ftt_segment) { @@ -795,36 +890,49 @@ fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) * Make sure the given segment register specifies a user priority * selector rather than a kernel selector. */ - if (!SELISUPL(sel)) + if (ISPL(sel) != SEL_UPL) return (-1); - ndx = SELTOIDX(sel); + ndx = IDXSEL(sel); /* * Check the bounds and grab the descriptor out of the specified * descriptor table. */ - if (SELISLDT(sel)) { - if (ndx > p->p_ldtlimit) + if (ISLDT(sel)) { +#ifdef __i386__ + if (ndx > p->p_md.md_ldt->ldt_len) return (-1); - desc = p->p_ldt + ndx; + desc = (struct segment_descriptor *) + p->p_md.md_ldt[ndx].ldt_base; +#else + if (ndx > max_ldt_segment) + return (-1); + + desc = (struct user_segment_descriptor *) + p->p_md.md_ldt[ndx].ldt_base; +#endif } else { if (ndx >= NGDT) return (-1); - desc = cpu_get_gdt() + ndx; +#ifdef __i386__ + desc = &gdt[ndx].sd; +#else + desc = &gdt[ndx]; +#endif } /* * The descriptor must have user privilege level and it must be * present in memory. */ - if (desc->usd_dpl != SEL_UPL || desc->usd_p != 1) + if (desc->sd_dpl != SEL_UPL || desc->sd_p != 1) return (-1); - type = desc->usd_type; + type = desc->sd_type; /* * If the S bit in the type field is not set, this descriptor can @@ -833,7 +941,7 @@ fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) if ((type & 0x10) != 0x10) return (-1); - limit = USEGD_GETLIMIT(desc) * (desc->usd_gran ? PAGESIZE : 1); + limit = USD_GETLIMIT(desc) * (desc->sd_gran ? PAGESIZE : 1); if (tp->ftt_segment == FASTTRAP_SEG_CS) { /* @@ -861,7 +969,7 @@ fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) if ((type & 0x4) == 0) { if (*addr > limit) return (-1); - } else if (desc->usd_def32) { + } else if (desc->sd_def32) { if (*addr < limit + 1 || 0xffff < *addr) return (-1); } else { @@ -870,18 +978,21 @@ fasttrap_do_seg(fasttrap_tracepoint_t *tp, struct regs *rp, uintptr_t *addr) } } - *addr += USEGD_GETBASE(desc); + *addr += USD_GETBASE(desc); return (0); } int -fasttrap_pid_probe(struct regs *rp) +fasttrap_pid_probe(struct reg *rp) { proc_t *p = curproc; - uintptr_t pc = rp->r_pc - 1, new_pc = 0; + uintptr_t pc = rp->r_rip - 1; + uintptr_t new_pc = 0; fasttrap_bucket_t *bucket; +#if defined(sun) kmutex_t *pid_mtx; +#endif fasttrap_tracepoint_t *tp, tp_local; pid_t pid; dtrace_icookie_t cookie; @@ -911,6 +1022,7 @@ fasttrap_pid_probe(struct regs *rp) curthread->t_dtrace_regv = 0; #endif +#if defined(sun) /* * Treat a child created by a call to vfork(2) as if it were its * parent. We know that there's only one thread of control in such a @@ -919,10 +1031,14 @@ fasttrap_pid_probe(struct regs *rp) while (p->p_flag & SVFORK) { p = p->p_parent; } +#endif + PROC_LOCK(p); pid = p->p_pid; +#if defined(sun) pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock; mutex_enter(pid_mtx); +#endif bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; /* @@ -940,7 +1056,10 @@ fasttrap_pid_probe(struct regs *rp) * fasttrap_ioctl), or somehow we have mislaid this tracepoint. */ if (tp == NULL) { +#if defined(sun) mutex_exit(pid_mtx); +#endif + PROC_UNLOCK(p); return (-1); } @@ -948,7 +1067,7 @@ fasttrap_pid_probe(struct regs *rp) * Set the program counter to the address of the traced instruction * so that it looks right in ustack() output. */ - rp->r_pc = pc; + rp->r_rip = pc; if (tp->ftt_ids != NULL) { fasttrap_id_t *id; @@ -995,9 +1114,9 @@ fasttrap_pid_probe(struct regs *rp) } } } else { -#endif +#else /* __amd64 */ uintptr_t s0, s1, s2, s3, s4, s5; - uint32_t *stack = (uint32_t *)rp->r_sp; + uint32_t *stack = (uint32_t *)rp->r_esp; /* * In 32-bit mode, all arguments are passed on the @@ -1050,6 +1169,7 @@ fasttrap_pid_probe(struct regs *rp) t[2], t[3], t[4]); } } +#endif /* __amd64 */ #ifdef __amd64 } #endif @@ -1061,7 +1181,10 @@ fasttrap_pid_probe(struct regs *rp) * tracepoint again later if we need to light up any return probes. */ tp_local = *tp; + PROC_UNLOCK(p); +#if defined(sun) mutex_exit(pid_mtx); +#endif tp = &tp_local; /* @@ -1069,7 +1192,7 @@ fasttrap_pid_probe(struct regs *rp) * had completely executed. This ensures that fasttrap_getreg() will * report the expected value for REG_RIP. */ - rp->r_pc = pc + tp->ftt_size; + rp->r_rip = pc + tp->ftt_size; /* * If there's an is-enabled probe connected to this tracepoint it @@ -1083,8 +1206,8 @@ fasttrap_pid_probe(struct regs *rp) * exotic way to shoot oneself in the foot. */ if (is_enabled) { - rp->r_r0 = 1; - new_pc = rp->r_pc; + rp->r_rax = 1; + new_pc = rp->r_rip; goto done; } @@ -1098,9 +1221,9 @@ fasttrap_pid_probe(struct regs *rp) case FASTTRAP_T_RET: case FASTTRAP_T_RET16: { - uintptr_t dst; - uintptr_t addr; - int ret; + uintptr_t dst = 0; + uintptr_t addr = 0; + int ret = 0; /* * We have to emulate _every_ facet of the behavior of a ret @@ -1109,20 +1232,22 @@ fasttrap_pid_probe(struct regs *rp) */ #ifdef __amd64 if (p->p_model == DATAMODEL_NATIVE) { -#endif - ret = fasttrap_fulword((void *)rp->r_sp, &dst); - addr = rp->r_sp + sizeof (uintptr_t); -#ifdef __amd64 + ret = dst = fasttrap_fulword((void *)rp->r_rsp); + addr = rp->r_rsp + sizeof (uintptr_t); } else { +#endif +#ifdef __i386__ uint32_t dst32; - ret = fasttrap_fuword32((void *)rp->r_sp, &dst32); + ret = dst32 = fasttrap_fuword32((void *)rp->r_esp); dst = dst32; - addr = rp->r_sp + sizeof (uint32_t); + addr = rp->r_esp + sizeof (uint32_t); +#endif +#ifdef __amd64 } #endif if (ret == -1) { - fasttrap_sigsegv(p, curthread, rp->r_sp); + fasttrap_sigsegv(p, curthread, rp->r_rsp); new_pc = pc; break; } @@ -1130,71 +1255,71 @@ fasttrap_pid_probe(struct regs *rp) if (tp->ftt_type == FASTTRAP_T_RET16) addr += tp->ftt_dest; - rp->r_sp = addr; + rp->r_rsp = addr; new_pc = dst; break; } case FASTTRAP_T_JCC: { - uint_t taken; + uint_t taken = 0; switch (tp->ftt_code) { case FASTTRAP_JO: - taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_OF) != 0; break; case FASTTRAP_JNO: - taken = (rp->r_ps & FASTTRAP_EFLAGS_OF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0; break; case FASTTRAP_JB: - taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) != 0; break; case FASTTRAP_JAE: - taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) == 0; break; case FASTTRAP_JE: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0; break; case FASTTRAP_JNE: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0; break; case FASTTRAP_JBE: - taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) != 0 || - (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) != 0 || + (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0; break; case FASTTRAP_JA: - taken = (rp->r_ps & FASTTRAP_EFLAGS_CF) == 0 && - (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_CF) == 0 && + (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0; break; case FASTTRAP_JS: - taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_SF) != 0; break; case FASTTRAP_JNS: - taken = (rp->r_ps & FASTTRAP_EFLAGS_SF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0; break; case FASTTRAP_JP: - taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) != 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_PF) != 0; break; case FASTTRAP_JNP: - taken = (rp->r_ps & FASTTRAP_EFLAGS_PF) == 0; + taken = (rp->r_rflags & FASTTRAP_EFLAGS_PF) == 0; break; case FASTTRAP_JL: - taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != - ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); + taken = ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) != + ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JGE: - taken = ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == - ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); + taken = ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) == + ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JLE: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0 || - ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) != - ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0 || + ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) != + ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0); break; case FASTTRAP_JG: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0 && - ((rp->r_ps & FASTTRAP_EFLAGS_SF) == 0) == - ((rp->r_ps & FASTTRAP_EFLAGS_OF) == 0); + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0 && + ((rp->r_rflags & FASTTRAP_EFLAGS_SF) == 0) == + ((rp->r_rflags & FASTTRAP_EFLAGS_OF) == 0); break; } @@ -1208,7 +1333,7 @@ fasttrap_pid_probe(struct regs *rp) case FASTTRAP_T_LOOP: { - uint_t taken; + uint_t taken = 0; #ifdef __amd64 greg_t cx = rp->r_rcx--; #else @@ -1217,11 +1342,11 @@ fasttrap_pid_probe(struct regs *rp) switch (tp->ftt_code) { case FASTTRAP_LOOPNZ: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) == 0 && + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) == 0 && cx != 0; break; case FASTTRAP_LOOPZ: - taken = (rp->r_ps & FASTTRAP_EFLAGS_ZF) != 0 && + taken = (rp->r_rflags & FASTTRAP_EFLAGS_ZF) != 0 && cx != 0; break; case FASTTRAP_LOOP: @@ -1253,18 +1378,19 @@ fasttrap_pid_probe(struct regs *rp) case FASTTRAP_T_PUSHL_EBP: { - int ret; - uintptr_t addr; + int ret = 0; + uintptr_t addr = 0; #ifdef __amd64 if (p->p_model == DATAMODEL_NATIVE) { -#endif - addr = rp->r_sp - sizeof (uintptr_t); - ret = fasttrap_sulword((void *)addr, rp->r_fp); -#ifdef __amd64 + addr = rp->r_rsp - sizeof (uintptr_t); + ret = fasttrap_sulword((void *)addr, &rp->r_rsp); } else { - addr = rp->r_sp - sizeof (uint32_t); - ret = fasttrap_suword32((void *)addr, - (uint32_t)rp->r_fp); +#endif +#ifdef __i386__ + addr = rp->r_rsp - sizeof (uint32_t); + ret = fasttrap_suword32((void *)addr, &rp->r_rsp); +#endif +#ifdef __amd64 } #endif @@ -1274,7 +1400,7 @@ fasttrap_pid_probe(struct regs *rp) break; } - rp->r_sp = addr; + rp->r_rsp = addr; new_pc = pc + tp->ftt_size; break; } @@ -1288,7 +1414,10 @@ fasttrap_pid_probe(struct regs *rp) if (tp->ftt_code == 0) { new_pc = tp->ftt_dest; } else { - uintptr_t value, addr = tp->ftt_dest; +#ifdef __amd64 + uintptr_t value; +#endif + uintptr_t addr = tp->ftt_dest; if (tp->ftt_base != FASTTRAP_NOREG) addr += fasttrap_getreg(rp, tp->ftt_base); @@ -1312,32 +1441,34 @@ fasttrap_pid_probe(struct regs *rp) #ifdef __amd64 if (p->p_model == DATAMODEL_NATIVE) { -#endif - if (fasttrap_fulword((void *)addr, - &value) == -1) { + if ((value = fasttrap_fulword((void *)addr)) + == -1) { fasttrap_sigsegv(p, curthread, addr); new_pc = pc; break; } new_pc = value; -#ifdef __amd64 } else { +#endif +#ifdef __i386__ uint32_t value32; addr = (uintptr_t)(uint32_t)addr; - if (fasttrap_fuword32((void *)addr, - &value32) == -1) { + if ((value32 = fasttrap_fuword32((void *)addr)) + == -1) { fasttrap_sigsegv(p, curthread, addr); new_pc = pc; break; } new_pc = value32; - } #endif + } +#ifdef __amd64 } else { new_pc = addr; } +#endif } /* @@ -1347,18 +1478,20 @@ fasttrap_pid_probe(struct regs *rp) * this instruction weren't traced. */ if (tp->ftt_type == FASTTRAP_T_CALL) { - int ret; - uintptr_t addr; + int ret = 0; + uintptr_t addr = 0, pcps; #ifdef __amd64 if (p->p_model == DATAMODEL_NATIVE) { - addr = rp->r_sp - sizeof (uintptr_t); - ret = fasttrap_sulword((void *)addr, - pc + tp->ftt_size); + addr = rp->r_rsp - sizeof (uintptr_t); + pcps = pc + tp->ftt_size; + ret = fasttrap_sulword((void *)addr, &pcps); } else { #endif - addr = rp->r_sp - sizeof (uint32_t); - ret = fasttrap_suword32((void *)addr, - (uint32_t)(pc + tp->ftt_size)); +#ifdef __i386__ + addr = rp->r_rsp - sizeof (uint32_t); + pcps = (uint32_t)(pc + tp->ftt_size); + ret = fasttrap_suword32((void *)addr, &pcps); +#endif #ifdef __amd64 } #endif @@ -1369,7 +1502,7 @@ fasttrap_pid_probe(struct regs *rp) break; } - rp->r_sp = addr; + rp->r_rsp = addr; } break; @@ -1383,7 +1516,9 @@ fasttrap_pid_probe(struct regs *rp) uint8_t scratch[2 * FASTTRAP_MAX_INSTR_SIZE + 7]; #endif uint_t i = 0; +#if defined(sun) klwp_t *lwp = ttolwp(curthread); +#endif /* * Compute the address of the ulwp_t and step over the @@ -1391,6 +1526,7 @@ fasttrap_pid_probe(struct regs *rp) * thread pointer is very different on 32- and 64-bit * kernels. */ +#if defined(sun) #if defined(__amd64) if (p->p_model == DATAMODEL_LP64) { addr = lwp->lwp_pcb.pcb_fsbase; @@ -1400,9 +1536,16 @@ fasttrap_pid_probe(struct regs *rp) addr += sizeof (caddr32_t); } #else - addr = USEGD_GETBASE(&lwp->lwp_pcb.pcb_gsdesc); + addr = USD_GETBASE(&lwp->lwp_pcb.pcb_gsdesc); addr += sizeof (void *); #endif +#endif /* sun */ +#ifdef __i386__ + addr = USD_GETBASE(&curthread->td_pcb->pcb_gsd); +#else + addr = curthread->td_pcb->pcb_gsbase; +#endif + addr += sizeof (void *); /* * Generic Instruction Tracing @@ -1495,7 +1638,7 @@ fasttrap_pid_probe(struct regs *rp) #ifdef __amd64 if (tp->ftt_ripmode != 0) { - greg_t *reg; + greg_t *reg = NULL; ASSERT(p->p_model == DATAMODEL_LP64); ASSERT(tp->ftt_ripmode & @@ -1566,6 +1709,7 @@ fasttrap_pid_probe(struct regs *rp) i += sizeof (uint64_t); } else { #endif +#ifdef __i386__ /* * Set up the jmp to the next instruction; note that * the size of the traced instruction cancels out. @@ -1574,6 +1718,7 @@ fasttrap_pid_probe(struct regs *rp) /* LINTED - alignment */ *(uint32_t *)&scratch[i] = pc - addr - 5; i += sizeof (uint32_t); +#endif #ifdef __amd64 } #endif @@ -1632,7 +1777,7 @@ done: * output. We had previously set it to the end of the * instruction to simplify %rip-relative addressing. */ - rp->r_pc = pc; + rp->r_rip = pc; fasttrap_return_common(rp, pc, pid, new_pc); } else { @@ -1643,13 +1788,14 @@ done: } } - rp->r_pc = new_pc; + rp->r_rip = new_pc; + set_regs(curthread, rp); return (0); } int -fasttrap_return_probe(struct regs *rp) +fasttrap_return_probe(struct reg *rp) { proc_t *p = curproc; uintptr_t pc = curthread->t_dtrace_pc; @@ -1660,6 +1806,7 @@ fasttrap_return_probe(struct regs *rp) curthread->t_dtrace_scrpc = 0; curthread->t_dtrace_astpc = 0; +#if defined(sun) /* * Treat a child created by a call to vfork(2) as if it were its * parent. We know that there's only one thread of control in such a @@ -1668,15 +1815,16 @@ fasttrap_return_probe(struct regs *rp) while (p->p_flag & SVFORK) { p = p->p_parent; } +#endif /* - * We set rp->r_pc to the address of the traced instruction so + * We set rp->r_rip to the address of the traced instruction so * that it appears to dtrace_probe() that we're on the original * instruction, and so that the user can't easily detect our * complex web of lies. dtrace_return_probe() (our caller) * will correctly set %pc after we return. */ - rp->r_pc = pc; + rp->r_rip = pc; fasttrap_return_common(rp, pc, p->p_pid, npc); @@ -1688,7 +1836,11 @@ uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { - return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 1, argno)); + struct reg r; + + fill_regs(curthread, &r); + + return (fasttrap_anarg(&r, 1, argno)); } /*ARGSUSED*/ @@ -1696,11 +1848,15 @@ uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) { - return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno)); + struct reg r; + + fill_regs(curthread, &r); + + return (fasttrap_anarg(&r, 0, argno)); } static ulong_t -fasttrap_getreg(struct regs *rp, uint_t reg) +fasttrap_getreg(struct reg *rp, uint_t reg) { #ifdef __amd64 switch (reg) { @@ -1723,20 +1879,23 @@ fasttrap_getreg(struct regs *rp, uint_t reg) case REG_ERR: return (rp->r_err); case REG_RIP: return (rp->r_rip); case REG_CS: return (rp->r_cs); +#if defined(sun) case REG_RFL: return (rp->r_rfl); +#endif case REG_RSP: return (rp->r_rsp); case REG_SS: return (rp->r_ss); case REG_FS: return (rp->r_fs); case REG_GS: return (rp->r_gs); case REG_DS: return (rp->r_ds); case REG_ES: return (rp->r_es); - case REG_FSBASE: return (rdmsr(MSR_AMD_FSBASE)); - case REG_GSBASE: return (rdmsr(MSR_AMD_GSBASE)); + case REG_FSBASE: return (rdmsr(MSR_FSBASE)); + case REG_GSBASE: return (rdmsr(MSR_GSBASE)); } panic("dtrace: illegal register constant"); /*NOTREACHED*/ #else +#define _NGREG 19 if (reg >= _NGREG) panic("dtrace: illegal register constant"); diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c index c58e88ec71a..d9ed0800654 100644 --- a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c @@ -42,6 +42,7 @@ #include #include +#include "regset.h" uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); @@ -103,12 +104,11 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, { volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; - struct amd64_frame *frame; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); - while (pc != 0 && sp != 0) { + while (pc != 0) { ret++; if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; @@ -117,10 +117,12 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, break; } - frame = (struct amd64_frame *) sp; + if (sp == 0) + break; - pc = dtrace_fulword(&frame->f_retaddr); - sp = dtrace_fulword(&frame->f_frame); + pc = dtrace_fuword64((void *)(sp + + offsetof(struct amd64_frame, f_retaddr))); + sp = dtrace_fuword64((void *)sp); /* * This is totally bogus: if we faulted, we're going to clear @@ -141,7 +143,7 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; - uintptr_t pc, sp; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; @@ -165,18 +167,28 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) return; pc = tf->tf_rip; + fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; - pc = dtrace_fulword((void *) sp); + pc = dtrace_fuword64((void *) sp); } - n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); + n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); @@ -193,7 +205,7 @@ dtrace_getustackdepth(void) { proc_t *p = curproc; struct trapframe *tf; - uintptr_t pc, sp; + uintptr_t pc, fp, sp; int n = 0; if (p == NULL || (tf = curthread->td_frame) == NULL) @@ -203,30 +215,40 @@ dtrace_getustackdepth(void) return (-1); pc = tf->tf_rip; + fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { - n++; + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ - pc = dtrace_fulword((void *) sp); + pc = dtrace_fuword64((void *) sp); + n++; } - n += dtrace_getustack_common(NULL, 0, pc, sp); + n += dtrace_getustack_common(NULL, 0, pc, fp); return (n); } -#ifdef notyet void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp, oldcontext; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; +#ifdef notyet /* XXX signal stack */ + uintptr_t oldcontext; size_t s1, s2; +#endif if (*flags & CPU_DTRACE_FAULT) return; @@ -237,7 +259,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -246,12 +268,15 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; - oldcontext = lwp->lwp_oldcontext; + pc = tf->tf_rip; + sp = tf->tf_rsp; + fp = tf->tf_rbp; +#ifdef notyet /* XXX signal stack */ + oldcontext = lwp->lwp_oldcontext; s1 = sizeof (struct xframe) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); +#endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; @@ -260,19 +285,20 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword64((void *)sp); } - while (pc != 0 && sp != 0) { + while (pc != 0) { *pcstack++ = (uint64_t)pc; - *fpstack++ = sp; + *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; + if (fp == 0) + break; + +#ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; @@ -281,11 +307,12 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); - } else { - struct xframe *fr = (struct xframe *)sp; - - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); + } else +#endif /* XXX */ + { + pc = dtrace_fuword64((void *)(fp + + offsetof(struct amd64_frame, f_retaddr))); + fp = dtrace_fuword64((void *)fp); } /* @@ -301,9 +328,8 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } -#endif /*ARGSUSED*/ uint64_t @@ -412,31 +438,30 @@ dtrace_getstackdepth(int aframes) return depth - aframes; } -#ifdef notyet ulong_t -dtrace_getreg(struct regs *rp, uint_t reg) +dtrace_getreg(struct trapframe *rp, uint_t reg) { -#if defined(__amd64) + /* This table is dependent on reg.d. */ int regmap[] = { - REG_GS, /* GS */ - REG_FS, /* FS */ - REG_ES, /* ES */ - REG_DS, /* DS */ - REG_RDI, /* EDI */ - REG_RSI, /* ESI */ - REG_RBP, /* EBP */ - REG_RSP, /* ESP */ - REG_RBX, /* EBX */ - REG_RDX, /* EDX */ - REG_RCX, /* ECX */ - REG_RAX, /* EAX */ - REG_TRAPNO, /* TRAPNO */ - REG_ERR, /* ERR */ - REG_RIP, /* EIP */ - REG_CS, /* CS */ - REG_RFL, /* EFL */ - REG_RSP, /* UESP */ - REG_SS /* SS */ + REG_GS, /* 0 GS */ + REG_FS, /* 1 FS */ + REG_ES, /* 2 ES */ + REG_DS, /* 3 DS */ + REG_RDI, /* 4 EDI */ + REG_RSI, /* 5 ESI */ + REG_RBP, /* 6 EBP, REG_FP */ + REG_RSP, /* 7 ESP */ + REG_RBX, /* 8 EBX, REG_R1 */ + REG_RDX, /* 9 EDX */ + REG_RCX, /* 10 ECX */ + REG_RAX, /* 11 EAX, REG_R0 */ + REG_TRAPNO, /* 12 TRAPNO */ + REG_ERR, /* 13 ERR */ + REG_RIP, /* 14 EIP, REG_PC */ + REG_CS, /* 15 CS */ + REG_RFL, /* 16 EFL, REG_PS */ + REG_RSP, /* 17 UESP, REG_SP */ + REG_SS /* 18 SS */ }; if (reg <= SS) { @@ -447,77 +472,68 @@ dtrace_getreg(struct regs *rp, uint_t reg) reg = regmap[reg]; } else { + /* This is dependent on reg.d. */ reg -= SS + 1; } switch (reg) { case REG_RDI: - return (rp->r_rdi); + return (rp->tf_rdi); case REG_RSI: - return (rp->r_rsi); + return (rp->tf_rsi); case REG_RDX: - return (rp->r_rdx); + return (rp->tf_rdx); case REG_RCX: - return (rp->r_rcx); + return (rp->tf_rcx); case REG_R8: - return (rp->r_r8); + return (rp->tf_r8); case REG_R9: - return (rp->r_r9); + return (rp->tf_r9); case REG_RAX: - return (rp->r_rax); + return (rp->tf_rax); case REG_RBX: - return (rp->r_rbx); + return (rp->tf_rbx); case REG_RBP: - return (rp->r_rbp); + return (rp->tf_rbp); case REG_R10: - return (rp->r_r10); + return (rp->tf_r10); case REG_R11: - return (rp->r_r11); + return (rp->tf_r11); case REG_R12: - return (rp->r_r12); + return (rp->tf_r12); case REG_R13: - return (rp->r_r13); + return (rp->tf_r13); case REG_R14: - return (rp->r_r14); + return (rp->tf_r14); case REG_R15: - return (rp->r_r15); + return (rp->tf_r15); case REG_DS: - return (rp->r_ds); + return (rp->tf_ds); case REG_ES: - return (rp->r_es); + return (rp->tf_es); case REG_FS: - return (rp->r_fs); + return (rp->tf_fs); case REG_GS: - return (rp->r_gs); + return (rp->tf_gs); case REG_TRAPNO: - return (rp->r_trapno); + return (rp->tf_trapno); case REG_ERR: - return (rp->r_err); + return (rp->tf_err); case REG_RIP: - return (rp->r_rip); + return (rp->tf_rip); case REG_CS: - return (rp->r_cs); + return (rp->tf_cs); case REG_SS: - return (rp->r_ss); + return (rp->tf_ss); case REG_RFL: - return (rp->r_rfl); + return (rp->tf_rflags); case REG_RSP: - return (rp->r_rsp); + return (rp->tf_rsp); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } - -#else - if (reg > SS) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - - return ((&rp->r_gs)[reg]); -#endif } -#endif static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) diff --git a/sys/cddl/dev/dtrace/amd64/instr_size.c b/sys/cddl/dev/dtrace/amd64/instr_size.c index 418d9f1fb53..1acf2c5813e 100644 --- a/sys/cddl/dev/dtrace/amd64/instr_size.c +++ b/sys/cddl/dev/dtrace/amd64/instr_size.c @@ -47,6 +47,7 @@ typedef u_int model_t; #define DATAMODEL_NATIVE 0 int dtrace_instr_size(uchar_t *); +int dtrace_instr_size_isa(uchar_t *, model_t, int *); #endif #include @@ -124,6 +125,12 @@ dtrace_dis_isize(uchar_t *instr, dis_isize_t which, model_t model, int *rmindex) return (sz); } +int +dtrace_instr_size_isa(uchar_t *instr, model_t model, int *rmindex) +{ + return (dtrace_dis_isize(instr, DIS_ISIZE_INSTR, model, rmindex)); +} + int dtrace_instr_size(uchar_t *instr) { diff --git a/sys/cddl/dev/dtrace/amd64/regset.h b/sys/cddl/dev/dtrace/amd64/regset.h new file mode 100644 index 00000000000..d6732ff5e99 --- /dev/null +++ b/sys/cddl/dev/dtrace/amd64/regset.h @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _REGSET_H +#define _REGSET_H + +/* + * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The names and offsets defined here should be specified by the + * AMD64 ABI suppl. + * + * We make fsbase and gsbase part of the lwp context (since they're + * the only way to access the full 64-bit address range via the segment + * registers) and thus belong here too. However we treat them as + * read-only; if %fs or %gs are updated, the results of the descriptor + * table lookup that those updates implicitly cause will be reflected + * in the corresponding fsbase and/or gsbase values the next time the + * context can be inspected. However it is NOT possible to override + * the fsbase/gsbase settings via this interface. + * + * Direct modification of the base registers (thus overriding the + * descriptor table base address) can be achieved with _lwp_setprivate. + */ + +#define REG_GSBASE 27 +#define REG_FSBASE 26 +#define REG_DS 25 +#define REG_ES 24 + +#define REG_GS 23 +#define REG_FS 22 +#define REG_SS 21 +#define REG_RSP 20 +#define REG_RFL 19 +#define REG_CS 18 +#define REG_RIP 17 +#define REG_ERR 16 +#define REG_TRAPNO 15 +#define REG_RAX 14 +#define REG_RCX 13 +#define REG_RDX 12 +#define REG_RBX 11 +#define REG_RBP 10 +#define REG_RSI 9 +#define REG_RDI 8 +#define REG_R8 7 +#define REG_R9 6 +#define REG_R10 5 +#define REG_R11 4 +#define REG_R12 3 +#define REG_R13 2 +#define REG_R14 1 +#define REG_R15 0 + +/* + * The names and offsets defined here are specified by i386 ABI suppl. + */ + +#define SS 18 /* only stored on a privilege transition */ +#define UESP 17 /* only stored on a privilege transition */ +#define EFL 16 +#define CS 15 +#define EIP 14 +#define ERR 13 +#define TRAPNO 12 +#define EAX 11 +#define ECX 10 +#define EDX 9 +#define EBX 8 +#define ESP 7 +#define EBP 6 +#define ESI 5 +#define EDI 4 +#define DS 3 +#define ES 2 +#define FS 1 +#define GS 0 + +#define REG_PC EIP +#define REG_FP EBP +#define REG_SP UESP +#define REG_PS EFL +#define REG_R0 EAX +#define REG_R1 EDX + +#ifdef __cplusplus +} +#endif + +#endif /* _REGSET_H */ diff --git a/sys/cddl/dev/dtrace/dtrace_cddl.h b/sys/cddl/dev/dtrace/dtrace_cddl.h index 75fe8648cc1..d2adfbc07c3 100644 --- a/sys/cddl/dev/dtrace/dtrace_cddl.h +++ b/sys/cddl/dev/dtrace/dtrace_cddl.h @@ -36,6 +36,7 @@ typedef struct kdtrace_proc { int p_dtrace_probes; /* Are there probes for this proc? */ u_int64_t p_dtrace_count; /* Number of DTrace tracepoints */ void *p_dtrace_helpers; /* DTrace helpers, if any */ + int p_dtrace_model; } kdtrace_proc_t; @@ -59,6 +60,9 @@ typedef struct kdtrace_thread { /* Handling a return probe. */ u_int8_t _td_dtrace_ast; /* Saved ast flag. */ +#ifdef __amd64__ + u_int8_t _td_dtrace_reg; +#endif } _tds; u_long _td_dtrace_ft; /* Bitwise or of these flags. */ } _tdu; @@ -67,6 +71,7 @@ typedef struct kdtrace_thread { #define td_dtrace_step _tdu._tds._td_dtrace_step #define td_dtrace_ret _tdu._tds._td_dtrace_ret #define td_dtrace_ast _tdu._tds._td_dtrace_ast +#define td_dtrace_reg _tdu._tds._td_dtrace_reg uintptr_t td_dtrace_pc; /* DTrace saved pc from fasttrap. */ uintptr_t td_dtrace_npc; /* DTrace next pc from fasttrap. */ @@ -74,6 +79,9 @@ typedef struct kdtrace_thread { /* DTrace per-thread scratch location. */ uintptr_t td_dtrace_astpc; /* DTrace return sequence location. */ +#ifdef __amd64__ + uintptr_t td_dtrace_regv; +#endif u_int64_t td_hrtime; /* Last time on cpu. */ int td_errno; /* Syscall return value. */ } kdtrace_thread_t; @@ -89,16 +97,38 @@ typedef struct kdtrace_thread { #define t_dtrace_stop td_dtrace->td_dtrace_stop #define t_dtrace_sig td_dtrace->td_dtrace_sig #define t_predcache td_dtrace->td_predcache -#define p_dtrace_helpers p_dtrace->p_dtrace_helpers +#define t_dtrace_ft td_dtrace->td_dtrace_ft +#define t_dtrace_on td_dtrace->td_dtrace_on +#define t_dtrace_step td_dtrace->td_dtrace_step +#define t_dtrace_ret td_dtrace->td_dtrace_ret +#define t_dtrace_ast td_dtrace->td_dtrace_ast +#define t_dtrace_reg td_dtrace->td_dtrace_reg +#define t_dtrace_pc td_dtrace->td_dtrace_pc +#define t_dtrace_npc td_dtrace->td_dtrace_npc +#define t_dtrace_scrpc td_dtrace->td_dtrace_scrpc +#define t_dtrace_astpc td_dtrace->td_dtrace_astpc +#define t_dtrace_regv td_dtrace->td_dtrace_regv +#define p_dtrace_helpers p_dtrace->p_dtrace_helpers +#define p_dtrace_count p_dtrace->p_dtrace_count +#define p_dtrace_probes p_dtrace->p_dtrace_probes +#define p_model p_dtrace->p_dtrace_model +#define DATAMODEL_NATIVE 0 +#ifdef __amd64__ +#define DATAMODEL_LP64 0 +#define DATAMODEL_ILP32 1 +#else +#define DATAMODEL_LP64 1 +#define DATAMODEL_ILP32 0 +#endif /* - * Definitions for fields in struct proc which are named differntly in FreeBSD. + * Definitions for fields in struct proc which are named differently in FreeBSD. */ #define p_cred p_ucred #define p_parent p_pptr /* - * Definitions for fields in struct thread which are named differntly in FreeBSD. + * Definitions for fields in struct thread which are named differently in FreeBSD. */ #define t_procp td_proc #define t_tid td_tid diff --git a/sys/cddl/dev/dtrace/dtrace_ioctl.c b/sys/cddl/dev/dtrace/dtrace_ioctl.c index bc408c43e55..79fea7bb79d 100644 --- a/sys/cddl/dev/dtrace/dtrace_ioctl.c +++ b/sys/cddl/dev/dtrace/dtrace_ioctl.c @@ -27,6 +27,55 @@ SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW, &dtrace_verbose_i #define DTRACE_IOCTL_PRINTF(fmt, ...) if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ ) +static int +dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + int rval; + dof_helper_t *dhp = NULL; + dof_hdr_t *dof = NULL; + + switch (cmd) { + case DTRACEHIOC_ADDDOF: + dhp = (dof_helper_t *)addr; + /* XXX all because dofhp_dof is 64 bit */ +#ifdef __i386 + addr = (caddr_t)(uint32_t)dhp->dofhp_dof; +#else + addr = (caddr_t)dhp->dofhp_dof; +#endif + /* FALLTHROUGH */ + case DTRACEHIOC_ADD: + dof = dtrace_dof_copyin((intptr_t)addr, &rval); + + if (dof == NULL) + return (rval); + + mutex_enter(&dtrace_lock); + if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) { + if (dhp) { + dhp->gen = rval; + copyout(dhp, addr, sizeof(*dhp)); + } + rval = 0; + } else { + rval = EINVAL; + } + mutex_exit(&dtrace_lock); + return (rval); + case DTRACEHIOC_REMOVE: + mutex_enter(&dtrace_lock); + rval = dtrace_helper_destroygen((int)*addr); + mutex_exit(&dtrace_lock); + + return (rval); + default: + break; + } + + return (ENOTTY); +} + /* ARGSUSED */ static int dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, diff --git a/sys/cddl/dev/dtrace/dtrace_load.c b/sys/cddl/dev/dtrace/dtrace_load.c index accee4706ac..59267259c35 100644 --- a/sys/cddl/dev/dtrace/dtrace_load.c +++ b/sys/cddl/dev/dtrace/dtrace_load.c @@ -161,7 +161,10 @@ dtrace_load(void *dummy) /* Setup device cloning events. */ eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000); #else - dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "dtrace/dtrace"); + dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "dtrace/dtrace"); + helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660, + "dtrace/helper"); #endif return; diff --git a/sys/cddl/dev/dtrace/dtrace_unload.c b/sys/cddl/dev/dtrace/dtrace_unload.c index 40b09dc463a..247cbb183dd 100644 --- a/sys/cddl/dev/dtrace/dtrace_unload.c +++ b/sys/cddl/dev/dtrace/dtrace_unload.c @@ -43,6 +43,7 @@ dtrace_unload() } #else destroy_dev(dtrace_dev); + destroy_dev(helper_dev); #endif mutex_enter(&dtrace_provider_lock); diff --git a/sys/cddl/dev/dtrace/i386/dtrace_isa.c b/sys/cddl/dev/dtrace/i386/dtrace_isa.c index bf891aa39e1..3f73a50ef2e 100644 --- a/sys/cddl/dev/dtrace/i386/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/i386/dtrace_isa.c @@ -33,13 +33,17 @@ #include #include +#include #include +#include #include #include #include #include +#include "regset.h" + extern uintptr_t kernbase; uintptr_t kernelbase = (uintptr_t) &kernbase; @@ -100,21 +104,22 @@ dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, } } -#ifdef notyet static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { - klwp_t *lwp = ttolwp(curthread); +#ifdef notyet proc_t *p = curproc; - uintptr_t oldcontext = lwp->lwp_oldcontext; + uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ + size_t s1, s2; +#endif volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; - size_t s1, s2; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); +#ifdef notyet /* XXX signal stack. */ if (p->p_model == DATAMODEL_NATIVE) { s1 = sizeof (struct frame) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); @@ -122,8 +127,9 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } +#endif - while (pc != 0 && sp != 0) { + while (pc != 0) { ret++; if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; @@ -132,6 +138,10 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, break; } + if (sp == 0) + break; + +#ifdef notyet /* XXX signal stack. */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; @@ -163,6 +173,11 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, sp = dtrace_fuword32(&fr->fr_savfp); } } +#else + pc = dtrace_fuword32((void *)(sp + + offsetof(struct i386_frame, f_retaddr))); + sp = dtrace_fuword32((void *)sp); +#endif /* ! notyet */ /* * This is totally bogus: if we faulted, we're going to clear @@ -181,10 +196,9 @@ dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; @@ -198,7 +212,7 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -207,19 +221,26 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword32((void *) sp); } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); @@ -231,24 +252,58 @@ dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } int dtrace_getustackdepth(void) { + proc_t *p = curproc; + struct trapframe *tf; + uintptr_t pc, fp, sp; + int n = 0; + + if (p == NULL || (tf = curthread->td_frame) == NULL) + return (0); + + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) + return (-1); + + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; + + if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { + /* + * In an entry probe. The frame pointer has not yet been + * pushed (that happens in the function prologue). The + * best approach is to add the current pc as a missing top + * of stack and back the pc up to the caller, which is stored + * at the current stack pointer address since the call + * instruction puts it there right before the branch. + */ + + pc = dtrace_fuword32((void *) sp); + n++; + } + + n += dtrace_getustack_common(NULL, 0, pc, fp); + + return (n); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { - klwp_t *lwp = ttolwp(curthread); proc_t *p = curproc; - struct regs *rp; - uintptr_t pc, sp, oldcontext; + struct trapframe *tf; + uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; +#ifdef notyet /* XXX signal stack */ + uintptr_t oldcontext; size_t s1, s2; +#endif if (*flags & CPU_DTRACE_FAULT) return; @@ -259,7 +314,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) /* * If there's no user context we still need to zero the stack. */ - if (lwp == NULL || p == NULL || (rp = lwp->lwp_regs) == NULL) + if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; @@ -268,8 +323,11 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - pc = rp->r_pc; - sp = rp->r_fp; + pc = tf->tf_eip; + fp = tf->tf_ebp; + sp = tf->tf_esp; + +#ifdef notyet /* XXX signal stack */ oldcontext = lwp->lwp_oldcontext; if (p->p_model == DATAMODEL_NATIVE) { @@ -279,6 +337,7 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } +#endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; @@ -287,19 +346,20 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) if (pcstack_limit <= 0) return; - if (p->p_model == DATAMODEL_NATIVE) - pc = dtrace_fulword((void *)rp->r_sp); - else - pc = dtrace_fuword32((void *)rp->r_sp); + pc = dtrace_fuword32((void *)sp); } - while (pc != 0 && sp != 0) { + while (pc != 0) { *pcstack++ = (uint64_t)pc; - *fpstack++ = sp; + *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; + if (fp == 0) + break; + +#ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; @@ -318,18 +378,12 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) oldcontext = dtrace_fuword32(&ucp->uc_link); } - } else { - if (p->p_model == DATAMODEL_NATIVE) { - struct frame *fr = (struct frame *)sp; - - pc = dtrace_fulword(&fr->fr_savpc); - sp = dtrace_fulword(&fr->fr_savfp); - } else { - struct frame32 *fr = (struct frame32 *)sp; - - pc = dtrace_fuword32(&fr->fr_savpc); - sp = dtrace_fuword32(&fr->fr_savfp); - } + } else +#endif /* XXX */ + { + pc = dtrace_fuword32((void *)(fp + + offsetof(struct i386_frame, f_retaddr))); + fp = dtrace_fuword32((void *)fp); } /* @@ -345,9 +399,8 @@ dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) zero: while (pcstack_limit-- > 0) - *pcstack++ = NULL; + *pcstack++ = 0; } -#endif uint64_t dtrace_getarg(int arg, int aframes) @@ -424,112 +477,92 @@ dtrace_getstackdepth(int aframes) return depth - aframes; } -#ifdef notyet ulong_t -dtrace_getreg(struct regs *rp, uint_t reg) +dtrace_getreg(struct trapframe *rp, uint_t reg) { -#if defined(__amd64) - int regmap[] = { - REG_GS, /* GS */ - REG_FS, /* FS */ - REG_ES, /* ES */ - REG_DS, /* DS */ - REG_RDI, /* EDI */ - REG_RSI, /* ESI */ - REG_RBP, /* EBP */ - REG_RSP, /* ESP */ - REG_RBX, /* EBX */ - REG_RDX, /* EDX */ - REG_RCX, /* ECX */ - REG_RAX, /* EAX */ - REG_TRAPNO, /* TRAPNO */ - REG_ERR, /* ERR */ - REG_RIP, /* EIP */ - REG_CS, /* CS */ - REG_RFL, /* EFL */ - REG_RSP, /* UESP */ - REG_SS /* SS */ + struct pcb *pcb; + int regmap[] = { /* Order is dependent on reg.d */ + REG_GS, /* 0 GS */ + REG_FS, /* 1 FS */ + REG_ES, /* 2 ES */ + REG_DS, /* 3 DS */ + REG_RDI, /* 4 EDI */ + REG_RSI, /* 5 ESI */ + REG_RBP, /* 6 EBP, REG_FP */ + REG_RSP, /* 7 ESP */ + REG_RBX, /* 8 EBX */ + REG_RDX, /* 9 EDX, REG_R1 */ + REG_RCX, /* 10 ECX */ + REG_RAX, /* 11 EAX, REG_R0 */ + REG_TRAPNO, /* 12 TRAPNO */ + REG_ERR, /* 13 ERR */ + REG_RIP, /* 14 EIP, REG_PC */ + REG_CS, /* 15 CS */ + REG_RFL, /* 16 EFL, REG_PS */ + REG_RSP, /* 17 UESP, REG_SP */ + REG_SS /* 18 SS */ }; - if (reg <= SS) { - if (reg >= sizeof (regmap) / sizeof (int)) { - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - - reg = regmap[reg]; - } else { - reg -= SS + 1; - } - - switch (reg) { - case REG_RDI: - return (rp->r_rdi); - case REG_RSI: - return (rp->r_rsi); - case REG_RDX: - return (rp->r_rdx); - case REG_RCX: - return (rp->r_rcx); - case REG_R8: - return (rp->r_r8); - case REG_R9: - return (rp->r_r9); - case REG_RAX: - return (rp->r_rax); - case REG_RBX: - return (rp->r_rbx); - case REG_RBP: - return (rp->r_rbp); - case REG_R10: - return (rp->r_r10); - case REG_R11: - return (rp->r_r11); - case REG_R12: - return (rp->r_r12); - case REG_R13: - return (rp->r_r13); - case REG_R14: - return (rp->r_r14); - case REG_R15: - return (rp->r_r15); - case REG_DS: - return (rp->r_ds); - case REG_ES: - return (rp->r_es); - case REG_FS: - return (rp->r_fs); - case REG_GS: - return (rp->r_gs); - case REG_TRAPNO: - return (rp->r_trapno); - case REG_ERR: - return (rp->r_err); - case REG_RIP: - return (rp->r_rip); - case REG_CS: - return (rp->r_cs); - case REG_SS: - return (rp->r_ss); - case REG_RFL: - return (rp->r_rfl); - case REG_RSP: - return (rp->r_rsp); - default: - DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); - return (0); - } - -#else if (reg > SS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } - return ((&rp->r_gs)[reg]); + if (reg >= sizeof (regmap) / sizeof (int)) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); + } + + reg = regmap[reg]; + + switch(reg) { + case REG_GS: + if ((pcb = curthread->td_pcb) == NULL) { + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); + } + return (pcb->pcb_gs); + case REG_FS: + return (rp->tf_fs); + case REG_ES: + return (rp->tf_es); + case REG_DS: + return (rp->tf_ds); + case REG_RDI: + return (rp->tf_edi); + case REG_RSI: + return (rp->tf_esi); + case REG_RBP: + return (rp->tf_ebp); + case REG_RSP: + return (rp->tf_isp); + case REG_RBX: + return (rp->tf_ebx); + case REG_RCX: + return (rp->tf_ecx); + case REG_RAX: + return (rp->tf_eax); + case REG_TRAPNO: + return (rp->tf_trapno); + case REG_ERR: + return (rp->tf_err); + case REG_RIP: + return (rp->tf_eip); + case REG_CS: + return (rp->tf_cs); + case REG_RFL: + return (rp->tf_eflags); +#if 0 + case REG_RSP: + return (rp->tf_esp); #endif + case REG_SS: + return (rp->tf_ss); + default: + DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); + return (0); + } } -#endif static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) diff --git a/sys/cddl/dev/dtrace/i386/instr_size.c b/sys/cddl/dev/dtrace/i386/instr_size.c index fb6af2d0abd..7f667f7e5ca 100644 --- a/sys/cddl/dev/dtrace/i386/instr_size.c +++ b/sys/cddl/dev/dtrace/i386/instr_size.c @@ -47,6 +47,7 @@ typedef u_int model_t; #define DATAMODEL_NATIVE 0 int dtrace_instr_size(uchar_t *); +int dtrace_instr_size_isa(uchar_t *, model_t, int *); #endif #include @@ -124,6 +125,12 @@ dtrace_dis_isize(uchar_t *instr, dis_isize_t which, model_t model, int *rmindex) return (sz); } +int +dtrace_instr_size_isa(uchar_t *instr, model_t model, int *rmindex) +{ + return (dtrace_dis_isize(instr, DIS_ISIZE_INSTR, model, rmindex)); +} + int dtrace_instr_size(uchar_t *instr) { diff --git a/sys/cddl/dev/dtrace/i386/regset.h b/sys/cddl/dev/dtrace/i386/regset.h new file mode 100644 index 00000000000..d6732ff5e99 --- /dev/null +++ b/sys/cddl/dev/dtrace/i386/regset.h @@ -0,0 +1,127 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * $FreeBSD$ + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#ifndef _REGSET_H +#define _REGSET_H + +/* + * #pragma ident "@(#)regset.h 1.11 05/06/08 SMI" + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The names and offsets defined here should be specified by the + * AMD64 ABI suppl. + * + * We make fsbase and gsbase part of the lwp context (since they're + * the only way to access the full 64-bit address range via the segment + * registers) and thus belong here too. However we treat them as + * read-only; if %fs or %gs are updated, the results of the descriptor + * table lookup that those updates implicitly cause will be reflected + * in the corresponding fsbase and/or gsbase values the next time the + * context can be inspected. However it is NOT possible to override + * the fsbase/gsbase settings via this interface. + * + * Direct modification of the base registers (thus overriding the + * descriptor table base address) can be achieved with _lwp_setprivate. + */ + +#define REG_GSBASE 27 +#define REG_FSBASE 26 +#define REG_DS 25 +#define REG_ES 24 + +#define REG_GS 23 +#define REG_FS 22 +#define REG_SS 21 +#define REG_RSP 20 +#define REG_RFL 19 +#define REG_CS 18 +#define REG_RIP 17 +#define REG_ERR 16 +#define REG_TRAPNO 15 +#define REG_RAX 14 +#define REG_RCX 13 +#define REG_RDX 12 +#define REG_RBX 11 +#define REG_RBP 10 +#define REG_RSI 9 +#define REG_RDI 8 +#define REG_R8 7 +#define REG_R9 6 +#define REG_R10 5 +#define REG_R11 4 +#define REG_R12 3 +#define REG_R13 2 +#define REG_R14 1 +#define REG_R15 0 + +/* + * The names and offsets defined here are specified by i386 ABI suppl. + */ + +#define SS 18 /* only stored on a privilege transition */ +#define UESP 17 /* only stored on a privilege transition */ +#define EFL 16 +#define CS 15 +#define EIP 14 +#define ERR 13 +#define TRAPNO 12 +#define EAX 11 +#define ECX 10 +#define EDX 9 +#define EBX 8 +#define ESP 7 +#define EBP 6 +#define ESI 5 +#define EDI 4 +#define DS 3 +#define ES 2 +#define FS 1 +#define GS 0 + +#define REG_PC EIP +#define REG_FP EBP +#define REG_SP UESP +#define REG_PS EFL +#define REG_R0 EAX +#define REG_R1 EDX + +#ifdef __cplusplus +} +#endif + +#endif /* _REGSET_H */ diff --git a/sys/cddl/dev/systrace/systrace.c b/sys/cddl/dev/systrace/systrace.c index 72c25e4e291..3e992e3a553 100644 --- a/sys/cddl/dev/systrace/systrace.c +++ b/sys/cddl/dev/systrace/systrace.c @@ -153,22 +153,24 @@ static dtrace_provider_id_t systrace_id; * compat syscall from something like Linux. */ static void -systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params) +systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params, + int ret) { int n_args = 0; u_int64_t uargs[8]; + memset(uargs, 0, sizeof(uargs)); /* * Check if this syscall has an argument conversion function * registered. */ - if (sysent->sy_systrace_args_func != NULL) + if (params && sysent->sy_systrace_args_func != NULL) { /* * Convert the syscall parameters using the registered * function. */ (*sysent->sy_systrace_args_func)(sysnum, params, uargs, &n_args); - else + } else if (params) { /* * Use the built-in system call argument conversion * function to translate the syscall structure fields @@ -176,6 +178,13 @@ systrace_probe(u_int32_t id, int sysnum, struct sysent *sysent, void *params) * expects. */ systrace_args(sysnum, params, uargs, &n_args); + } else { + /* + * Since params is NULL, this is a 'return' probe. + * Set arg0 and arg1 as the return value of this syscall. + */ + uargs[0] = uargs[1] = ret; + } /* Process the probe using the converted argments. */ dtrace_probe(id, uargs[0], uargs[1], uargs[2], uargs[3], uargs[4]); diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 579d81b28ba..8da38335983 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -2525,11 +2525,13 @@ syscall32_helper_unregister(struct syscall_helper_data *sd) register_t * freebsd32_copyout_strings(struct image_params *imgp) { - int argc, envc; + int argc, envc, i; u_int32_t *vectp; char *stringp, *destp; u_int32_t *stack_base; struct freebsd32_ps_strings *arginfo; + char canary[sizeof(long) * 8]; + int32_t pagesizes32[MAXPAGESIZES]; size_t execpath_len; int szsigcode; @@ -2545,8 +2547,10 @@ freebsd32_copyout_strings(struct image_params *imgp) sv_psstrings; szsigcode = *(imgp->proc->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - - roundup(execpath_len, sizeof(char *)) - - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); + roundup(execpath_len, sizeof(char *)) - + roundup(sizeof(canary), sizeof(char *)) - + roundup(sizeof(pagesizes32), sizeof(char *)) - + roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* * install sigcode @@ -2564,6 +2568,25 @@ freebsd32_copyout_strings(struct image_params *imgp) execpath_len); } + /* + * Prepare the canary for SSP. + */ + arc4rand(canary, sizeof(canary), 0); + imgp->canary = (uintptr_t)arginfo - szsigcode - execpath_len - + sizeof(canary); + copyout(canary, (void *)imgp->canary, sizeof(canary)); + imgp->canarylen = sizeof(canary); + + /* + * Prepare the pagesizes array. + */ + for (i = 0; i < MAXPAGESIZES; i++) + pagesizes32[i] = (uint32_t)pagesizes[i]; + imgp->pagesizes = (uintptr_t)arginfo - szsigcode - execpath_len - + roundup(sizeof(canary), sizeof(char *)) - sizeof(pagesizes32); + copyout(pagesizes32, (void *)imgp->pagesizes, sizeof(pagesizes32)); + imgp->pagesizeslen = sizeof(pagesizes32); + /* * If we have a valid auxargs ptr, prepare some room * on the stack. diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 974f825ea52..76c8c37fc47 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -96,6 +97,10 @@ __FBSDID("$FreeBSD$"); #include #endif /* __i386__ || __amd64__ */ +#ifdef COMPAT_FREEBSD32 +#include +#endif + #ifdef COMPAT_LINUX32 /* XXX */ #include #else @@ -886,57 +891,172 @@ linprocfs_doprocroot(PFS_FILL_ARGS) return (0); } +#define MAX_ARGV_STR 512 /* Max number of argv-like strings */ +#define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */ + +static int +linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb, + void (*resolver)(const struct ps_strings, u_long *, int *)) +{ + struct iovec iov; + struct uio tmp_uio; + struct ps_strings pss; + int ret, i, n_elements, elm_len; + u_long addr, pbegin; + char **env_vector, *envp; + char env_string[UIO_CHUNK_SZ]; +#ifdef COMPAT_FREEBSD32 + struct freebsd32_ps_strings pss32; + uint32_t *env_vector32; +#endif + +#define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \ +do { \ + iov.iov_base = (caddr_t)(base); \ + iov.iov_len = (len); \ + uio.uio_iov = &(iov); \ + uio.uio_iovcnt = (cnt); \ + uio.uio_offset = (off_t)(offset); \ + uio.uio_resid = (sz); \ + uio.uio_segflg = (flg); \ + uio.uio_rw = (rw); \ + uio.uio_td = (td); \ +} while (0) + + env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK); + +#ifdef COMPAT_FREEBSD32 + env_vector32 = NULL; + if ((p->p_sysent->sv_flags & SV_ILP32) != 0) { + env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR, + M_TEMP, M_WAITOK); + elm_len = sizeof(int32_t); + envp = (char *)env_vector32; + + UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1, + (off_t)(p->p_sysent->sv_psstrings), + sizeof(pss32), UIO_SYSSPACE, UIO_READ, td); + ret = proc_rwmem(p, &tmp_uio); + if (ret != 0) + goto done; + pss.ps_argvstr = PTRIN(pss32.ps_argvstr); + pss.ps_nargvstr = pss32.ps_nargvstr; + pss.ps_envstr = PTRIN(pss32.ps_envstr); + pss.ps_nenvstr = pss32.ps_nenvstr; + } else { +#endif + elm_len = sizeof(char *); + envp = (char *)env_vector; + + UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1, + (off_t)(p->p_sysent->sv_psstrings), + sizeof(pss), UIO_SYSSPACE, UIO_READ, td); + ret = proc_rwmem(p, &tmp_uio); + if (ret != 0) + goto done; +#ifdef COMPAT_FREEBSD32 + } +#endif + + /* Get the array address and the number of elements */ + resolver(pss, &addr, &n_elements); + + /* Consistent with lib/libkvm/kvm_proc.c */ + if (n_elements > MAX_ARGV_STR) { + ret = E2BIG; + goto done; + } + + UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1, + (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td); + ret = proc_rwmem(p, &tmp_uio); + if (ret != 0) + goto done; +#ifdef COMPAT_FREEBSD32 + if (env_vector32 != NULL) { + for (i = 0; i < n_elements; i++) + env_vector[i] = PTRIN(env_vector32[i]); + } +#endif + + /* Now we can iterate through the list of strings */ + for (i = 0; i < n_elements; i++) { + pbegin = (vm_offset_t)env_vector[i]; + for (;;) { + UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string), + 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td); + ret = proc_rwmem(p, &tmp_uio); + if (ret != 0) + goto done; + + if (!strvalid(env_string, UIO_CHUNK_SZ)) { + /* + * We didn't find the end of the string. + * Add the string to the buffer and move + * the pointer. But do not allow strings + * of unlimited length. + */ + sbuf_bcat(sb, env_string, UIO_CHUNK_SZ); + if (sbuf_len(sb) >= ARG_MAX) { + ret = E2BIG; + goto done; + } + pbegin += UIO_CHUNK_SZ; + } else { + sbuf_cat(sb, env_string); + break; + } + } + sbuf_bcat(sb, "", 1); + } +#undef UIO_HELPER + +done: + free(env_vector, M_TEMP); +#ifdef COMPAT_FREEBSD32 + free(env_vector32, M_TEMP); +#endif + return (ret); +} + +static void +ps_string_argv(const struct ps_strings ps, u_long *addr, int *n) +{ + + *addr = (u_long) ps.ps_argvstr; + *n = ps.ps_nargvstr; +} + +static void +ps_string_env(const struct ps_strings ps, u_long *addr, int *n) +{ + + *addr = (u_long) ps.ps_envstr; + *n = ps.ps_nenvstr; +} + /* * Filler function for proc/pid/cmdline */ static int linprocfs_doproccmdline(PFS_FILL_ARGS) { - struct ps_strings pstr; - char **ps_argvstr; - int error, i; - - /* - * If we are using the ps/cmdline caching, use that. Otherwise - * revert back to the old way which only implements full cmdline - * for the currept process and just p->p_comm for all other - * processes. - * Note that if the argv is no longer available, we deliberately - * don't fall back on p->p_comm or return an error: the authentic - * Linux behaviour is to return zero-length in this case. - */ + int ret; PROC_LOCK(p); - if (p->p_args && p_cansee(td, p) == 0) { + if ((ret = p_cansee(td, p)) != 0) { + PROC_UNLOCK(p); + return (ret); + } + if (p->p_args != NULL) { sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); PROC_UNLOCK(p); - } else if (p != td->td_proc) { - PROC_UNLOCK(p); - sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); - } else { - PROC_UNLOCK(p); - error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, - sizeof(pstr)); - if (error) - return (error); - if (pstr.ps_nargvstr > ARG_MAX) - return (E2BIG); - ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), - M_TEMP, M_WAITOK); - error = copyin((void *)pstr.ps_argvstr, ps_argvstr, - pstr.ps_nargvstr * sizeof(char *)); - if (error) { - free(ps_argvstr, M_TEMP); - return (error); - } - for (i = 0; i < pstr.ps_nargvstr; i++) { - sbuf_copyin(sb, ps_argvstr[i], 0); - sbuf_printf(sb, "%c", '\0'); - } - free(ps_argvstr, M_TEMP); + return (0); } + PROC_UNLOCK(p); - return (0); + ret = linprocfs_doargv(td, p, sb, ps_string_argv); + return (ret); } /* @@ -945,9 +1065,17 @@ linprocfs_doproccmdline(PFS_FILL_ARGS) static int linprocfs_doprocenviron(PFS_FILL_ARGS) { + int ret; - sbuf_printf(sb, "doprocenviron\n%c", '\0'); - return (0); + PROC_LOCK(p); + if ((ret = p_cansee(td, p)) != 0) { + PROC_UNLOCK(p); + return (ret); + } + PROC_UNLOCK(p); + + ret = linprocfs_doargv(td, p, sb, ps_string_env); + return (ret); } /* diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 48422605599..01af020face 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -238,12 +238,12 @@ futex_get(uint32_t *uaddr, struct waiting_proc **wp, struct futex **f, } static int -futex_sleep(struct futex *f, struct waiting_proc *wp, unsigned long timeout) +futex_sleep(struct futex *f, struct waiting_proc *wp, int timeout) { int error; FUTEX_ASSERT_LOCKED(f); - LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %ld ref %d", + LINUX_CTR4(sys_futex, "futex_sleep enter uaddr %p wp %p timo %d ref %d", f->f_uaddr, wp, timeout, f->f_refcount); error = sx_sleep(wp, &f->f_lck, PCATCH, "futex", timeout); if (wp->wp_flags & FUTEX_WP_REQUEUED) { @@ -327,8 +327,8 @@ futex_requeue(struct futex *f, int n, struct futex *f2, int n2) static int futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts) { - struct l_timespec timeout = {0, 0}; - struct timeval tv = {0, 0}; + struct l_timespec timeout; + struct timeval tv; int timeout_hz; int error; @@ -336,26 +336,14 @@ futex_wait(struct futex *f, struct waiting_proc *wp, struct l_timespec *ts) error = copyin(ts, &timeout, sizeof(timeout)); if (error) return (error); - } - - tv.tv_usec = timeout.tv_sec * 1000000 + timeout.tv_nsec / 1000; - timeout_hz = tvtohz(&tv); - - if (timeout.tv_sec == 0 && timeout.tv_nsec == 0) + TIMESPEC_TO_TIMEVAL(&tv, &timeout); + error = itimerfix(&tv); + if (error) + return (error); + timeout_hz = tvtohz(&tv); + } else timeout_hz = 0; - /* - * If the user process requests a non null timeout, - * make sure we do not turn it into an infinite - * timeout because timeout_hz gets null. - * - * We use a minimal timeout of 1/hz. Maybe it would - * make sense to just return ETIMEDOUT without sleeping. - */ - if (((timeout.tv_sec != 0) || (timeout.tv_nsec != 0)) && - (timeout_hz == 0)) - timeout_hz = 1; - error = futex_sleep(f, wp, timeout_hz); if (error == EWOULDBLOCK) error = ETIMEDOUT; @@ -431,7 +419,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) int op_ret, val, ret, nrwake; struct linux_emuldata *em; struct waiting_proc *wp; - struct futex *f, *f2; + struct futex *f, *f2 = NULL; int error = 0; /* diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c index b6de86a3c01..07a281e2926 100644 --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -2220,7 +2220,7 @@ again: addrs++; } - if (!sbuf_overflowed(sb)) + if (sbuf_error(sb) == 0) valid_len = sbuf_len(sb); } if (addrs == 0) { @@ -2228,7 +2228,7 @@ again: sbuf_bcat(sb, &ifr, sizeof(ifr)); max_len += sizeof(ifr); - if (!sbuf_overflowed(sb)) + if (sbuf_error(sb) == 0) valid_len = sbuf_len(sb); } } diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h index 4363a327c9d..13cd3598572 100644 --- a/sys/compat/linux/linux_util.h +++ b/sys/compat/linux/linux_util.h @@ -31,11 +31,6 @@ * $FreeBSD$ */ -/* - * This file is pretty much the same as Christos' svr4_util.h - * (for now). - */ - #ifndef _LINUX_UTIL_H_ #define _LINUX_UTIL_H_ diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c index ba1e49ffaf6..714fcd83411 100644 --- a/sys/compat/ndis/subr_ntoskrnl.c +++ b/sys/compat/ndis/subr_ntoskrnl.c @@ -274,7 +274,6 @@ ntoskrnl_libinit() kdpc_queue *kq; callout_entry *e; int i; - char name[64]; mtx_init(&ntoskrnl_dispatchlock, "ntoskrnl dispatch lock", MTX_NDIS_LOCK, MTX_DEF|MTX_RECURSE); @@ -321,9 +320,8 @@ ntoskrnl_libinit() #endif kq = kq_queues + i; kq->kq_cpu = i; - sprintf(name, "Windows DPC %d", i); error = kproc_create(ntoskrnl_dpc_thread, kq, &p, - RFHIGHPID, NDIS_KSTACK_PAGES, name); + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows DPC %d", i); if (error) panic("failed to launch DPC thread"); } @@ -334,9 +332,8 @@ ntoskrnl_libinit() for (i = 0; i < WORKITEM_THREADS; i++) { kq = wq_queues + i; - sprintf(name, "Windows Workitem %d", i); error = kproc_create(ntoskrnl_workitem_thread, kq, &p, - RFHIGHPID, NDIS_KSTACK_PAGES, name); + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Workitem %d", i); if (error) panic("failed to launch workitem thread"); } @@ -3382,7 +3379,6 @@ PsCreateSystemThread(handle, reqaccess, objattrs, phandle, void *thrctx; { int error; - char tname[128]; thread_context *tc; struct proc *p; @@ -3393,9 +3389,8 @@ PsCreateSystemThread(handle, reqaccess, objattrs, phandle, tc->tc_thrctx = thrctx; tc->tc_thrfunc = thrfunc; - sprintf(tname, "windows kthread %d", ntoskrnl_kth); error = kproc_create(ntoskrnl_thrfunc, tc, &p, - RFHIGHPID, NDIS_KSTACK_PAGES, tname); + RFHIGHPID, NDIS_KSTACK_PAGES, "Windows Kthread %d", ntoskrnl_kth); if (error) { free(tc, M_TEMP); diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c index e15232b5e3c..b6ff15316af 100644 --- a/sys/compat/svr4/svr4_sysvec.c +++ b/sys/compat/svr4/svr4_sysvec.c @@ -309,5 +309,5 @@ static moduledata_t svr4_elf_mod = { svr4_elf_modevent, 0 }; -DECLARE_MODULE(svr4elf, svr4_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +DECLARE_MODULE_TIED(svr4elf, svr4_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); MODULE_DEPEND(svr4elf, streams, 1, 1, 1); diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c index 224520c2c4f..493be05dea2 100644 --- a/sys/compat/x86bios/x86bios.c +++ b/sys/compat/x86bios/x86bios.c @@ -203,6 +203,13 @@ x86bios_get_intr(int intno) return (readl(BIOS_PADDRTOVADDR(intno * 4))); } +void +x86bios_set_intr(int intno, uint32_t saddr) +{ + + writel(BIOS_PADDRTOVADDR(intno * 4), saddr); +} + void x86bios_intr(struct x86regs *regs, int intno) { @@ -619,11 +626,15 @@ x86bios_call(struct x86regs *regs, uint16_t seg, uint16_t off) uint32_t x86bios_get_intr(int intno) { - uint32_t *iv; - iv = (uint32_t *)((vm_offset_t)x86bios_ivt + intno * 4); + return (le32toh(*((uint32_t *)x86bios_ivt + intno))); +} - return (le32toh(*iv)); +void +x86bios_set_intr(int intno, uint32_t saddr) +{ + + *((uint32_t *)x86bios_ivt + intno) = htole32(saddr); } void @@ -668,7 +679,7 @@ x86bios_unmap_mem(void) free(x86bios_map, M_DEVBUF); if (x86bios_ivt != NULL) #ifdef X86BIOS_NATIVE_ARCH - pmap_unmapdev((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); + pmap_unmapbios((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE); #else free(x86bios_ivt, M_DEVBUF); #endif @@ -801,7 +812,8 @@ x86bios_get_orm(uint32_t offset) /* Does the shadow ROM contain BIOS POST code for x86? */ p = x86bios_offset(offset); - if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || p[3] != 0xe9) + if (p == NULL || p[0] != 0x55 || p[1] != 0xaa || + (p[3] != 0xe9 && p[3] != 0xeb)) return (NULL); return (p); diff --git a/sys/compat/x86bios/x86bios.h b/sys/compat/x86bios/x86bios.h index f4749329f89..491367de4f1 100644 --- a/sys/compat/x86bios/x86bios.h +++ b/sys/compat/x86bios/x86bios.h @@ -151,6 +151,7 @@ void x86bios_init_regs(struct x86regs *regs); void x86bios_intr(struct x86regs *regs, int intno); int x86bios_match_device(uint32_t offset, device_t dev); void *x86bios_offset(uint32_t offset); +void x86bios_set_intr(int intno, uint32_t saddr); __END_DECLS #endif /* !_X86BIOS_H_ */ diff --git a/sys/conf/Makefile.mips b/sys/conf/Makefile.mips index 0b56bb72518..6291d6cb464 100644 --- a/sys/conf/Makefile.mips +++ b/sys/conf/Makefile.mips @@ -54,20 +54,12 @@ SYSTEM_LD+=-EB EXTRA_FLAGS+=-EB TRAMP_LDFLAGS+=-Wl,-EB HACK_EXTRA_FLAGS+=-EB -Wl,-EB -.if defined(TARGET_64BIT) -SYSTEM_LD+=-m elf64btsmip_fbsd -HACK_EXTRA_FLAGS+=-Wl,-m,elf64btsmip_fbsd -.endif .else CFLAGS+=-EL SYSTEM_LD+=-EL EXTRA_FLAGS+=-EL TRAMP_LDFLAGS+=-Wl,-EL HACK_EXTRA_FLAGS+=-EL -Wl,-EL -.if defined(TARGET_64BIT) -SYSTEM_LD+=-m elf64ltsmip_fbsd -HACK_EXTRA_FLAGS+=-Wl,-m,elf64ltsmip_fbsd -.endif .endif diff --git a/sys/conf/NOTES b/sys/conf/NOTES index 0a44e1c7ab9..73a4d09f2df 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2609,6 +2609,8 @@ device uhci device ohci # EHCI controller device ehci +# XHCI controller +device xhci # SL811 Controller #device slhci # General USB code (mandatory for USB) diff --git a/sys/conf/files b/sys/conf/files index 9f0d5ce92d2..a82de344280 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -221,6 +221,7 @@ contrib/dev/acpica/executer/exsystem.c optional acpi contrib/dev/acpica/executer/exutils.c optional acpi contrib/dev/acpica/hardware/hwacpi.c optional acpi contrib/dev/acpica/hardware/hwgpe.c optional acpi +contrib/dev/acpica/hardware/hwpci.c optional acpi contrib/dev/acpica/hardware/hwregs.c optional acpi contrib/dev/acpica/hardware/hwsleep.c optional acpi contrib/dev/acpica/hardware/hwtimer.c optional acpi @@ -289,6 +290,7 @@ contrib/dev/acpica/utilities/utosi.c optional acpi contrib/dev/acpica/utilities/utresrc.c optional acpi contrib/dev/acpica/utilities/utstate.c optional acpi contrib/dev/acpica/utilities/utxface.c optional acpi +contrib/dev/acpica/utilities/utxferror.c optional acpi contrib/ipfilter/netinet/fil.c optional ipfilter inet \ compile-with "${NORMAL_C} -I$S/contrib/ipfilter" contrib/ipfilter/netinet/ip_auth.c optional ipfilter inet \ @@ -1008,6 +1010,14 @@ dev/fxp/if_fxp.c optional fxp inet dev/gem/if_gem.c optional gem dev/gem/if_gem_pci.c optional gem pci dev/gem/if_gem_sbus.c optional gem sbus +dev/gpio/gpiobus.c optional gpio \ + dependency "gpiobus_if.h" +dev/gpio/gpioc.c optional gpio \ + dependency "gpio_if.h" +dev/gpio/gpioiic.c optional gpioiic +dev/gpio/gpioled.c optional gpioled +dev/gpio/gpio_if.m optional gpio +dev/gpio/gpiobus_if.m optional gpio dev/hatm/if_hatm.c optional hatm pci dev/hatm/if_hatm_intr.c optional hatm pci dev/hatm/if_hatm_ioctl.c optional hatm pci @@ -1064,7 +1074,7 @@ ipw_bss.fwo optional ipwbssfw | ipwfw \ no-implicit-rule \ clean "ipw_bss.fwo" ipw_bss.fw optional ipwbssfw | ipwfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ipw/ipw2100-1.3.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ipw/ipw2100-1.3.fw.uu" \ no-obj no-implicit-rule \ clean "ipw_bss.fw" @@ -1078,7 +1088,7 @@ ipw_ibss.fwo optional ipwibssfw | ipwfw \ no-implicit-rule \ clean "ipw_ibss.fwo" ipw_ibss.fw optional ipwibssfw | ipwfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ipw/ipw2100-1.3-i.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ipw/ipw2100-1.3-i.fw.uu" \ no-obj no-implicit-rule \ clean "ipw_ibss.fw" @@ -1092,7 +1102,7 @@ ipw_monitor.fwo optional ipwmonitorfw | ipwfw \ no-implicit-rule \ clean "ipw_monitor.fwo" ipw_monitor.fw optional ipwmonitorfw | ipwfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ipw/ipw2100-1.3-p.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ipw/ipw2100-1.3-p.fw.uu" \ no-obj no-implicit-rule \ clean "ipw_monitor.fw" @@ -1120,7 +1130,7 @@ iwi_bss.fwo optional iwibssfw | iwifw \ no-implicit-rule \ clean "iwi_bss.fwo" iwi_bss.fw optional iwibssfw | iwifw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwi/ipw2200-bss.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwi/ipw2200-bss.fw.uu" \ no-obj no-implicit-rule \ clean "iwi_bss.fw" @@ -1134,7 +1144,7 @@ iwi_ibss.fwo optional iwiibssfw | iwifw \ no-implicit-rule \ clean "iwi_ibss.fwo" iwi_ibss.fw optional iwiibssfw | iwifw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwi/ipw2200-ibss.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwi/ipw2200-ibss.fw.uu" \ no-obj no-implicit-rule \ clean "iwi_ibss.fw" @@ -1148,7 +1158,7 @@ iwi_monitor.fwo optional iwimonitorfw | iwifw \ no-implicit-rule \ clean "iwi_monitor.fwo" iwi_monitor.fw optional iwimonitorfw | iwifw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwi/ipw2200-sniffer.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwi/ipw2200-sniffer.fw.uu" \ no-obj no-implicit-rule \ clean "iwi_monitor.fw" @@ -1163,7 +1173,7 @@ iwn1000fw.fwo optional iwn1000fw | iwnfw \ no-implicit-rule \ clean "iwn1000fw.fwo" iwn1000.fw optional iwn1000fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-1000-128.50.3.1.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-1000-128.50.3.1.fw.uu" \ no-obj no-implicit-rule \ clean "iwn1000.fw" @@ -1177,7 +1187,7 @@ iwn4965fw.fwo optional iwn4965fw | iwnfw \ no-implicit-rule \ clean "iwn4965fw.fwo" iwn4965.fw optional iwn4965fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-4965-228.61.2.24.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-4965-228.61.2.24.fw.uu" \ no-obj no-implicit-rule \ clean "iwn4965.fw" @@ -1191,7 +1201,7 @@ iwn5000fw.fwo optional iwn5000fw | iwnfw \ no-implicit-rule \ clean "iwn5000fw.fwo" iwn5000.fw optional iwn5000fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-5000-8.24.2.12.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-5000-8.24.2.12.fw.uu" \ no-obj no-implicit-rule \ clean "iwn5000.fw" @@ -1205,7 +1215,7 @@ iwn5150fw.fwo optional iwn5150fw | iwnfw \ no-implicit-rule \ clean "iwn5150fw.fwo" iwn5150.fw optional iwn5150fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-5150-8.24.2.2.fw.uu"\ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-5150-8.24.2.2.fw.uu" \ no-obj no-implicit-rule \ clean "iwn5150.fw" @@ -1219,7 +1229,7 @@ iwn6000fw.fwo optional iwn6000fw | iwnfw \ no-implicit-rule \ clean "iwn6000fw.fwo" iwn6000.fw optional iwn6000fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-6000-9.221.4.1.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-6000-9.221.4.1.fw.uu" \ no-obj no-implicit-rule \ clean "iwn6000.fw" @@ -1233,7 +1243,7 @@ iwn6050fw.fwo optional iwn6050fw | iwnfw \ no-implicit-rule \ clean "iwn6050fw.fwo" iwn6050.fw optional iwn6050fw | iwnfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/iwn/iwlwifi-6050-9.201.4.1.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/iwn/iwlwifi-6050-9.201.4.1.fw.uu" \ no-obj no-implicit-rule \ clean "iwn6000.fw" @@ -1328,6 +1338,11 @@ dev/mmc/mmcbr_if.m standard dev/mmc/mmcbus_if.m standard dev/mmc/mmcsd.c optional mmcsd dev/mn/if_mn.c optional mn pci +dev/mps/mps.c optional mps +dev/mps/mps_pci.c optional mps pci +dev/mps/mps_sas.c optional mps +dev/mps/mps_table.c optional mps +dev/mps/mps_user.c optional mps dev/mpt/mpt.c optional mpt dev/mpt/mpt_cam.c optional mpt dev/mpt/mpt_debug.c optional mpt @@ -1351,7 +1366,7 @@ mw88W8363.fwo optional mwlfw \ no-implicit-rule \ clean "mw88W8363.fwo" mw88W8363.fw optional mwlfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/mwl/mw88W8363.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/mwl/mw88W8363.fw.uu" \ no-obj no-implicit-rule \ clean "mw88W8363.fw" @@ -1361,7 +1376,7 @@ mwlboot.fwo optional mwlfw \ no-implicit-rule \ clean "mwlboot.fwo" mwlboot.fw optional mwlfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/mwl/mwlboot.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/mwl/mwlboot.fw.uu" \ no-obj no-implicit-rule \ clean "mwlboot.fw" @@ -1466,7 +1481,7 @@ rt2561fw.fwo optional rt2561fw | ralfw \ no-implicit-rule \ clean "rt2561fw.fwo" rt2561.fw optional rt2561fw | ralfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ral/rt2561.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ral/rt2561.fw.uu" \ no-obj no-implicit-rule \ clean "rt2561.fw" @@ -1480,7 +1495,7 @@ rt2561sfw.fwo optional rt2561sfw | ralfw \ no-implicit-rule \ clean "rt2561sfw.fwo" rt2561s.fw optional rt2561sfw | ralfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ral/rt2561s.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ral/rt2561s.fw.uu" \ no-obj no-implicit-rule \ clean "rt2561s.fw" @@ -1494,7 +1509,7 @@ rt2661fw.fwo optional rt2661fw | ralfw \ no-implicit-rule \ clean "rt2661fw.fwo" rt2661.fw optional rt2661fw | ralfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ral/rt2661.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ral/rt2661.fw.uu" \ no-obj no-implicit-rule \ clean "rt2661.fw" @@ -1508,7 +1523,7 @@ rt2860fw.fwo optional rt2860fw | ralfw \ no-implicit-rule \ clean "rt2860fw.fwo" rt2860.fw optional rt2860fw | ralfw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/ral/rt2860.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/ral/rt2860.fw.uu" \ no-obj no-implicit-rule \ clean "rt2860.fw" @@ -1733,6 +1748,8 @@ dev/usb/controller/ohci_atmelarm.c optional ohci at91rm9200 dev/usb/controller/ohci_pci.c optional ohci pci dev/usb/controller/uhci.c optional uhci dev/usb/controller/uhci_pci.c optional uhci pci +dev/usb/controller/xhci.c optional xhci +dev/usb/controller/xhci_pci.c optional xhci pci dev/usb/controller/uss820dci.c optional uss820dci dev/usb/controller/uss820dci_atmelarm.c optional uss820dci at91rm9200 dev/usb/controller/usb_controller.c optional usb @@ -1773,6 +1790,7 @@ dev/usb/net/if_aue.c optional aue dev/usb/net/if_axe.c optional axe dev/usb/net/if_cdce.c optional cdce dev/usb/net/if_cue.c optional cue +dev/usb/net/if_ipheth.c optional ipheth dev/usb/net/if_kue.c optional kue dev/usb/net/if_rue.c optional rue dev/usb/net/if_udav.c optional udav @@ -1868,7 +1886,7 @@ wpifw.fwo optional wpifw \ no-implicit-rule \ clean "wpifw.fwo" wpi.fw optional wpifw \ - dependency ".PHONY" \ + dependency "$S/contrib/dev/wpi/iwlwifi-3945-2.14.4.fw.uu" \ compile-with "uudecode -o ${.TARGET} $S/contrib/dev/wpi/iwlwifi-3945-2.14.4.fw.uu" \ no-obj no-implicit-rule \ clean "wpi.fw" @@ -1883,6 +1901,7 @@ fs/coda/coda_vfsops.c optional vcoda fs/coda/coda_vnops.c optional vcoda fs/deadfs/dead_vnops.c standard fs/devfs/devfs_devs.c standard +fs/devfs/devfs_dir.c standard fs/devfs/devfs_rule.c standard fs/devfs/devfs_vfsops.c standard fs/devfs/devfs_vnops.c standard @@ -2249,6 +2268,7 @@ kern/vfs_hash.c standard kern/vfs_init.c standard kern/vfs_lookup.c standard kern/vfs_mount.c standard +kern/vfs_mountroot.c standard kern/vfs_subr.c standard kern/vfs_syscalls.c standard kern/vfs_vnops.c standard @@ -2322,6 +2342,8 @@ libkern/iconv_xlat16.c optional libiconv libkern/index.c standard libkern/inet_aton.c standard libkern/inet_ntoa.c standard +libkern/inet_ntop.c standard +libkern/inet_pton.c standard libkern/mcount.c optional profiling-routine libkern/memcmp.c standard libkern/qsort.c standard @@ -2432,6 +2454,7 @@ net80211/ieee80211_power.c optional wlan net80211/ieee80211_proto.c optional wlan net80211/ieee80211_radiotap.c optional wlan net80211/ieee80211_ratectl.c optional wlan +net80211/ieee80211_ratectl_none.c optional wlan net80211/ieee80211_regdomain.c optional wlan net80211/ieee80211_rssadapt.c optional wlan wlan_rssadapt net80211/ieee80211_scan.c optional wlan @@ -2537,6 +2560,7 @@ netinet/if_atm.c optional atm netinet/if_ether.c optional inet ether netinet/igmp.c optional inet netinet/in.c optional inet +netinet/in_debug.c optional inet ddb netinet/ip_carp.c optional inet carp | inet6 carp netinet/in_gif.c optional gif inet | netgraph_gif inet netinet/ip_gre.c optional gre inet @@ -2729,8 +2753,6 @@ rpc/clnt_dg.c optional krpc | nfslockd | nfsclient | nfscl | nfsd rpc/clnt_rc.c optional krpc | nfslockd | nfsclient | nfscl | nfsd rpc/clnt_vc.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd rpc/getnetconfig.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd -rpc/inet_ntop.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd -rpc/inet_pton.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd rpc/replay.c optional krpc | nfslockd | nfsserver | nfscl | nfsd rpc/rpc_callmsg.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd rpc/rpc_generic.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd @@ -2988,19 +3010,20 @@ xen/gnttab.c optional xen | xenhvm xen/features.c optional xen | xenhvm xen/evtchn/evtchn.c optional xen xen/evtchn/evtchn_dev.c optional xen | xenhvm -xen/reboot.c optional xen -xen/xenbus/xenbus_client.c optional xen | xenhvm -xen/xenbus/xenbus_comms.c optional xen | xenhvm -xen/xenbus/xenbus_dev.c optional xen | xenhvm xen/xenbus/xenbus_if.m optional xen | xenhvm -xen/xenbus/xenbus_probe.c optional xen | xenhvm -#xen/xenbus/xenbus_probe_backend.c optional xen -xen/xenbus/xenbus_xs.c optional xen | xenhvm +xen/xenbus/xenbus.c optional xen | xenhvm +xen/xenbus/xenbusb_if.m optional xen | xenhvm +xen/xenbus/xenbusb.c optional xen | xenhvm +xen/xenbus/xenbusb_front.c optional xen | xenhvm +xen/xenbus/xenbusb_back.c optional xen | xenhvm +xen/xenstore/xenstore.c optional xen | xenhvm +xen/xenstore/xenstore_dev.c optional xen | xenhvm dev/xen/balloon/balloon.c optional xen | xenhvm +dev/xen/blkfront/blkfront.c optional xen | xenhvm +dev/xen/blkback/blkback.c optional xen | xenhvm dev/xen/console/console.c optional xen dev/xen/console/xencons_ring.c optional xen -dev/xen/blkfront/blkfront.c optional xen | xenhvm +dev/xen/control/control.c optional xen | xenhvm dev/xen/netfront/netfront.c optional xen | xenhvm dev/xen/xenpci/xenpci.c optional xenpci dev/xen/xenpci/evtchn.c optional xenpci -dev/xen/xenpci/machine_reboot.c optional xenpci diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 14e08d1490a..a3b113b23d2 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -87,7 +87,7 @@ acpi_wakecode.h optional acpi \ clean "acpi_wakecode.h" acpi_wakedata.h optional acpi \ dependency "acpi_wakecode.o" \ - compile-with 'nm -n --defined-only acpi_wakecode.o | while read offset dummy what; do echo "#define $${what} 0x$${offset}"; done > ${.TARGET}' \ + compile-with '${NM} -n --defined-only acpi_wakecode.o | while read offset dummy what; do echo "#define $${what} 0x$${offset}"; done > ${.TARGET}' \ no-obj no-implicit-rule before-depend \ clean "acpi_wakedata.h" # @@ -229,6 +229,9 @@ dev/syscons/scterm-teken.c optional sc dev/syscons/scvesactl.c optional sc vga vesa dev/syscons/scvgarndr.c optional sc vga dev/syscons/scvtb.c optional sc +dev/tpm/tpm.c optional tpm +dev/tpm/tpm_acpi.c optional tpm acpi +dev/tpm/tpm_isa.c optional tpm isa dev/uart/uart_cpu_amd64.c optional uart dev/wpi/if_wpi.c optional wpi isa/syscons_isa.c optional sc @@ -317,6 +320,7 @@ x86/isa/isa.c standard x86/isa/isa_dma.c standard x86/isa/nmi.c standard x86/isa/orm.c optional isa +x86/pci/qpi.c standard x86/x86/io_apic.c standard x86/x86/local_apic.c standard x86/x86/mca.c standard diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 078282c222c..f10a234a589 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -394,6 +394,7 @@ x86/isa/isa.c optional isa x86/isa/isa_dma.c optional isa x86/isa/nmi.c standard x86/isa/orm.c optional isa +x86/pci/qpi.c standard x86/x86/io_apic.c optional apic x86/x86/local_apic.c optional apic x86/x86/mca.c standard diff --git a/sys/conf/files.mips b/sys/conf/files.mips index c33fa9afbb7..99a772358e0 100644 --- a/sys/conf/files.mips +++ b/sys/conf/files.mips @@ -22,7 +22,6 @@ mips/mips/machdep.c standard mips/mips/mp_machdep.c optional smp mips/mips/mpboot.S optional smp -mips/mips/psraccess.S standard # ---------------------------------------------------------------------- # Phase 3 # ---------------------------------------------------------------------- diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index 1788a97bf23..0dfe031b0fb 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -26,7 +26,10 @@ dev/cfi/cfi_bus_fdt.c optional cfi fdt dev/fb/fb.c optional sc dev/fdt/fdt_powerpc.c optional fdt dev/hwpmc/hwpmc_powerpc.c optional hwpmc +dev/iicbus/ds1775.c optional ds1775 powermac +dev/iicbus/max6690.c optional max6690 powermac dev/kbd/kbd.c optional sc +dev/mem/memutil.c optional mem dev/ofw/openfirm.c optional aim | fdt dev/ofw/openfirmio.c optional aim | fdt dev/ofw/ofw_bus_if.m optional aim | fdt @@ -52,6 +55,7 @@ dev/syscons/scvtb.c optional sc dev/tsec/if_tsec.c optional tsec dev/tsec/if_tsec_fdt.c optional tsec fdt dev/uart/uart_cpu_powerpc.c optional uart aim +kern/kern_clocksource.c standard kern/syscalls.c optional ktr libkern/ashldi3.c optional powerpc libkern/ashrdi3.c optional powerpc @@ -82,7 +86,6 @@ powerpc/aim/mp_cpudep.c optional aim smp powerpc/aim/nexus.c optional aim powerpc/aim/ofw_machdep.c optional aim powerpc/aim/ofwmagic.S optional aim -powerpc/aim/platform_chrp.c optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/aim/swtch32.S optional aim powerpc powerpc/aim/swtch64.S optional aim powerpc64 @@ -102,15 +105,15 @@ powerpc/booke/trap.c optional e500 powerpc/booke/vm_machdep.c optional e500 powerpc/cpufreq/dfs.c optional cpufreq powerpc/cpufreq/pcr.c optional cpufreq aim -powerpc/fpu/fpu_add.c optional fpu_emu -powerpc/fpu/fpu_compare.c optional fpu_emu -powerpc/fpu/fpu_div.c optional fpu_emu -powerpc/fpu/fpu_emu.c optional fpu_emu -powerpc/fpu/fpu_explode.c optional fpu_emu -powerpc/fpu/fpu_implode.c optional fpu_emu -powerpc/fpu/fpu_mul.c optional fpu_emu -powerpc/fpu/fpu_sqrt.c optional fpu_emu -powerpc/fpu/fpu_subr.c optional fpu_emu +powerpc/fpu/fpu_add.c optional fpu_emu powerpc +powerpc/fpu/fpu_compare.c optional fpu_emu powerpc +powerpc/fpu/fpu_div.c optional fpu_emu powerpc +powerpc/fpu/fpu_emu.c optional fpu_emu powerpc +powerpc/fpu/fpu_explode.c optional fpu_emu powerpc +powerpc/fpu/fpu_implode.c optional fpu_emu powerpc +powerpc/fpu/fpu_mul.c optional fpu_emu powerpc +powerpc/fpu/fpu_sqrt.c optional fpu_emu powerpc +powerpc/fpu/fpu_subr.c optional fpu_emu powerpc powerpc/mambo/mambocall.S optional mambo powerpc/mambo/mambo.c optional mambo powerpc/mambo/mambo_console.c optional mambo @@ -137,12 +140,14 @@ powerpc/powermac/ata_dbdma.c optional powermac ata | powermac atamacio powerpc/powermac/cuda.c optional powermac cuda powerpc/powermac/cpcht.c optional powermac pci powerpc/powermac/dbdma.c optional powermac pci +powerpc/powermac/fcu.c optional powermac fcu powerpc/powermac/grackle.c optional powermac pci powerpc/powermac/hrowpic.c optional powermac pci powerpc/powermac/kiic.c optional powermac kiic powerpc/powermac/macgpio.c optional powermac pci powerpc/powermac/macio.c optional powermac pci powerpc/powermac/openpic_macio.c optional powermac pci +powerpc/powermac/platform_powermac.c optional powermac powerpc/powermac/pswitch.c optional powermac pswitch powerpc/powermac/pmu.c optional powermac pmu powerpc/powermac/smu.c optional powermac smu diff --git a/sys/conf/kern.mk b/sys/conf/kern.mk index 5676057d3d4..4d8636cf734 100644 --- a/sys/conf/kern.mk +++ b/sys/conf/kern.mk @@ -6,7 +6,7 @@ # Note that the newly added -Wcast-qual is responsible for generating # most of the remaining warnings. Warnings introduced with -Wall will # also pop up, but are easier to fix. -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" #CWARNFLAGS= -w2 # use this if you are terribly bored CWARNFLAGS= .else @@ -29,22 +29,22 @@ CWARNFLAGS?= -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes \ # operations inside the kernel itself. These operations are exclusively # reserved for user applications. # -.if ${MACHINE_ARCH} == "i386" && ${CC} != "icc" -.if ${CC} != "clang" +.if ${MACHINE_CPUARCH} == "i386" && ${CC:T:Micc} != "icc" +.if ${CC:T:Mclang} != "clang" CFLAGS+= -mno-align-long-strings -mpreferred-stack-boundary=2 .endif CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 INLINE_LIMIT?= 8000 .endif -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "arm" INLINE_LIMIT?= 8000 .endif # # For IA-64, we use r13 for the kernel globals pointer and we only use # a very small subset of float registers for integer divides. # -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" CFLAGS+= -ffixed-r13 -mfixed-range=f32-f127 -fpic #-mno-sdata INLINE_LIMIT?= 15000 .endif @@ -54,7 +54,7 @@ INLINE_LIMIT?= 15000 # point emulation. This avoids using floating point registers for integer # operations which it has a tendency to do. # -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" CFLAGS+= -mcmodel=medany -msoft-float INLINE_LIMIT?= 15000 .endif @@ -64,7 +64,7 @@ INLINE_LIMIT?= 15000 # operations inside the kernel itself. These operations are exclusively # reserved for user applications. # -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+= -mcmodel=kernel -mno-red-zone \ -mfpmath=387 -mno-sse -mno-sse2 -mno-sse3 -mno-mmx -mno-3dnow \ -msoft-float -fno-asynchronous-unwind-tables @@ -76,7 +76,7 @@ INLINE_LIMIT?= 8000 # floating point registers for integer operations which it has a tendency to do. # Also explicitly disable Altivec instructions inside the kernel. # -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.if ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -msoft-float -mno-altivec INLINE_LIMIT?= 15000 .endif @@ -84,7 +84,7 @@ INLINE_LIMIT?= 15000 # # For MIPS we also tell gcc to use floating point emulation # -.if ${MACHINE_ARCH} == "mips" +.if ${MACHINE_CPUARCH} == "mips" CFLAGS+= -msoft-float INLINE_LIMIT?= 8000 .endif @@ -93,21 +93,22 @@ INLINE_LIMIT?= 8000 # GCC 3.0 and above like to do certain optimizations based on the # assumption that the program is linked against libc. Stop this. # -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" CFLAGS+= -nolib_inline .else CFLAGS+= -ffreestanding .endif -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" CFLAGS+= -restrict .endif # # GCC SSP support. # -.if ${MK_SSP} != "no" && ${CC} != "icc" && ${MACHINE_ARCH} != "ia64" && \ - ${MACHINE_ARCH} != "arm" && ${MACHINE_ARCH} != "mips" +.if ${MK_SSP} != "no" && ${CC:T:Micc} != "icc" && \ + ${MACHINE_CPUARCH} != "ia64" && ${MACHINE_CPUARCH} != "arm" && \ + ${MACHINE_CPUARCH} != "mips" CFLAGS+= -fstack-protector .endif diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk index f759f271fb8..c7e6281f69e 100644 --- a/sys/conf/kern.post.mk +++ b/sys/conf/kern.post.mk @@ -84,8 +84,8 @@ gdbinit: grep -v '# XXX' ${S}/../tools/debugscripts/dot.gdbinit | \ sed "s:MODPATH:${.OBJDIR}/modules:" > .gdbinit cp ${S}/../tools/debugscripts/gdbinit.kernel ${.CURDIR} -.if exists(${S}/../tools/debugscripts/gdbinit.${MACHINE_ARCH}) - cp ${S}/../tools/debugscripts/gdbinit.${MACHINE_ARCH} \ +.if exists(${S}/../tools/debugscripts/gdbinit.${MACHINE_CPUARCH}) + cp ${S}/../tools/debugscripts/gdbinit.${MACHINE_CPUARCH} \ ${.CURDIR}/gdbinit.machine .endif .endif diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk index b113946583b..fc97942a7fa 100644 --- a/sys/conf/kern.pre.mk +++ b/sys/conf/kern.pre.mk @@ -23,7 +23,7 @@ NM?= nm OBJCOPY?= objcopy SIZE?= size -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" COPTFLAGS?= -O .else . if defined(DEBUG) @@ -32,7 +32,7 @@ CTFFLAGS+= -g . else _MINUS_O= -O2 . endif -. if ${MACHINE_ARCH} == "amd64" +. if ${MACHINE_CPUARCH} == "amd64" COPTFLAGS?=-O2 -frename-registers -pipe . else COPTFLAGS?=${_MINUS_O} -pipe @@ -42,13 +42,13 @@ COPTFLAGS+= -fno-strict-aliasing . endif .endif .if !defined(NO_CPU_COPTFLAGS) -. if ${CC} == "icc" +. if ${CC:T:Micc} == "icc" COPTFLAGS+= ${_ICC_CPUCFLAGS:C/(-x[^M^K^W]+)[MKW]+|-x[MKW]+/\1/} . else COPTFLAGS+= ${_CPUCFLAGS} . endif .endif -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" C_DIALECT= NOSTDINC= -X .else @@ -92,8 +92,8 @@ INCLUDES+= -I$S/dev/cxgb CFLAGS= ${COPTFLAGS} ${C_DIALECT} ${DEBUG} ${CWARNFLAGS} CFLAGS+= ${INCLUDES} -D_KERNEL -DHAVE_KERNEL_OPTION_HEADERS -include opt_global.h -.if ${CC} != "icc" -.if ${CC} != "clang" +.if ${CC:T:Micc} != "icc" +.if ${CC:T:Mclang} != "clang" CFLAGS+= -fno-common -finline-limit=${INLINE_LIMIT} .if ${MACHINE_CPUARCH} != "mips" CFLAGS+= --param inline-unit-growth=100 @@ -111,7 +111,7 @@ WERROR?= -Werror ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} .if defined(PROFLEVEL) && ${PROFLEVEL} >= 1 -.if ${CC} == "icc" || ${CC} == "clang" +.if ${CC:T:Micc} == "icc" || ${CC:T:Mclang} == "clang" .error "Profiling doesn't work with icc or clang yet" .endif CFLAGS+= -DGPROF -falign-functions=16 diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 1c7b5aee858..2965d98c01f 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -81,7 +81,16 @@ OBJCOPY?= objcopy .SUFFIXES: .out .o .c .cc .cxx .C .y .l .s .S -.if ${CC} == "icc" +# amd64 and mips use direct linking for kmod, all others use shared binaries +.if ${MACHINE_CPUARCH} != amd64 && \ + ${MACHINE_CPUARCH} != ia64 && \ + ${MACHINE_CPUARCH} != mips +__KLD_SHARED=yes +.else +__KLD_SHARED=no +.endif + +.if ${CC:T:Micc} == "icc" CFLAGS:= ${CFLAGS:C/(-x[^M^K^W]+)[MKW]+|-x[MKW]+/\1/} .else . if !empty(CFLAGS:M-O[23s]) && empty(CFLAGS:M-fno-strict-aliasing) @@ -94,7 +103,7 @@ CFLAGS+= -D_KERNEL CFLAGS+= -DKLD_MODULE # Don't use any standard or source-relative include directories. -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" NOSTDINC= -X .else CSTD= c99 @@ -114,7 +123,7 @@ CFLAGS+= -I. -I@ # for example. CFLAGS+= -I@/contrib/altq -.if ${CC} != "icc" && ${CC} != "clang" +.if ${CC:T:Micc} != "icc" && ${CC:T:Mclang} != "clang" CFLAGS+= -finline-limit=${INLINE_LIMIT} CFLAGS+= --param inline-unit-growth=100 CFLAGS+= --param large-function-growth=1000 @@ -122,21 +131,21 @@ CFLAGS+= --param large-function-growth=1000 # Disallow common variables, and if we end up with commons from # somewhere unexpected, allocate storage for them in the module itself. -.if ${CC} != "icc" +.if ${CC:T:Micc} != "icc" CFLAGS+= -fno-common .endif LDFLAGS+= -d -warn-common CFLAGS+= ${DEBUG_FLAGS} -.if ${MACHINE_ARCH} == amd64 +.if ${MACHINE_CPUARCH} == amd64 CFLAGS+= -fno-omit-frame-pointer .endif -.if ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64" +.if ${MACHINE_CPUARCH} == powerpc CFLAGS+= -mlongcall -fno-omit-frame-pointer .endif -.if ${MACHINE_ARCH} == "mips" +.if ${MACHINE_CPUARCH} == mips CFLAGS+= -G0 -fno-pic -mno-abicalls -mlong-calls .endif @@ -190,8 +199,7 @@ ${PROG}.symbols: ${FULLPROG} ${OBJCOPY} --only-keep-debug ${FULLPROG} ${.TARGET} .endif -.if ${MACHINE_ARCH} != amd64 && ${MACHINE_ARCH} != ia64 && \ - ${MACHINE_ARCH} != mips +.if ${__KLD_SHARED} == yes ${FULLPROG}: ${KMOD}.kld ${LD} -Bshareable ${LDFLAGS} -o ${.TARGET} ${KMOD}.kld .if !defined(DEBUG_FLAGS) @@ -204,8 +212,7 @@ EXPORT_SYMS?= NO CLEANFILES+= export_syms .endif -.if ${MACHINE_ARCH} != amd64 && ${MACHINE_ARCH} != ia64 && \ - ${MACHINE_ARCH} != mips +.if ${__KLD_SHARED} == yes ${KMOD}.kld: ${OBJS} .else ${FULLPROG}: ${OBJS} @@ -225,9 +232,7 @@ ${FULLPROG}: ${OBJS} export_syms | xargs -J% ${OBJCOPY} % ${.TARGET} .endif .endif -.if !defined(DEBUG_FLAGS) && \ - (${MACHINE_ARCH} == amd64 || ${MACHINE_ARCH} == ia64 || \ - ${MACHINE_ARCH} == mips) +.if !defined(DEBUG_FLAGS) && ${__KLD_SHARED} == no ${OBJCOPY} --strip-debug ${.TARGET} .endif diff --git a/sys/conf/ldscript.mips.64.cfe b/sys/conf/ldscript.mips.64.cfe new file mode 100644 index 00000000000..027456de1ca --- /dev/null +++ b/sys/conf/ldscript.mips.64.cfe @@ -0,0 +1,320 @@ +/*- + * Copyright (c) 2001, 2004, 2008, Juniper Networks, Inc. + * 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 Juniper Networks, Inc. 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 JUNIPER NETWORKS 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 JUNIPER NETWORKS 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. + * + * JNPR: ldscript.mips,v 1.3 2006/10/11 06:12:04 + * $FreeBSD$ + */ + +/* + * This linker script is needed to build a kernel for use by Broadcom CFE + * when loaded over TFTP; its ELF loader does not support backwards seek + * on network I/O streams. + * Furthermore, CFE will only load PT_LOAD segments, therefore the dynamic + * sections must be placed in their own segment. + */ + +OUTPUT_FORMAT("elf64-tradbigmips", "elf64-tradbigmips", "elf64-tradlittlemips") + +OUTPUT_ARCH(mips) +ENTRY(_start) +SEARCH_DIR(/usr/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; +PROVIDE (_DYNAMIC = 0); +*/ + +PHDRS +{ + headers PT_PHDR FILEHDR PHDRS ; + interp PT_INTERP ; + text PT_LOAD ; + dynamic PT_LOAD ; + data PT_LOAD ; +} + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = KERNLOADADDR ; + .interp : { *(.interp) } :interp + .hash : { *(.hash) } :text + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : + { + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t.*) + } + .rela.text : + { + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t.*) + } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : + { + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r.*) + } + .rela.rodata : + { + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r.*) + } + .rel.data : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d.*) + } + .rela.data : + { + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d.*) + } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.sdata : + { + *(.rel.sdata) + *(.rel.sdata.*) + *(.rel.gnu.linkonce.s.*) + } + .rela.sdata : + { + *(.rela.sdata) + *(.rela.sdata.*) + *(.rela.gnu.linkonce.s.*) + } + .rel.sbss : + { + *(.rel.sbss) + *(.rel.sbss.*) + *(.rel.gnu.linkonce.sb.*) + } + .rela.sbss : + { + *(.rela.sbss) + *(.rela.sbss.*) + *(.rel.gnu.linkonce.sb.*) + } + .rel.sdata2 : + { + *(.rel.sdata2) + *(.rel.sdata2.*) + *(.rel.gnu.linkonce.s2.*) + } + .rela.sdata2 : + { + *(.rela.sdata2) + *(.rela.sdata2.*) + *(.rela.gnu.linkonce.s2.*) + } + .rel.sbss2 : + { + *(.rel.sbss2) + *(.rel.sbss2.*) + *(.rel.gnu.linkonce.sb2.*) + } + .rela.sbss2 : + { + *(.rela.sbss2) + *(.rela.sbss2.*) + *(.rela.gnu.linkonce.sb2.*) + } + .rel.bss : + { + *(.rel.bss) + *(.rel.bss.*) + *(.rel.gnu.linkonce.b.*) + } + .rela.bss : + { + *(.rela.bss) + *(.rela.bss.*) + *(.rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } :text =0x1000000 + .text : + { + *(.trap) + *(.text) + *(.text.*) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t.*) + } =0x1000000 + .fini : + { + KEEP (*(.fini)) + } =0x1000000 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .reginfo : { *(.reginfo) } + .sdata2 : { *(.sdata2) *(.sdata2.*) *(.gnu.linkonce.s2.*) } + .sbss2 : { *(.sbss2) *(.sbss2.*) *(.gnu.linkonce.sb2.*) } + . = ALIGN(0x2000) + (. & (0x2000 - 1)); + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } :data + .data1 : { *(.data1) } + .eh_frame : { KEEP (*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .plt : { *(.plt) } + _gp = ALIGN(16) + 0x7ff0; + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } :dynamic + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : + { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : + { + PROVIDE (__sbss_start = .); + PROVIDE (___sbss_start = .); + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + *(.scommon) + PROVIDE (__sbss_end = .); + PROVIDE (___sbss_end = .); + } + .bss : + { + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(64 / 8); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} diff --git a/sys/conf/ldscript.mips.octeon1.64 b/sys/conf/ldscript.mips.octeon1.64 index aaef94579c0..ab2cef0dfea 100644 --- a/sys/conf/ldscript.mips.octeon1.64 +++ b/sys/conf/ldscript.mips.octeon1.64 @@ -7,24 +7,29 @@ ENTRY(_start) __DYNAMIC = 0; PROVIDE (_DYNAMIC = 0); +PHDRS { + text PT_LOAD FLAGS(0x7); +} + SECTIONS { . = KERNLOADADDR + SIZEOF_HEADERS; - .text . : { + .text : { *(.text) *(.dynamic) etext = .; _etext = .; . = ALIGN(0x2000); - } + } : text - .rodata ALIGN(0x2000) : { + . = ALIGN(0x2000); + .rodata : { _fdata = .; *(.rodata) . = ALIGN(32); } - .data . : { + .data : { _rwdata = .; *(.data) . = ALIGN(32); @@ -33,15 +38,15 @@ SECTIONS { _gp = (. + 0x8000); - .sdata . : { + .sdata : { _small_start = .; *(.sdata) . = ALIGN(32); edata = .; _edata = .; - } + } : text - .sbss . : { + .sbss : { __bss_start = .; _fbss = .; *(.sbss) *(.scommon) @@ -49,7 +54,7 @@ SECTIONS { . = ALIGN(32); } - .bss . : { + .bss : { *(.bss) *(COMMON) . = ALIGN(32); diff --git a/sys/conf/makeLINT.mk b/sys/conf/makeLINT.mk index e7ca9092193..049d63be399 100644 --- a/sys/conf/makeLINT.mk +++ b/sys/conf/makeLINT.mk @@ -17,3 +17,6 @@ LINT: ${NOTES} ../../conf/makeLINT.sed echo "ident ${.TARGET}-VIMAGE" >> ${.TARGET}-VIMAGE echo "options VIMAGE" >> ${.TARGET}-VIMAGE .endif +.if ${TARGET} == "powerpc" + echo "machine ${TARGET} ${TARGET_ARCH}" >> ${.TARGET} +.endif diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh index cabee5a932b..6fe0a639a54 100644 --- a/sys/conf/newvers.sh +++ b/sys/conf/newvers.sh @@ -38,16 +38,16 @@ if [ "X${BRANCH_OVERRIDE}" != "X" ]; then fi RELEASE="${REVISION}-${BRANCH}" VERSION="${TYPE} ${RELEASE}" +SYSDIR=$(dirname $0)/.. if [ "X${PARAMFILE}" != "X" ]; then RELDATE=$(awk '/__FreeBSD_version.*propagated to newvers/ {print $3}' \ ${PARAMFILE}) else RELDATE=$(awk '/__FreeBSD_version.*propagated to newvers/ {print $3}' \ - $(dirname $0)/../sys/param.h) + ${SYSDIR}/sys/param.h) fi - b=share/examples/etc/bsd-style-copyright year=`date '+%Y'` # look for copyright template @@ -87,51 +87,43 @@ touch version v=`cat version` u=${USER:-root} d=`pwd` h=${HOSTNAME:-`hostname`} t=`date` i=`${MAKE:-make} -V KERN_IDENT` -case "$d" in -*/sys/*) - SRCDIR=${d##*obj} - if [ -n "$MACHINE" ]; then - SRCDIR=${SRCDIR##/$MACHINE} +for dir in /bin /usr/bin /usr/local/bin; do + if [ -d "${SYSDIR}/.svn" -a -x "${dir}/svnversion" ] ; then + svnversion=${dir}/svnversion + break fi - SRCDIR=${SRCDIR%%/sys/*} - - for dir in /bin /usr/bin /usr/local/bin; do - if [ -d "${SRCDIR}/sys/.svn" -a -x "${dir}/svnversion" ] ; then - svnversion=${dir}/svnversion - break - fi - if [ -d "${SRCDIR}/.git" -a -x "${dir}/git" ] ; then - git_cmd="${dir}/git --git-dir=${SRCDIR}/.git" - break - fi - done - - if [ -n "$svnversion" ] ; then - svn=" r`cd ${SRCDIR}/sys && $svnversion`" + if [ -d "${SYSDIR}/../.git" -a -x "${dir}/git" ] ; then + git_cmd="${dir}/git --git-dir=${SYSDIR}/../.git" + break fi - if [ -n "$git_cmd" ] ; then - git=`$git_cmd rev-parse --verify --short HEAD 2>/dev/null` - svn=`$git_cmd svn find-rev $git 2>/dev/null` - if [ -n "$svn" ] ; then +done + +if [ -n "$svnversion" ] ; then + echo "$svnversion" + svn=" r`cd ${SYSDIR} && $svnversion`" +fi + +if [ -n "$git_cmd" ] ; then + git=`$git_cmd rev-parse --verify --short HEAD 2>/dev/null` + svn=`$git_cmd svn find-rev $git 2>/dev/null` + if [ -n "$svn" ] ; then + svn=" r${svn}" + git="=${git}" + else + svn=`$git_cmd log | fgrep 'git-svn-id:' | head -1 | \ + sed -n 's/^.*@\([0-9][0-9]*\).*$/\1/p'` + if [ -n $svn ] ; then svn=" r${svn}" - git="=${git}" + git="+${git}" else - svn=`$git_cmd log | fgrep 'git-svn-id:' | head -1 | \ - sed -n 's/^.*@\([0-9][0-9]*\).*$/\1/p'` - if [ -n $svn ] ; then - svn=" r${svn}" - git="+${git}" - else - git=" ${git}" - fi - fi - if $git_cmd --work-tree=${SRCDIR} diff-index \ - --name-only HEAD | read dummy; then - git="${git}-dirty" + git=" ${git}" fi fi - ;; -esac + if $git_cmd --work-tree=${SYSDIR}/.. diff-index \ + --name-only HEAD | read dummy; then + git="${git}-dirty" + fi +fi cat << EOF > vers.c $COPYRIGHT diff --git a/sys/conf/options b/sys/conf/options index b12290a0b56..75e2024b275 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -696,6 +696,7 @@ ED_SIC opt_ed.h # bce driver BCE_DEBUG opt_bce.h +BCE_NVRAM_WRITE_SUPPORT opt_bce.h SOCKBUF_DEBUG opt_global.h diff --git a/sys/conf/options.arm b/sys/conf/options.arm index 219b17fced3..3f9df6bf008 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -31,8 +31,11 @@ STARTUP_PAGETABLE_ADDR opt_global.h XSCALE_CACHE_READ_WRITE_ALLOCATE opt_global.h XSACLE_DISABLE_CCNT opt_timer.h VERBOSE_INIT_ARM opt_global.h +AT91_ATE_USE_RMII opt_at91.h AT91_BWCT opt_at91.h AT91_TSC opt_at91.h AT91_KWIKBYTE opt_at91.h +AT91_MCI_HAS_4WIRE opt_at91.h +AT91_MCI_SLOT_B opt_at91.h CPU_FA526 opt_global.h CPU_FA626TE opt_global.h diff --git a/sys/contrib/dev/acpica/acpica_prep.sh b/sys/contrib/dev/acpica/acpica_prep.sh index 8109381650f..a88d28104ba 100755 --- a/sys/contrib/dev/acpica/acpica_prep.sh +++ b/sys/contrib/dev/acpica/acpica_prep.sh @@ -22,8 +22,8 @@ fulldirs="common compiler debugger disassembler dispatcher events \ stripdirs="acpisrc acpixtract examples generate os_specific tests" stripfiles="Makefile README acintel.h aclinux.h acmsvc.h acnetbsd.h \ acos2.h accygwin.h acefi.h acwin.h acwin64.h aeexec.c \ - aehandlers.c aemain.c aetables.c osunixdir.c readme.txt \ - utclib.c" + aehandlers.c aemain.c aetables.c aetables.h osunixdir.c \ + readme.txt utclib.c" # include files to canonify src_headers="acapps.h accommon.h acconfig.h acdebug.h acdisasm.h \ @@ -33,8 +33,8 @@ src_headers="acapps.h accommon.h acconfig.h acdebug.h acdisasm.h \ acresrc.h acrestyp.h acstruct.h actables.h actbl.h actbl1.h \ actbl2.h actypes.h acutils.h amlcode.h amlresrc.h \ platform/acenv.h platform/acfreebsd.h platform/acgcc.h" -comp_headers="aslcompiler.h asldefine.h aslglobal.h asltypes.h \ - dtcompiler.h dttemplate.h" +comp_headers="aslcompiler.h asldefine.h aslglobal.h aslmessages.h \ + asltypes.h dtcompiler.h dttemplate.h" platform_headers="acfreebsd.h acgcc.h" # pre-clean diff --git a/sys/contrib/dev/acpica/changes.txt b/sys/contrib/dev/acpica/changes.txt index 6ac171f2fb6..21538415534 100644 --- a/sys/contrib/dev/acpica/changes.txt +++ b/sys/contrib/dev/acpica/changes.txt @@ -1,3 +1,127 @@ +---------------------------------------- +13 October 2010. Summary of changes for version 20101013: + +This release is available at www.acpica.org/downloads + +1) ACPI CA Core Subsystem: + +Added support to clear the PCIEXP_WAKE event. When clearing ACPI events, now +clear the PCIEXP_WAKE_STS bit in the ACPI PM1 Status Register, via +HwClearAcpiStatus. Original change from Colin King. ACPICA BZ 880. + +Changed the type of the predefined namespace object _TZ from ThermalZone to +Device. This was found to be confusing to the host software that processes +the various thermal zones, since _TZ is not really a ThermalZone. However, a +Notify() can still be performed on it. ACPICA BZ 876. Suggestion from Rui +Zhang. + +Added Windows Vista SP2 to the list of supported _OSI strings. The actual +string is "Windows 2006 SP2". + +Eliminated duplicate code in AcpiUtExecute* functions. Now that the nsrepair +code automatically repairs _HID-related strings, this type of code is no +longer needed in Execute_HID, Execute_CID, and Execute_UID. ACPICA BZ 878. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + Current Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL: Implemented additional compile-time validation for _HID strings. The +non-hex prefix (such as "PNP" or "ACPI") must be uppercase, and the length of +the string must be exactly seven or eight characters. For both _HID and _CID +strings, all characters must be alphanumeric. ACPICA BZ 874. + +iASL: Allow certain "null" resource descriptors. Some BIOS code creates +descriptors that are mostly or all zeros, with the expectation that they will +be filled in at runtime. iASL now allows this as long as there is a "resource +tag" (name) associated with the descriptor, which gives the ASL a handle +needed to modify the descriptor. ACPICA BZ 873. + +Added single-thread support to the generic Unix application OSL. Primarily +for iASL support, this change removes the use of semaphores in the single- +threaded ACPICA tools/applications - increasing performance. The +_MULTI_THREADED option was replaced by the (reverse) ACPI_SINGLE_THREADED +option. ACPICA BZ 879. + +AcpiExec: several fixes for the 64-bit version. Adds XSDT support and support +for 64-bit DSDT/FACS addresses in the FADT. Lin Ming. + +iASL: Moved all compiler messages to a new file, aslmessages.h. + +---------------------------------------- +15 September 2010. Summary of changes for version 20100915: + +This release is available at www.acpica.org/downloads + +1) ACPI CA Core Subsystem: + +Removed the AcpiOsDerivePciId OSL interface. The various host implementations +of this function were not OS-dependent and are now obsolete and can be +removed from all host OSLs. This function has been replaced by +AcpiHwDerivePciId, which is now part of the ACPICA core code. +AcpiHwDerivePciId has been implemented without recursion. Adds one new +module, hwpci.c. ACPICA BZ 857. + +Implemented a dynamic repair for _HID and _CID strings. The following +problems are now repaired at runtime: 1) Remove a leading asterisk in the +string, and 2) the entire string is uppercased. Both repairs are in +accordance with the ACPI specification and will simplify host driver code. +ACPICA BZ 871. + +The ACPI_THREAD_ID type is no longer configurable, internally it is now +always UINT64. This simplifies the ACPICA code, especially any printf output. +UINT64 is the only common data type for all thread_id types across all +operating systems. It is now up to the host OSL to cast the native thread_id +type to UINT64 before returning the value to ACPICA (via AcpiOsGetThreadId). +Lin Ming, Bob Moore. + +Added the ACPI_INLINE type to enhance the ACPICA configuration. The "inline" +keyword is not standard across compilers, and this type allows inline to be +configured on a per-compiler basis. Lin Ming. + +Made the system global AcpiGbl_SystemAwakeAndRunning publically available. +Added an extern for this boolean in acpixf.h. Some hosts utilize this value +during suspend/restore operations. ACPICA BZ 869. + +All code that implements error/warning messages with the "ACPI:" prefix has +been moved to a new module, utxferror.c. + +The UINT64_OVERLAY was moved to utmath.c, which is the only module where it +is used. ACPICA BZ 829. Lin Ming, Bob Moore. + +Example Code and Data Size: These are the sizes for the OS-independent +acpica.lib produced by the Microsoft Visual C++ 6.0 32-bit compiler. The +debug version of the code includes the debug output trace mechanism and has a +much larger code and data size. + + Previous Release: + Non-Debug Version: 89.1K Code, 19.0K Data, 108.1K Total + Debug Version: 165.1K Code, 51.9K Data, 217.0K Total + Current Release: + Non-Debug Version: 89.9K Code, 19.0K Data, 108.9K Total + Debug Version: 166.3K Code, 52.1K Data, 218.4K Total + +2) iASL Compiler/Disassembler and Tools: + +iASL/Disassembler: Write ACPI errors to stderr instead of the output file. +This keeps the output files free of random error messages that may originate +from within the namespace/interpreter code. Used this opportunity to merge +all ACPI:-style messages into a single new module, utxferror.c. ACPICA BZ +866. Lin Ming, Bob Moore. + +Tools: update some printfs for ansi warnings on size_t. Handle width change +of size_t on 32-bit versus 64-bit generations. Lin Ming. + ---------------------------------------- 06 August 2010. Summary of changes for version 20100806: diff --git a/sys/contrib/dev/acpica/common/adfile.c b/sys/contrib/dev/acpica/common/adfile.c index d72f36900aa..f1480682610 100644 --- a/sys/contrib/dev/acpica/common/adfile.c +++ b/sys/contrib/dev/acpica/common/adfile.c @@ -126,13 +126,13 @@ /* Local prototypes */ -INT32 +static INT32 AdWriteBuffer ( char *Filename, char *Buffer, UINT32 Length); -char FilenameBuf[20]; +static char FilenameBuf[20]; /****************************************************************************** @@ -190,7 +190,7 @@ AdGenerateFilename ( * ******************************************************************************/ -INT32 +static INT32 AdWriteBuffer ( char *Filename, char *Buffer, diff --git a/sys/contrib/dev/acpica/common/adisasm.c b/sys/contrib/dev/acpica/common/adisasm.c index da754a09219..2ca24d8b734 100644 --- a/sys/contrib/dev/acpica/common/adisasm.c +++ b/sys/contrib/dev/acpica/common/adisasm.c @@ -147,18 +147,18 @@ LsSetupNsList ( /* Local prototypes */ -void +static void AdCreateTableHeader ( char *Filename, ACPI_TABLE_HEADER *Table); -ACPI_STATUS +static ACPI_STATUS AdDeferredParse ( ACPI_PARSE_OBJECT *Op, UINT8 *Aml, UINT32 AmlLength); -ACPI_STATUS +static ACPI_STATUS AdParseDeferredOps ( ACPI_PARSE_OBJECT *Root); @@ -612,10 +612,10 @@ AdDisassemblerHeader ( /* Header and input table info */ - AcpiOsPrintf ("/*\n * Intel ACPI Component Architecture\n"); - AcpiOsPrintf (" * AML Disassembler version %8.8X\n", ACPI_CA_VERSION); + AcpiOsPrintf ("/*\n"); + AcpiOsPrintf (ACPI_COMMON_HEADER ("AML Disassembler", " * ")); - AcpiOsPrintf (" *\n * Disassembly of %s, %s", Filename, ctime (&Timer)); + AcpiOsPrintf (" * Disassembly of %s, %s", Filename, ctime (&Timer)); AcpiOsPrintf (" *\n"); } @@ -634,7 +634,7 @@ AdDisassemblerHeader ( * *****************************************************************************/ -void +static void AdCreateTableHeader ( char *Filename, ACPI_TABLE_HEADER *Table) @@ -781,7 +781,7 @@ AdDisplayTables ( * *****************************************************************************/ -ACPI_STATUS +static ACPI_STATUS AdDeferredParse ( ACPI_PARSE_OBJECT *Op, UINT8 *Aml, @@ -904,7 +904,7 @@ AdDeferredParse ( * *****************************************************************************/ -ACPI_STATUS +static ACPI_STATUS AdParseDeferredOps ( ACPI_PARSE_OBJECT *Root) { diff --git a/sys/contrib/dev/acpica/common/adwalk.c b/sys/contrib/dev/acpica/common/adwalk.c index c30ad6a4932..8c45609f08f 100644 --- a/sys/contrib/dev/acpica/common/adwalk.c +++ b/sys/contrib/dev/acpica/common/adwalk.c @@ -792,6 +792,7 @@ AcpiDmXrefDescendingOp ( ACPI_PARSE_OBJECT *NextOp; ACPI_NAMESPACE_NODE *Node; ACPI_OPERAND_OBJECT *Object; + UINT32 ParamCount = 0; WalkState = Info->WalkState; @@ -880,18 +881,13 @@ AcpiDmXrefDescendingOp ( if (Object) { ObjectType2 = Object->Common.Type; + if (ObjectType2 == ACPI_TYPE_METHOD) + { + ParamCount = Object->Method.ParamCount; + } } - if (ObjectType2 == ACPI_TYPE_METHOD) - { - AcpiDmAddToExternalList (Op, Path, ACPI_TYPE_METHOD, - Object->Method.ParamCount); - } - else - { - AcpiDmAddToExternalList (Op, Path, (UINT8) ObjectType2, 0); - } - + AcpiDmAddToExternalList (Op, Path, (UINT8) ObjectType2, ParamCount); Op->Common.Node = Node; } else diff --git a/sys/contrib/dev/acpica/common/dmrestag.c b/sys/contrib/dev/acpica/common/dmrestag.c index 70ded1de866..ed2a7e119b9 100644 --- a/sys/contrib/dev/acpica/common/dmrestag.c +++ b/sys/contrib/dev/acpica/common/dmrestag.c @@ -704,8 +704,8 @@ AcpiDmUpdateResourceName ( Name[0] = '_'; Name[1] = AcpiGbl_Prefix[AcpiGbl_NextPrefix]; - Name[2] = AcpiUtHexToAsciiChar (AcpiGbl_NextResourceId, 4); - Name[3] = AcpiUtHexToAsciiChar (AcpiGbl_NextResourceId, 0); + Name[2] = AcpiUtHexToAsciiChar ((UINT64) AcpiGbl_NextResourceId, 4); + Name[3] = AcpiUtHexToAsciiChar ((UINT64) AcpiGbl_NextResourceId, 0); /* Update globals for next name */ diff --git a/sys/contrib/dev/acpica/common/getopt.c b/sys/contrib/dev/acpica/common/getopt.c index b4a5b9e1e1d..34a66ee5669 100644 --- a/sys/contrib/dev/acpica/common/getopt.c +++ b/sys/contrib/dev/acpica/common/getopt.c @@ -126,7 +126,6 @@ int AcpiGbl_Opterr = 1; int AcpiGbl_Optind = 1; -int AcpiGbl_Optopt; char *AcpiGbl_Optarg; @@ -171,9 +170,7 @@ AcpiGetopt( /* Get the option */ - CurrentChar = - AcpiGbl_Optopt = - argv[AcpiGbl_Optind][CurrentCharPtr]; + CurrentChar = argv[AcpiGbl_Optind][CurrentCharPtr]; /* Make sure that the option is legal */ diff --git a/sys/contrib/dev/acpica/compiler/aslanalyze.c b/sys/contrib/dev/acpica/compiler/aslanalyze.c index 1929b86a604..20a2e1bd0d8 100644 --- a/sys/contrib/dev/acpica/compiler/aslanalyze.c +++ b/sys/contrib/dev/acpica/compiler/aslanalyze.c @@ -166,7 +166,7 @@ static UINT32 AnGetInternalMethodReturnType ( ACPI_PARSE_OBJECT *Op); -BOOLEAN +static BOOLEAN AnIsResultUsed ( ACPI_PARSE_OBJECT *Op); @@ -656,6 +656,95 @@ AnMapObjTypeToBtype ( } +/******************************************************************************* + * + * FUNCTION: AnCheckId + * + * PARAMETERS: Op - Current parse op + * Type - HID or CID + * + * RETURN: None + * + * DESCRIPTION: Perform various checks on _HID and _CID strings. Only limited + * checks can be performed on _CID strings. + * + ******************************************************************************/ + +#define ASL_TYPE_HID 0 +#define ASL_TYPE_CID 1 +#include + +static void +AnCheckId ( + ACPI_PARSE_OBJECT *Op, + ACPI_NAME Type) +{ + UINT32 i; + ACPI_SIZE Length; + UINT32 AlphaPrefixLength; + + + if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) + { + return; + } + + Length = strlen (Op->Asl.Value.String); + + /* + * If _HID/_CID is a string, all characters must be alphanumeric. + * One of the things we want to catch here is the use of + * a leading asterisk in the string -- an odd construct + * that certain platform manufacturers are fond of. + */ + for (i = 0; Op->Asl.Value.String[i]; i++) + { + if (!isalnum ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, + Op, Op->Asl.Value.String); + break; + } + } + + if (Type == ASL_TYPE_CID) + { + /* _CID strings are bus-specific, no more checks can be performed */ + + return; + } + + /* _HID String must be of the form "XXX####" or "ACPI####" */ + + if ((Length < 7) || (Length > 8)) + { + AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, + Op, Op->Asl.Value.String); + return; + } + + /* _HID Length is valid, now check for uppercase (first 3 or 4 chars) */ + + AlphaPrefixLength = 3; + if (Length >= 8) + { + AlphaPrefixLength = 4; + } + + /* Ensure the alphabetic prefix is all uppercase */ + + for (i = 0; (i < AlphaPrefixLength) && Op->Asl.Value.String[i]; i++) + { + if (!isupper ((int) Op->Asl.Value.String[i])) + { + AslError (ASL_ERROR, ASL_MSG_UPPER_CASE, + Op, &Op->Asl.Value.String[i]); + break; + } + } +} + + /******************************************************************************* * * FUNCTION: AnMethodAnalysisWalkBegin @@ -983,23 +1072,29 @@ AnMethodAnalysisWalkBegin ( if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg)) { Next = Op->Asl.Child->Asl.Next; - if (Next->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) + AnCheckId (Next, ASL_TYPE_HID); + } + + /* Special typechecking for _CID */ + + else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg)) + { + Next = Op->Asl.Child->Asl.Next; + + if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || + (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) { - /* - * _HID is a string, all characters must be alphanumeric. - * One of the things we want to catch here is the use of - * a leading asterisk in the string. - */ - for (i = 0; Next->Asl.Value.String[i]; i++) + Next = Next->Asl.Child; + while (Next) { - if (!isalnum ((int) Next->Asl.Value.String[i])) - { - AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, - Next, Next->Asl.Value.String); - break; - } + AnCheckId (Next, ASL_TYPE_CID); + Next = Next->Asl.Next; } } + else + { + AnCheckId (Next, ASL_TYPE_CID); + } } break; @@ -1754,7 +1849,7 @@ AnOperandTypecheckWalkEnd ( * ******************************************************************************/ -BOOLEAN +static BOOLEAN AnIsResultUsed ( ACPI_PARSE_OBJECT *Op) { @@ -1862,6 +1957,7 @@ AnOtherSemanticAnalysisWalkBegin ( if (Op->Asl.AmlOpcode == AML_DIVIDE_OP) { if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) && + (PrevArgNode) && (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO)) { AslError (ASL_WARNING, ASL_MSG_RESULT_NOT_USED, Op, Op->Asl.ExternalName); diff --git a/sys/contrib/dev/acpica/compiler/aslcodegen.c b/sys/contrib/dev/acpica/compiler/aslcodegen.c index 6821a69e492..98f2b7fb62d 100644 --- a/sys/contrib/dev/acpica/compiler/aslcodegen.c +++ b/sys/contrib/dev/acpica/compiler/aslcodegen.c @@ -513,11 +513,11 @@ CgWriteTableHeader ( /* Compiler ID */ - strncpy (TableHeader.AslCompilerId, CompilerCreatorId, 4); + strncpy (TableHeader.AslCompilerId, ASL_CREATOR_ID, 4); /* Compiler version */ - TableHeader.AslCompilerRevision = CompilerCreatorRevision; + TableHeader.AslCompilerRevision = ASL_REVISION; /* Table length. Checksum zero for now, will rewrite later */ diff --git a/sys/contrib/dev/acpica/compiler/aslcompile.c b/sys/contrib/dev/acpica/compiler/aslcompile.c index 00fa31dabaf..d9421c01855 100644 --- a/sys/contrib/dev/acpica/compiler/aslcompile.c +++ b/sys/contrib/dev/acpica/compiler/aslcompile.c @@ -117,6 +117,7 @@ #include #include #include +#include #define _COMPONENT ACPI_COMPILER ACPI_MODULE_NAME ("aslcompile") @@ -127,12 +128,12 @@ static void CmFlushSourceCode ( void); -void +static void FlConsumeAnsiComment ( ASL_FILE_INFO *FileInfo, ASL_FILE_STATUS *Status); -void +static void FlConsumeNewComment ( ASL_FILE_INFO *FileInfo, ASL_FILE_STATUS *Status); @@ -155,6 +156,7 @@ AslCompilerSignon ( UINT32 FileId) { char *Prefix = ""; + char *UtilityName; /* Set line prefix depending on the destination file type */ @@ -192,36 +194,21 @@ AslCompilerSignon ( break; } - /* - * Compiler signon with copyright - */ - FlPrintFile (FileId, - "%s\n%s%s\n%s", - Prefix, - Prefix, IntelAcpiCA, - Prefix); - /* Running compiler or disassembler? */ if (Gbl_DisasmFlag) { - FlPrintFile (FileId, - "%s", DisassemblerId); + UtilityName = AML_DISASSEMBLER_NAME; } else { - FlPrintFile (FileId, - "%s", CompilerId); + UtilityName = ASL_COMPILER_NAME; } - /* Version, copyright, compliance */ + /* Compiler signon with copyright */ - FlPrintFile (FileId, - " version %X\n%s%s\n%s%s\n%s\n", - (UINT32) ACPI_CA_VERSION, - Prefix, CompilerCopyright, - Prefix, CompilerCompliance, - Prefix); + FlPrintFile (FileId, "%s\n", Prefix); + FlPrintFile (FileId, ACPI_COMMON_HEADER (UtilityName, Prefix)); } @@ -345,7 +332,7 @@ CmFlushSourceCode ( * ******************************************************************************/ -void +static void FlConsumeAnsiComment ( ASL_FILE_INFO *FileInfo, ASL_FILE_STATUS *Status) @@ -389,7 +376,7 @@ FlConsumeAnsiComment ( } -void +static void FlConsumeNewComment ( ASL_FILE_INFO *FileInfo, ASL_FILE_STATUS *Status) diff --git a/sys/contrib/dev/acpica/compiler/aslcompiler.h b/sys/contrib/dev/acpica/compiler/aslcompiler.h index 91ea273d707..a0f01a93bac 100644 --- a/sys/contrib/dev/acpica/compiler/aslcompiler.h +++ b/sys/contrib/dev/acpica/compiler/aslcompiler.h @@ -147,6 +147,7 @@ #include #include +#include #include @@ -686,6 +687,10 @@ ACPI_STATUS LsDisplayNamespace ( void); +void +LsSetupNsList ( + void *Handle); + /* * aslutils - common compiler utilites @@ -791,7 +796,8 @@ RsSmallAddressCheck ( ACPI_PARSE_OBJECT *MinOp, ACPI_PARSE_OBJECT *MaxOp, ACPI_PARSE_OBJECT *LengthOp, - ACPI_PARSE_OBJECT *AlignOp); + ACPI_PARSE_OBJECT *AlignOp, + ACPI_PARSE_OBJECT *Op); void RsLargeAddressCheck ( @@ -803,7 +809,8 @@ RsLargeAddressCheck ( ACPI_PARSE_OBJECT *MinOp, ACPI_PARSE_OBJECT *MaxOp, ACPI_PARSE_OBJECT *LengthOp, - ACPI_PARSE_OBJECT *GranOp); + ACPI_PARSE_OBJECT *GranOp, + ACPI_PARSE_OBJECT *Op); UINT16 RsGetStringDataLength ( diff --git a/sys/contrib/dev/acpica/compiler/asldefine.h b/sys/contrib/dev/acpica/compiler/asldefine.h index 4cd8130b134..4105aeb0151 100644 --- a/sys/contrib/dev/acpica/compiler/asldefine.h +++ b/sys/contrib/dev/acpica/compiler/asldefine.h @@ -122,15 +122,13 @@ /* * Compiler versions and names */ -#define CompilerCreatorRevision ACPI_CA_VERSION +#define ASL_REVISION ACPI_CA_VERSION +#define ASL_COMPILER_NAME "ASL Optimizing Compiler" +#define AML_DISASSEMBLER_NAME "AML Disassembler" +#define ASL_INVOCATION_NAME "iasl" +#define ASL_CREATOR_ID "INTL" -#define IntelAcpiCA "Intel ACPI Component Architecture" -#define CompilerId "ASL Optimizing Compiler" -#define DisassemblerId "AML Disassembler" -#define CompilerCopyright "Copyright (c) 2000 - 2010 Intel Corporation" -#define CompilerCompliance "Supports ACPI Specification Revision 4.0a" -#define CompilerName "iasl" -#define CompilerCreatorId "INTL" +#define ASL_COMPLIANCE "Supports ACPI Specification Revision 4.0a" /* Configuration constants */ diff --git a/sys/contrib/dev/acpica/compiler/aslerror.c b/sys/contrib/dev/acpica/compiler/aslerror.c index 262dd200e1f..383e6174435 100644 --- a/sys/contrib/dev/acpica/compiler/aslerror.c +++ b/sys/contrib/dev/acpica/compiler/aslerror.c @@ -304,7 +304,7 @@ AePrintException ( if (Enode->LineNumber) { - fprintf (OutputFile, "%6u: ", Enode->LineNumber); + fprintf (OutputFile, " %6u: ", Enode->LineNumber); /* * Seek to the offset in the combined source file, read the source @@ -358,7 +358,7 @@ AePrintException ( { /* Decode the message ID */ - fprintf (OutputFile, "%s %4.4d -", + fprintf (OutputFile, "%s %4.4d - ", AslErrorLevel[Enode->Level], Enode->MessageId + ((Enode->Level+1) * 1000)); diff --git a/sys/contrib/dev/acpica/compiler/aslfiles.c b/sys/contrib/dev/acpica/compiler/aslfiles.c index 3557b1fccc6..55dc0b315fe 100644 --- a/sys/contrib/dev/acpica/compiler/aslfiles.c +++ b/sys/contrib/dev/acpica/compiler/aslfiles.c @@ -122,7 +122,7 @@ /* Local prototypes */ -FILE * +static FILE * FlOpenIncludeWithPrefix ( char *PrefixDir, char *Filename); @@ -546,7 +546,7 @@ FlAddIncludeDirectory ( * ******************************************************************************/ -FILE * +static FILE * FlOpenIncludeWithPrefix ( char *PrefixDir, char *Filename) diff --git a/sys/contrib/dev/acpica/compiler/asllisting.c b/sys/contrib/dev/acpica/compiler/asllisting.c index 9458b929215..28027bc9184 100644 --- a/sys/contrib/dev/acpica/compiler/asllisting.c +++ b/sys/contrib/dev/acpica/compiler/asllisting.c @@ -202,7 +202,7 @@ static void LsDoHexOutputAsl ( void); -ACPI_STATUS +static ACPI_STATUS LsTreeWriteWalk ( ACPI_PARSE_OBJECT *Op, UINT32 Level, @@ -222,7 +222,7 @@ LsTreeWriteWalk ( * ******************************************************************************/ -ACPI_STATUS +static ACPI_STATUS LsTreeWriteWalk ( ACPI_PARSE_OBJECT *Op, UINT32 Level, diff --git a/sys/contrib/dev/acpica/compiler/asllookup.c b/sys/contrib/dev/acpica/compiler/asllookup.c index 9dd6bf3b870..fd29c88d44a 100644 --- a/sys/contrib/dev/acpica/compiler/asllookup.c +++ b/sys/contrib/dev/acpica/compiler/asllookup.c @@ -180,11 +180,7 @@ LsDoOnePathname ( void *Context, void **ReturnValue); -void -LsSetupNsList ( - void *Handle); - -ACPI_PARSE_OBJECT * +static ACPI_PARSE_OBJECT * LkGetNameOp ( ACPI_PARSE_OBJECT *Op); @@ -623,7 +619,7 @@ LkObjectExists ( * ******************************************************************************/ -ACPI_PARSE_OBJECT * +static ACPI_PARSE_OBJECT * LkGetNameOp ( ACPI_PARSE_OBJECT *Op) { diff --git a/sys/contrib/dev/acpica/compiler/aslmain.c b/sys/contrib/dev/acpica/compiler/aslmain.c index 662742ff624..5abac749a8d 100644 --- a/sys/contrib/dev/acpica/compiler/aslmain.c +++ b/sys/contrib/dev/acpica/compiler/aslmain.c @@ -214,7 +214,7 @@ Options ( printf (" -cr Disable Resource Descriptor error checking\n"); printf (" -r Override table header Revision (1-255)\n"); - printf ("\nListings:\n"); + printf ("\nASL Listing Files:\n"); printf (" -l Create mixed listing file (ASL source and AML) (*.lst)\n"); printf (" -ln Create namespace file (*.nsp)\n"); printf (" -ls Create combined source file (expanded includes) (*.src)\n"); @@ -296,7 +296,8 @@ Usage ( void) { - printf ("Usage: %s [Options] [Files]\n\n", CompilerName); + printf ("%s\n", ASL_COMPLIANCE); + printf ("Usage: %s [Options] [Files]\n\n", ASL_INVOCATION_NAME); Options (); } @@ -462,6 +463,7 @@ AslDoOptions ( BOOLEAN IsResponseFile) { int j; + ACPI_STATUS Status; /* Get the command line options */ @@ -554,7 +556,12 @@ AslDoOptions ( case 'e': - AcpiDmAddToExternalFileList (AcpiGbl_Optarg); + Status = AcpiDmAddToExternalFileList (AcpiGbl_Optarg); + if (ACPI_FAILURE (Status)) + { + printf ("Could not add %s to external list\n", AcpiGbl_Optarg); + return (-1); + } break; @@ -601,7 +608,6 @@ AslDoOptions ( printf ("Unknown option: -h%s\n", AcpiGbl_Optarg); return (-1); } - break; case 'I': /* Add an include file search directory */ @@ -891,13 +897,14 @@ AslCommandLine ( char **argv) { int BadCommandLine = 0; + ACPI_STATUS Status; /* Minimum command line contains at least the command and an input file */ if (argc < 2) { - AslCompilerSignon (ASL_FILE_STDOUT); + printf (ACPI_COMMON_SIGNON (ASL_COMPILER_NAME)); Usage (); exit (1); } @@ -908,7 +915,11 @@ AslCommandLine ( if (Gbl_DoTemplates) { - DtCreateTemplates (Gbl_TemplateSignature); + Status = DtCreateTemplates (Gbl_TemplateSignature); + if (ACPI_FAILURE (Status)) + { + exit (-1); + } exit (1); } @@ -924,7 +935,7 @@ AslCommandLine ( if (Gbl_DoSignon) { - AslCompilerSignon (ASL_FILE_STDOUT); + printf (ACPI_COMMON_SIGNON (ASL_COMPILER_NAME)); } /* Abort if anything went wrong on the command line */ diff --git a/sys/contrib/dev/acpica/compiler/aslmessages.h b/sys/contrib/dev/acpica/compiler/aslmessages.h new file mode 100644 index 00000000000..04578003df9 --- /dev/null +++ b/sys/contrib/dev/acpica/compiler/aslmessages.h @@ -0,0 +1,436 @@ + +/****************************************************************************** + * + * Module Name: aslmessages.h - Compiler error/warning messages + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + *****************************************************************************/ + + +#ifndef __ASLMESSAGES_H +#define __ASLMESSAGES_H + + +#define ASL_WARNING 0 +#define ASL_WARNING2 1 +#define ASL_WARNING3 2 +#define ASL_ERROR 3 +#define ASL_REMARK 4 +#define ASL_OPTIMIZATION 5 +#define ASL_NUM_REPORT_LEVELS 6 + + +/* Values for all compiler messages */ + +typedef enum +{ + ASL_MSG_RESERVED = 0, + ASL_MSG_ALPHANUMERIC_STRING, + ASL_MSG_AML_NOT_IMPLEMENTED, + ASL_MSG_ARG_COUNT_HI, + ASL_MSG_ARG_COUNT_LO, + ASL_MSG_ARG_INIT, + ASL_MSG_BACKWARDS_OFFSET, + ASL_MSG_BITS_TO_BYTES, + ASL_MSG_BUFFER_LENGTH, + ASL_MSG_BYTES_TO_BITS, + ASL_MSG_CLOSE, + ASL_MSG_COMPILER_INTERNAL, + ASL_MSG_CONSTANT_EVALUATION, + ASL_MSG_CONSTANT_FOLDED, + ASL_MSG_CORE_EXCEPTION, + ASL_MSG_DEBUG_FILE_OPEN, + ASL_MSG_DEBUG_FILENAME, + ASL_MSG_DEPENDENT_NESTING, + ASL_MSG_DMA_CHANNEL, + ASL_MSG_DMA_LIST, + ASL_MSG_DUPLICATE_CASE, + ASL_MSG_DUPLICATE_ITEM, + ASL_MSG_EARLY_EOF, + ASL_MSG_ENCODING_LENGTH, + ASL_MSG_EX_INTERRUPT_LIST, + ASL_MSG_EX_INTERRUPT_LIST_MIN, + ASL_MSG_EX_INTERRUPT_NUMBER, + ASL_MSG_FIELD_ACCESS_WIDTH, + ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, + ASL_MSG_FIELD_UNIT_OFFSET, + ASL_MSG_INCLUDE_FILE_OPEN, + ASL_MSG_INPUT_FILE_OPEN, + ASL_MSG_INTEGER_LENGTH, + ASL_MSG_INTEGER_OPTIMIZATION, + ASL_MSG_INTERRUPT_LIST, + ASL_MSG_INTERRUPT_NUMBER, + ASL_MSG_INVALID_CONSTANT_OP, + ASL_MSG_INVALID_EISAID, + ASL_MSG_INVALID_ESCAPE, + ASL_MSG_INVALID_OPERAND, + ASL_MSG_INVALID_PERFORMANCE, + ASL_MSG_INVALID_PRIORITY, + ASL_MSG_INVALID_STRING, + ASL_MSG_INVALID_TARGET, + ASL_MSG_INVALID_TIME, + ASL_MSG_INVALID_TYPE, + ASL_MSG_INVALID_UUID, + ASL_MSG_LIST_LENGTH_LONG, + ASL_MSG_LIST_LENGTH_SHORT, + ASL_MSG_LISTING_FILE_OPEN, + ASL_MSG_LISTING_FILENAME, + ASL_MSG_LOCAL_INIT, + ASL_MSG_LONG_LINE, + ASL_MSG_MEMORY_ALLOCATION, + ASL_MSG_MISSING_ENDDEPENDENT, + ASL_MSG_MISSING_STARTDEPENDENT, + ASL_MSG_MULTIPLE_TYPES, + ASL_MSG_NAME_EXISTS, + ASL_MSG_NAME_OPTIMIZATION, + ASL_MSG_NESTED_COMMENT, + ASL_MSG_NO_CASES, + ASL_MSG_NO_RETVAL, + ASL_MSG_NO_WHILE, + ASL_MSG_NON_ASCII, + ASL_MSG_NOT_EXIST, + ASL_MSG_NOT_FOUND, + ASL_MSG_NOT_METHOD, + ASL_MSG_NOT_PARAMETER, + ASL_MSG_NOT_REACHABLE, + ASL_MSG_OPEN, + ASL_MSG_OUTPUT_FILE_OPEN, + ASL_MSG_OUTPUT_FILENAME, + ASL_MSG_PACKAGE_LENGTH, + ASL_MSG_READ, + ASL_MSG_RECURSION, + ASL_MSG_REGION_BUFFER_ACCESS, + ASL_MSG_REGION_BYTE_ACCESS, + ASL_MSG_RESERVED_ARG_COUNT_HI, + ASL_MSG_RESERVED_ARG_COUNT_LO, + ASL_MSG_RESERVED_METHOD, + ASL_MSG_RESERVED_OPERAND_TYPE, + ASL_MSG_RESERVED_RETURN_VALUE, + ASL_MSG_RESERVED_USE, + ASL_MSG_RESERVED_WORD, + ASL_MSG_RESOURCE_FIELD, + ASL_MSG_RESOURCE_INDEX, + ASL_MSG_RESOURCE_LIST, + ASL_MSG_RESOURCE_SOURCE, + ASL_MSG_RETURN_TYPES, + ASL_MSG_SCOPE_FWD_REF, + ASL_MSG_SCOPE_TYPE, + ASL_MSG_SEEK, + ASL_MSG_SINGLE_NAME_OPTIMIZATION, + ASL_MSG_SOME_NO_RETVAL, + ASL_MSG_SWITCH_TYPE, + ASL_MSG_SYNC_LEVEL, + ASL_MSG_SYNTAX, + ASL_MSG_TABLE_SIGNATURE, + ASL_MSG_TOO_MANY_TEMPS, + ASL_MSG_UNKNOWN_RESERVED_NAME, + ASL_MSG_UNREACHABLE_CODE, + ASL_MSG_UNSUPPORTED, + ASL_MSG_VENDOR_LIST, + ASL_MSG_WRITE, + ASL_MSG_MULTIPLE_DEFAULT, + ASL_MSG_TIMEOUT, + ASL_MSG_RESULT_NOT_USED, + ASL_MSG_NOT_REFERENCED, + ASL_MSG_NON_ZERO, + ASL_MSG_STRING_LENGTH, + ASL_MSG_SERIALIZED, + ASL_MSG_COMPILER_RESERVED, + ASL_MSG_NAMED_OBJECT_IN_WHILE, + ASL_MSG_LOCAL_OUTSIDE_METHOD, + ASL_MSG_ALIGNMENT, + ASL_MSG_ISA_ADDRESS, + ASL_MSG_INVALID_MIN_MAX, + ASL_MSG_INVALID_LENGTH, + ASL_MSG_INVALID_LENGTH_FIXED, + ASL_MSG_INVALID_GRANULARITY, + ASL_MSG_INVALID_GRAN_FIXED, + ASL_MSG_INVALID_ACCESS_SIZE, + ASL_MSG_INVALID_ADDR_FLAGS, + ASL_MSG_NULL_DESCRIPTOR, + ASL_MSG_UPPER_CASE, + ASL_MSG_HID_LENGTH, + ASL_MSG_INVALID_FIELD_NAME, + ASL_MSG_INTEGER_SIZE, + ASL_MSG_INVALID_HEX_INTEGER, + ASL_MSG_BUFFER_ELEMENT, + ASL_MSG_RESERVED_VALUE, + ASL_MSG_FLAG_VALUE, + ASL_MSG_ZERO_VALUE, + ASL_MSG_UNKNOWN_TABLE, + ASL_MSG_UNKNOWN_SUBTABLE, + ASL_MSG_OEM_TABLE + +} ASL_MESSAGE_IDS; + + +#ifdef ASL_EXCEPTIONS + +/* Actual message strings for each compiler message */ + +char *AslMessages [] = { +/* The zeroth message is reserved */ "", +/* ASL_MSG_ALPHANUMERIC_STRING */ "String must be entirely alphanumeric", +/* ASL_MSG_AML_NOT_IMPLEMENTED */ "Opcode is not implemented in compiler AML code generator", +/* ASL_MSG_ARG_COUNT_HI */ "Too many arguments", +/* ASL_MSG_ARG_COUNT_LO */ "Too few arguments", +/* ASL_MSG_ARG_INIT */ "Method argument is not initialized", +/* ASL_MSG_BACKWARDS_OFFSET */ "Invalid backwards offset", +/* ASL_MSG_BITS_TO_BYTES */ "Field offset is in bits, but a byte offset is required", +/* ASL_MSG_BUFFER_LENGTH */ "Effective AML buffer length is zero", +/* ASL_MSG_BYTES_TO_BITS */ "Field offset is in bytes, but a bit offset is required", +/* ASL_MSG_CLOSE */ "Could not close file", +/* ASL_MSG_COMPILER_INTERNAL */ "Internal compiler error", +/* ASL_MSG_CONSTANT_EVALUATION */ "Could not evaluate constant expression", +/* ASL_MSG_CONSTANT_FOLDED */ "Constant expression evaluated and reduced", +/* ASL_MSG_CORE_EXCEPTION */ "From ACPI CA Subsystem", +/* ASL_MSG_DEBUG_FILE_OPEN */ "Could not open debug file", +/* ASL_MSG_DEBUG_FILENAME */ "Could not create debug filename", +/* ASL_MSG_DEPENDENT_NESTING */ "Dependent function macros cannot be nested",\ +/* ASL_MSG_DMA_CHANNEL */ "Invalid DMA channel (must be 0-7)", +/* ASL_MSG_DMA_LIST */ "Too many DMA channels (8 max)", +/* ASL_MSG_DUPLICATE_CASE */ "Case value already specified", +/* ASL_MSG_DUPLICATE_ITEM */ "Duplicate value in list", +/* ASL_MSG_EARLY_EOF */ "Premature end-of-file reached", +/* ASL_MSG_ENCODING_LENGTH */ "Package length too long to encode", +/* ASL_MSG_EX_INTERRUPT_LIST */ "Too many interrupts (255 max)", +/* ASL_MSG_EX_INTERRUPT_LIST_MIN */ "Too few interrupts (1 minimum required)", +/* ASL_MSG_EX_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 32 bits)", +/* ASL_MSG_FIELD_ACCESS_WIDTH */ "Access width is greater than region size", +/* ASL_MSG_FIELD_UNIT_ACCESS_WIDTH */ "Access width of Field Unit extends beyond region limit", +/* ASL_MSG_FIELD_UNIT_OFFSET */ "Field Unit extends beyond region limit", +/* ASL_MSG_INCLUDE_FILE_OPEN */ "Could not open include file", +/* ASL_MSG_INPUT_FILE_OPEN */ "Could not open input file", +/* ASL_MSG_INTEGER_LENGTH */ "64-bit integer in 32-bit table, truncating", +/* ASL_MSG_INTEGER_OPTIMIZATION */ "Integer optimized to single-byte AML opcode", +/* ASL_MSG_INTERRUPT_LIST */ "Too many interrupts (16 max)", +/* ASL_MSG_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 0-15)", +/* ASL_MSG_INVALID_CONSTANT_OP */ "Invalid operator in constant expression (not type 3/4/5)", +/* ASL_MSG_INVALID_EISAID */ "EISAID string must be of the form \"UUUXXXX\" (3 uppercase, 4 hex digits)", +/* ASL_MSG_INVALID_ESCAPE */ "Invalid or unknown escape sequence", +/* ASL_MSG_INVALID_OPERAND */ "Invalid operand", +/* ASL_MSG_INVALID_PERFORMANCE */ "Invalid performance/robustness value", +/* ASL_MSG_INVALID_PRIORITY */ "Invalid priority value", +/* ASL_MSG_INVALID_STRING */ "Invalid Hex/Octal Escape - Non-ASCII or NULL", +/* ASL_MSG_INVALID_TARGET */ "Target operand not allowed in constant expression", +/* ASL_MSG_INVALID_TIME */ "Time parameter too long (255 max)", +/* ASL_MSG_INVALID_TYPE */ "Invalid type", +/* ASL_MSG_INVALID_UUID */ "UUID string must be of the form \"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp\"", +/* ASL_MSG_LIST_LENGTH_LONG */ "Initializer list longer than declared package length", +/* ASL_MSG_LIST_LENGTH_SHORT */ "Initializer list shorter than declared package length", +/* ASL_MSG_LISTING_FILE_OPEN */ "Could not open listing file", +/* ASL_MSG_LISTING_FILENAME */ "Could not create listing filename", +/* ASL_MSG_LOCAL_INIT */ "Method local variable is not initialized", +/* ASL_MSG_LONG_LINE */ "Splitting long input line", +/* ASL_MSG_MEMORY_ALLOCATION */ "Memory allocation failure", +/* ASL_MSG_MISSING_ENDDEPENDENT */ "Missing EndDependentFn() macro in dependent resource list", +/* ASL_MSG_MISSING_STARTDEPENDENT */ "Missing StartDependentFn() macro in dependent resource list", +/* ASL_MSG_MULTIPLE_TYPES */ "Multiple types", +/* ASL_MSG_NAME_EXISTS */ "Name already exists in scope", +/* ASL_MSG_NAME_OPTIMIZATION */ "NamePath optimized", +/* ASL_MSG_NESTED_COMMENT */ "Nested comment found", +/* ASL_MSG_NO_CASES */ "No Case statements under Switch", +/* ASL_MSG_NO_RETVAL */ "Called method returns no value", +/* ASL_MSG_NO_WHILE */ "No enclosing While statement", +/* ASL_MSG_NON_ASCII */ "Invalid characters found in file", +/* ASL_MSG_NOT_EXIST */ "Object does not exist", +/* ASL_MSG_NOT_FOUND */ "Object not found or not accessible from scope", +/* ASL_MSG_NOT_METHOD */ "Not a control method, cannot invoke", +/* ASL_MSG_NOT_PARAMETER */ "Not a parameter, used as local only", +/* ASL_MSG_NOT_REACHABLE */ "Object is not accessible from this scope", +/* ASL_MSG_OPEN */ "Could not open file", +/* ASL_MSG_OUTPUT_FILE_OPEN */ "Could not open output AML file", +/* ASL_MSG_OUTPUT_FILENAME */ "Could not create output filename", +/* ASL_MSG_PACKAGE_LENGTH */ "Effective AML package length is zero", +/* ASL_MSG_READ */ "Could not read file", +/* ASL_MSG_RECURSION */ "Recursive method call", +/* ASL_MSG_REGION_BUFFER_ACCESS */ "Host Operation Region requires BufferAcc access", +/* ASL_MSG_REGION_BYTE_ACCESS */ "Host Operation Region requires ByteAcc access", +/* ASL_MSG_RESERVED_ARG_COUNT_HI */ "Reserved method has too many arguments", +/* ASL_MSG_RESERVED_ARG_COUNT_LO */ "Reserved method has too few arguments", +/* ASL_MSG_RESERVED_METHOD */ "Reserved name must be a control method", +/* ASL_MSG_RESERVED_OPERAND_TYPE */ "Invalid object type for reserved name", +/* ASL_MSG_RESERVED_RETURN_VALUE */ "Reserved method must return a value", +/* ASL_MSG_RESERVED_USE */ "Invalid use of reserved name", +/* ASL_MSG_RESERVED_WORD */ "Use of reserved name", +/* ASL_MSG_RESOURCE_FIELD */ "Resource field name cannot be used as a target", +/* ASL_MSG_RESOURCE_INDEX */ "Missing ResourceSourceIndex (required)", +/* ASL_MSG_RESOURCE_LIST */ "Too many resource items (internal error)", +/* ASL_MSG_RESOURCE_SOURCE */ "Missing ResourceSource string (required)", +/* ASL_MSG_RETURN_TYPES */ "Not all control paths return a value", +/* ASL_MSG_SCOPE_FWD_REF */ "Forward references from Scope operator not allowed", +/* ASL_MSG_SCOPE_TYPE */ "Existing object has invalid type for Scope operator", +/* ASL_MSG_SEEK */ "Could not seek file", +/* ASL_MSG_SINGLE_NAME_OPTIMIZATION */ "NamePath optimized to NameSeg (uses run-time search path)", +/* ASL_MSG_SOME_NO_RETVAL */ "Called method may not always return a value", +/* ASL_MSG_SWITCH_TYPE */ "Switch expression is not a static Integer/Buffer/String data type, defaulting to Integer", +/* ASL_MSG_SYNC_LEVEL */ "SyncLevel must be in the range 0-15", +/* ASL_MSG_SYNTAX */ "", +/* ASL_MSG_TABLE_SIGNATURE */ "Invalid Table Signature", +/* ASL_MSG_TOO_MANY_TEMPS */ "Method requires too many temporary variables (_T_x)", +/* ASL_MSG_UNKNOWN_RESERVED_NAME */ "Unknown reserved name", +/* ASL_MSG_UNREACHABLE_CODE */ "Statement is unreachable", +/* ASL_MSG_UNSUPPORTED */ "Unsupported feature", +/* ASL_MSG_VENDOR_LIST */ "Too many vendor data bytes (7 max)", +/* ASL_MSG_WRITE */ "Could not write file", +/* ASL_MSG_MULTIPLE_DEFAULT */ "More than one Default statement within Switch construct", +/* ASL_MSG_TIMEOUT */ "Possible operator timeout is ignored", +/* ASL_MSG_RESULT_NOT_USED */ "Result is not used, operator has no effect", +/* ASL_MSG_NOT_REFERENCED */ "Namespace object is not referenced", +/* ASL_MSG_NON_ZERO */ "Operand evaluates to zero", +/* ASL_MSG_STRING_LENGTH */ "String literal too long", +/* ASL_MSG_SERIALIZED */ "Control Method marked Serialized", +/* ASL_MSG_COMPILER_RESERVED */ "Use of compiler reserved name", +/* ASL_MSG_NAMED_OBJECT_IN_WHILE */ "Creating a named object in a While loop", +/* ASL_MSG_LOCAL_OUTSIDE_METHOD */ "Local or Arg used outside a control method", +/* ASL_MSG_ALIGNMENT */ "Must be a multiple of alignment/granularity value", +/* ASL_MSG_ISA_ADDRESS */ "Maximum 10-bit ISA address (0x3FF)", +/* ASL_MSG_INVALID_MIN_MAX */ "Address Min is greater than Address Max", +/* ASL_MSG_INVALID_LENGTH */ "Length is larger than Min/Max window", +/* ASL_MSG_INVALID_LENGTH_FIXED */ "Length is not equal to fixed Min/Max window", +/* ASL_MSG_INVALID_GRANULARITY */ "Granularity must be zero or a power of two minus one", +/* ASL_MSG_INVALID_GRAN_FIXED */ "Granularity must be zero for fixed Min/Max", +/* ASL_MSG_INVALID_ACCESS_SIZE */ "Invalid AccessSize (Maximum is 4 - QWord access)", +/* ASL_MSG_INVALID_ADDR_FLAGS */ "Invalid combination of Length and Min/Max fixed flags", +/* ASL_MSG_NULL_DESCRIPTOR */ "Min/Max/Length/Gran are all zero, but no resource tag", +/* ASL_MSG_UPPER_CASE */ "Non-hex letters must be upper case", +/* ASL_MSG_HID_LENGTH */ "_HID string must be exactly 7 or 8 characters", + +/* These messages are used by the data table compiler only */ + +/* ASL_MSG_INVALID_FIELD_NAME */ "Invalid Field Name", +/* ASL_MSG_INTEGER_SIZE */ "Integer too large for target", +/* ASL_MSG_INVALID_HEX_INTEGER */ "Invalid hex integer constant", +/* ASL_MSG_BUFFER_ELEMENT */ "Invalid element in buffer initializer list", +/* ASL_MSG_RESERVED_VALUE */ "Reserved field must be zero", +/* ASL_MSG_FLAG_VALUE */ "Flag value is too large", +/* ASL_MSG_ZERO_VALUE */ "Value must be non-zero", +/* ASL_MSG_UNKNOWN_TABLE */ "Unknown ACPI table signature", +/* ASL_MSG_UNKNOWN_SUBTABLE */ "Unknown subtable type", +/* ASL_MSG_OEM_TABLE */ "OEM table - unknown contents" + +}; + + +char *AslErrorLevel [ASL_NUM_REPORT_LEVELS] = { + "Warning ", + "Warning ", + "Warning ", + "Error ", + "Remark ", + "Optimize" +}; + +#define ASL_ERROR_LEVEL_LENGTH 8 /* Length of strings above */ + +#endif /* ASL_EXCEPTIONS */ + +#endif /* __ASLMESSAGES_H */ diff --git a/sys/contrib/dev/acpica/compiler/aslopcodes.c b/sys/contrib/dev/acpica/compiler/aslopcodes.c index b1a56921de3..d67efbe2f65 100644 --- a/sys/contrib/dev/acpica/compiler/aslopcodes.c +++ b/sys/contrib/dev/acpica/compiler/aslopcodes.c @@ -592,9 +592,9 @@ OpcDoEisaId ( /* Create ID big-endian first (bits are contiguous) */ BigEndianId = - (UINT32) (InString[0] - 0x40) << 26 | - (UINT32) (InString[1] - 0x40) << 21 | - (UINT32) (InString[2] - 0x40) << 16 | + (UINT32) ((UINT8) (InString[0] - 0x40)) << 26 | + (UINT32) ((UINT8) (InString[1] - 0x40)) << 21 | + (UINT32) ((UINT8) (InString[2] - 0x40)) << 16 | (UtHexCharToValue (InString[3])) << 12 | (UtHexCharToValue (InString[4])) << 8 | diff --git a/sys/contrib/dev/acpica/compiler/aslpredef.c b/sys/contrib/dev/acpica/compiler/aslpredef.c index f50138d6c0e..cb40bc9e279 100644 --- a/sys/contrib/dev/acpica/compiler/aslpredef.c +++ b/sys/contrib/dev/acpica/compiler/aslpredef.c @@ -117,8 +117,6 @@ #include #include "aslcompiler.y.h" -#include -#include #include diff --git a/sys/contrib/dev/acpica/compiler/aslresource.c b/sys/contrib/dev/acpica/compiler/aslresource.c index 25289f54a21..2cc4ea091a2 100644 --- a/sys/contrib/dev/acpica/compiler/aslresource.c +++ b/sys/contrib/dev/acpica/compiler/aslresource.c @@ -139,6 +139,7 @@ * NULL, means "zero value for alignment is * OK, and means 64K alignment" (for * Memory24 descriptor) + * Op - Parent Op for entire construct * * RETURN: None. Adds error messages to error log if necessary * @@ -158,7 +159,8 @@ RsSmallAddressCheck ( ACPI_PARSE_OBJECT *MinOp, ACPI_PARSE_OBJECT *MaxOp, ACPI_PARSE_OBJECT *LengthOp, - ACPI_PARSE_OBJECT *AlignOp) + ACPI_PARSE_OBJECT *AlignOp, + ACPI_PARSE_OBJECT *Op) { if (Gbl_NoResourceChecking) @@ -166,6 +168,34 @@ RsSmallAddressCheck ( return; } + /* + * Check for a so-called "null descriptor". These are descriptors that are + * created with most fields set to zero. The intent is that the descriptor + * will be updated/completed at runtime via a BufferField. + * + * If the descriptor does NOT have a resource tag, it cannot be referenced + * by a BufferField and we will flag this as an error. Conversely, if + * the descriptor has a resource tag, we will assume that a BufferField + * will be used to dynamically update it, so no error. + * + * A possible enhancement to this check would be to verify that in fact + * a BufferField is created using the resource tag, and perhaps even + * verify that a Store is performed to the BufferField. + * + * Note: for these descriptors, Alignment is allowed to be zero + */ + if (!Minimum && !Maximum && !Length) + { + if (!Op->Asl.ExternalName) + { + /* No resource tag. Descriptor is fixed and is also illegal */ + + AslError (ASL_ERROR, ASL_MSG_NULL_DESCRIPTOR, Op, NULL); + } + + return; + } + /* Special case for Memory24, values are compressed */ if (Type == ACPI_RESOURCE_NAME_MEMORY24) @@ -230,6 +260,7 @@ RsSmallAddressCheck ( * MaxOp - Original Op for Address Max * LengthOp - Original Op for address range * GranOp - Original Op for address granularity + * Op - Parent Op for entire construct * * RETURN: None. Adds error messages to error log if necessary * @@ -259,7 +290,8 @@ RsLargeAddressCheck ( ACPI_PARSE_OBJECT *MinOp, ACPI_PARSE_OBJECT *MaxOp, ACPI_PARSE_OBJECT *LengthOp, - ACPI_PARSE_OBJECT *GranOp) + ACPI_PARSE_OBJECT *GranOp, + ACPI_PARSE_OBJECT *Op) { if (Gbl_NoResourceChecking) @@ -267,6 +299,32 @@ RsLargeAddressCheck ( return; } + /* + * Check for a so-called "null descriptor". These are descriptors that are + * created with most fields set to zero. The intent is that the descriptor + * will be updated/completed at runtime via a BufferField. + * + * If the descriptor does NOT have a resource tag, it cannot be referenced + * by a BufferField and we will flag this as an error. Conversely, if + * the descriptor has a resource tag, we will assume that a BufferField + * will be used to dynamically update it, so no error. + * + * A possible enhancement to this check would be to verify that in fact + * a BufferField is created using the resource tag, and perhaps even + * verify that a Store is performed to the BufferField. + */ + if (!Minimum && !Maximum && !Length && !Granularity) + { + if (!Op->Asl.ExternalName) + { + /* No resource tag. Descriptor is fixed and is also illegal */ + + AslError (ASL_ERROR, ASL_MSG_NULL_DESCRIPTOR, Op, NULL); + } + + return; + } + /* Basic checks on Min/Max/Length */ if (Minimum > Maximum) diff --git a/sys/contrib/dev/acpica/compiler/aslrestype1.c b/sys/contrib/dev/acpica/compiler/aslrestype1.c index 32f2cfc1458..5f44c288d46 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype1.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype1.c @@ -224,7 +224,6 @@ RsDoMemory24Descriptor ( ACPI_PARSE_OBJECT *MinOp = NULL; ACPI_PARSE_OBJECT *MaxOp = NULL; ACPI_PARSE_OBJECT *LengthOp = NULL; - ACPI_PARSE_OBJECT *AlignOp = NULL; ASL_RESOURCE_NODE *Rnode; UINT32 i; @@ -270,7 +269,6 @@ RsDoMemory24Descriptor ( Descriptor->Memory24.Alignment = (UINT16) InitializerOp->Asl.Value.Integer; RsCreateByteField (InitializerOp, ACPI_RESTAG_ALIGNMENT, CurrentByteOffset + ASL_RESDESC_OFFSET (Memory24.Alignment)); - AlignOp = InitializerOp; break; case 4: /* Length */ @@ -302,7 +300,7 @@ RsDoMemory24Descriptor ( Descriptor->Memory24.Maximum, Descriptor->Memory24.AddressLength, Descriptor->Memory24.Alignment, - MinOp, MaxOp, LengthOp, NULL); + MinOp, MaxOp, LengthOp, NULL, Op); return (Rnode); } @@ -410,7 +408,7 @@ RsDoMemory32Descriptor ( Descriptor->Memory32.Maximum, Descriptor->Memory32.AddressLength, Descriptor->Memory32.Alignment, - MinOp, MaxOp, LengthOp, AlignOp); + MinOp, MaxOp, LengthOp, AlignOp, Op); return (Rnode); } diff --git a/sys/contrib/dev/acpica/compiler/aslrestype1i.c b/sys/contrib/dev/acpica/compiler/aslrestype1i.c index a2b80cbc5f3..05614f405c1 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype1i.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype1i.c @@ -439,7 +439,7 @@ RsDoIoDescriptor ( Descriptor->Io.Maximum, Descriptor->Io.AddressLength, Descriptor->Io.Alignment, - MinOp, MaxOp, LengthOp, AlignOp); + MinOp, MaxOp, LengthOp, AlignOp, Op); return (Rnode); } diff --git a/sys/contrib/dev/acpica/compiler/aslrestype2d.c b/sys/contrib/dev/acpica/compiler/aslrestype2d.c index db0a2a7b85d..5101db6c865 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype2d.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype2d.c @@ -347,12 +347,12 @@ RsDoDwordIoDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address32.Minimum, - Descriptor->Address32.Maximum, - Descriptor->Address32.AddressLength, - Descriptor->Address32.Granularity, + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, Descriptor->Address32.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + OptionIndex + StringLength; @@ -583,12 +583,12 @@ RsDoDwordMemoryDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address32.Minimum, - Descriptor->Address32.Maximum, - Descriptor->Address32.AddressLength, - Descriptor->Address32.Granularity, + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, Descriptor->Address32.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + OptionIndex + StringLength; @@ -801,12 +801,12 @@ RsDoDwordSpaceDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address32.Minimum, - Descriptor->Address32.Maximum, - Descriptor->Address32.AddressLength, - Descriptor->Address32.Granularity, + (UINT64) Descriptor->Address32.Minimum, + (UINT64) Descriptor->Address32.Maximum, + (UINT64) Descriptor->Address32.AddressLength, + (UINT64) Descriptor->Address32.Granularity, Descriptor->Address32.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS32) + OptionIndex + StringLength; diff --git a/sys/contrib/dev/acpica/compiler/aslrestype2e.c b/sys/contrib/dev/acpica/compiler/aslrestype2e.c index b75d174fac1..6051fe3c94b 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype2e.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype2e.c @@ -116,7 +116,6 @@ #include -#include "aslcompiler.y.h" #define _COMPONENT ACPI_COMPILER ACPI_MODULE_NAME ("aslrestype2e") @@ -295,7 +294,7 @@ RsDoExtendedIoDescriptor ( Descriptor->ExtAddress64.AddressLength, Descriptor->ExtAddress64.Granularity, Descriptor->ExtAddress64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + StringLength; return (Rnode); @@ -476,7 +475,7 @@ RsDoExtendedMemoryDescriptor ( Descriptor->ExtAddress64.AddressLength, Descriptor->ExtAddress64.Granularity, Descriptor->ExtAddress64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + StringLength; return (Rnode); @@ -639,7 +638,7 @@ RsDoExtendedSpaceDescriptor ( Descriptor->ExtAddress64.AddressLength, Descriptor->ExtAddress64.Granularity, Descriptor->ExtAddress64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_EXTENDED_ADDRESS64) + StringLength; return (Rnode); diff --git a/sys/contrib/dev/acpica/compiler/aslrestype2q.c b/sys/contrib/dev/acpica/compiler/aslrestype2q.c index cea12aa4912..2daa93fa117 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype2q.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype2q.c @@ -343,7 +343,7 @@ RsDoQwordIoDescriptor ( Descriptor->Address64.AddressLength, Descriptor->Address64.Granularity, Descriptor->Address64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + OptionIndex + StringLength; @@ -573,7 +573,7 @@ RsDoQwordMemoryDescriptor ( Descriptor->Address64.AddressLength, Descriptor->Address64.Granularity, Descriptor->Address64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + OptionIndex + StringLength; @@ -785,7 +785,7 @@ RsDoQwordSpaceDescriptor ( Descriptor->Address64.AddressLength, Descriptor->Address64.Granularity, Descriptor->Address64.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS64) + OptionIndex + StringLength; diff --git a/sys/contrib/dev/acpica/compiler/aslrestype2w.c b/sys/contrib/dev/acpica/compiler/aslrestype2w.c index fa0bb2226a1..1630e25eeba 100644 --- a/sys/contrib/dev/acpica/compiler/aslrestype2w.c +++ b/sys/contrib/dev/acpica/compiler/aslrestype2w.c @@ -338,12 +338,12 @@ RsDoWordIoDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address16.Minimum, - Descriptor->Address16.Maximum, - Descriptor->Address16.AddressLength, - Descriptor->Address16.Granularity, + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, Descriptor->Address16.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + OptionIndex + StringLength; @@ -544,12 +544,12 @@ RsDoWordBusNumberDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address16.Minimum, - Descriptor->Address16.Maximum, - Descriptor->Address16.AddressLength, - Descriptor->Address16.Granularity, + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, Descriptor->Address16.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + OptionIndex + StringLength; @@ -761,12 +761,12 @@ RsDoWordSpaceDescriptor ( /* Validate the Min/Max/Len/Gran values */ RsLargeAddressCheck ( - Descriptor->Address16.Minimum, - Descriptor->Address16.Maximum, - Descriptor->Address16.AddressLength, - Descriptor->Address16.Granularity, + (UINT64) Descriptor->Address16.Minimum, + (UINT64) Descriptor->Address16.Maximum, + (UINT64) Descriptor->Address16.AddressLength, + (UINT64) Descriptor->Address16.Granularity, Descriptor->Address16.Flags, - MinOp, MaxOp, LengthOp, GranOp); + MinOp, MaxOp, LengthOp, GranOp, Op); Rnode->BufferLength = sizeof (AML_RESOURCE_ADDRESS16) + OptionIndex + StringLength; diff --git a/sys/contrib/dev/acpica/compiler/aslstartup.c b/sys/contrib/dev/acpica/compiler/aslstartup.c index 14b362c3eb1..fc4ad5c0b33 100644 --- a/sys/contrib/dev/acpica/compiler/aslstartup.c +++ b/sys/contrib/dev/acpica/compiler/aslstartup.c @@ -124,9 +124,8 @@ #define ASL_MAX_FILES 256 -char *FileList[ASL_MAX_FILES]; -int FileCount; -BOOLEAN AslToFile = TRUE; +static char *FileList[ASL_MAX_FILES]; +static BOOLEAN AslToFile = TRUE; /* Local prototypes */ @@ -136,7 +135,7 @@ AsDoWildcard ( char *DirectoryPathname, char *FileSpecifier); -UINT8 +static UINT8 AslDetectSourceFileType ( ASL_FILE_INFO *Info); @@ -210,6 +209,7 @@ AsDoWildcard ( #ifdef WIN32 void *DirInfo; char *Filename; + int FileCount; FileCount = 0; @@ -277,7 +277,7 @@ AsDoWildcard ( * ******************************************************************************/ -UINT8 +static UINT8 AslDetectSourceFileType ( ASL_FILE_INFO *Info) { @@ -397,7 +397,7 @@ AslDoOneFile ( /* Shutdown compiler and ACPICA subsystem */ AeClearErrorLog (); - AcpiTerminate (); + (void) AcpiTerminate (); /* * Gbl_Files[ASL_FILE_INPUT].Filename was replaced with the @@ -487,7 +487,7 @@ AslDoOneFile ( } Status = CmDoCompile (); - AcpiTerminate (); + (void) AcpiTerminate (); /* * Return non-zero exit code if there have been errors, unless the @@ -533,7 +533,7 @@ AslDoOnePathname ( ASL_PATHNAME_CALLBACK PathCallback) { ACPI_STATUS Status = AE_OK; - char **FileList; + char **WildcardList; char *Filename; char *FullPathname; @@ -548,16 +548,16 @@ AslDoOnePathname ( /* Expand possible wildcard into a file list (Windows/DOS only) */ - FileList = AsDoWildcard (Gbl_DirectoryPath, Filename); - while (*FileList) + WildcardList = AsDoWildcard (Gbl_DirectoryPath, Filename); + while (*WildcardList) { FullPathname = ACPI_ALLOCATE ( - strlen (Gbl_DirectoryPath) + strlen (*FileList) + 1); + strlen (Gbl_DirectoryPath) + strlen (*WildcardList) + 1); /* Construct a full path to the file */ strcpy (FullPathname, Gbl_DirectoryPath); - strcat (FullPathname, *FileList); + strcat (FullPathname, *WildcardList); /* * If -p not specified, we will use the input filename as the @@ -573,9 +573,9 @@ AslDoOnePathname ( Status |= (*PathCallback) (FullPathname); ACPI_FREE (FullPathname); - ACPI_FREE (*FileList); - *FileList = NULL; - FileList++; + ACPI_FREE (*WildcardList); + *WildcardList = NULL; + WildcardList++; } ACPI_FREE (Gbl_DirectoryPath); diff --git a/sys/contrib/dev/acpica/compiler/asltypes.h b/sys/contrib/dev/acpica/compiler/asltypes.h index f4e5f462525..ea042104e0c 100644 --- a/sys/contrib/dev/acpica/compiler/asltypes.h +++ b/sys/contrib/dev/acpica/compiler/asltypes.h @@ -302,307 +302,4 @@ typedef struct asl_event_info } ASL_EVENT_INFO; -#define ASL_WARNING 0 -#define ASL_WARNING2 1 -#define ASL_WARNING3 2 -#define ASL_ERROR 3 -#define ASL_REMARK 4 -#define ASL_OPTIMIZATION 5 -#define ASL_NUM_REPORT_LEVELS 6 - - -typedef enum -{ - ASL_MSG_RESERVED = 0, - ASL_MSG_ALPHANUMERIC_STRING, - ASL_MSG_AML_NOT_IMPLEMENTED, - ASL_MSG_ARG_COUNT_HI, - ASL_MSG_ARG_COUNT_LO, - ASL_MSG_ARG_INIT, - ASL_MSG_BACKWARDS_OFFSET, - ASL_MSG_BITS_TO_BYTES, - ASL_MSG_BUFFER_LENGTH, - ASL_MSG_BYTES_TO_BITS, - ASL_MSG_CLOSE, - ASL_MSG_COMPILER_INTERNAL, - ASL_MSG_CONSTANT_EVALUATION, - ASL_MSG_CONSTANT_FOLDED, - ASL_MSG_CORE_EXCEPTION, - ASL_MSG_DEBUG_FILE_OPEN, - ASL_MSG_DEBUG_FILENAME, - ASL_MSG_DEPENDENT_NESTING, - ASL_MSG_DMA_CHANNEL, - ASL_MSG_DMA_LIST, - ASL_MSG_DUPLICATE_CASE, - ASL_MSG_DUPLICATE_ITEM, - ASL_MSG_EARLY_EOF, - ASL_MSG_ENCODING_LENGTH, - ASL_MSG_EX_INTERRUPT_LIST, - ASL_MSG_EX_INTERRUPT_LIST_MIN, - ASL_MSG_EX_INTERRUPT_NUMBER, - ASL_MSG_FIELD_ACCESS_WIDTH, - ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, - ASL_MSG_FIELD_UNIT_OFFSET, - ASL_MSG_INCLUDE_FILE_OPEN, - ASL_MSG_INPUT_FILE_OPEN, - ASL_MSG_INTEGER_LENGTH, - ASL_MSG_INTEGER_OPTIMIZATION, - ASL_MSG_INTERRUPT_LIST, - ASL_MSG_INTERRUPT_NUMBER, - ASL_MSG_INVALID_CONSTANT_OP, - ASL_MSG_INVALID_EISAID, - ASL_MSG_INVALID_ESCAPE, - ASL_MSG_INVALID_OPERAND, - ASL_MSG_INVALID_PERFORMANCE, - ASL_MSG_INVALID_PRIORITY, - ASL_MSG_INVALID_STRING, - ASL_MSG_INVALID_TARGET, - ASL_MSG_INVALID_TIME, - ASL_MSG_INVALID_TYPE, - ASL_MSG_INVALID_UUID, - ASL_MSG_LIST_LENGTH_LONG, - ASL_MSG_LIST_LENGTH_SHORT, - ASL_MSG_LISTING_FILE_OPEN, - ASL_MSG_LISTING_FILENAME, - ASL_MSG_LOCAL_INIT, - ASL_MSG_LONG_LINE, - ASL_MSG_MEMORY_ALLOCATION, - ASL_MSG_MISSING_ENDDEPENDENT, - ASL_MSG_MISSING_STARTDEPENDENT, - ASL_MSG_MULTIPLE_TYPES, - ASL_MSG_NAME_EXISTS, - ASL_MSG_NAME_OPTIMIZATION, - ASL_MSG_NESTED_COMMENT, - ASL_MSG_NO_CASES, - ASL_MSG_NO_RETVAL, - ASL_MSG_NO_WHILE, - ASL_MSG_NON_ASCII, - ASL_MSG_NOT_EXIST, - ASL_MSG_NOT_FOUND, - ASL_MSG_NOT_METHOD, - ASL_MSG_NOT_PARAMETER, - ASL_MSG_NOT_REACHABLE, - ASL_MSG_OPEN, - ASL_MSG_OUTPUT_FILE_OPEN, - ASL_MSG_OUTPUT_FILENAME, - ASL_MSG_PACKAGE_LENGTH, - ASL_MSG_READ, - ASL_MSG_RECURSION, - ASL_MSG_REGION_BUFFER_ACCESS, - ASL_MSG_REGION_BYTE_ACCESS, - ASL_MSG_RESERVED_ARG_COUNT_HI, - ASL_MSG_RESERVED_ARG_COUNT_LO, - ASL_MSG_RESERVED_METHOD, - ASL_MSG_RESERVED_OPERAND_TYPE, - ASL_MSG_RESERVED_RETURN_VALUE, - ASL_MSG_RESERVED_USE, - ASL_MSG_RESERVED_WORD, - ASL_MSG_RESOURCE_FIELD, - ASL_MSG_RESOURCE_INDEX, - ASL_MSG_RESOURCE_LIST, - ASL_MSG_RESOURCE_SOURCE, - ASL_MSG_RETURN_TYPES, - ASL_MSG_SCOPE_FWD_REF, - ASL_MSG_SCOPE_TYPE, - ASL_MSG_SEEK, - ASL_MSG_SINGLE_NAME_OPTIMIZATION, - ASL_MSG_SOME_NO_RETVAL, - ASL_MSG_SWITCH_TYPE, - ASL_MSG_SYNC_LEVEL, - ASL_MSG_SYNTAX, - ASL_MSG_TABLE_SIGNATURE, - ASL_MSG_TOO_MANY_TEMPS, - ASL_MSG_UNKNOWN_RESERVED_NAME, - ASL_MSG_UNREACHABLE_CODE, - ASL_MSG_UNSUPPORTED, - ASL_MSG_VENDOR_LIST, - ASL_MSG_WRITE, - ASL_MSG_MULTIPLE_DEFAULT, - ASL_MSG_TIMEOUT, - ASL_MSG_RESULT_NOT_USED, - ASL_MSG_NOT_REFERENCED, - ASL_MSG_NON_ZERO, - ASL_MSG_STRING_LENGTH, - ASL_MSG_SERIALIZED, - ASL_MSG_COMPILER_RESERVED, - ASL_MSG_NAMED_OBJECT_IN_WHILE, - ASL_MSG_LOCAL_OUTSIDE_METHOD, - ASL_MSG_ALIGNMENT, - ASL_MSG_ISA_ADDRESS, - ASL_MSG_INVALID_MIN_MAX, - ASL_MSG_INVALID_LENGTH, - ASL_MSG_INVALID_LENGTH_FIXED, - ASL_MSG_INVALID_GRANULARITY, - ASL_MSG_INVALID_GRAN_FIXED, - ASL_MSG_INVALID_ACCESS_SIZE, - ASL_MSG_INVALID_ADDR_FLAGS, - ASL_MSG_INVALID_FIELD_NAME, - ASL_MSG_INTEGER_SIZE, - ASL_MSG_INVALID_HEX_INTEGER, - ASL_MSG_BUFFER_ELEMENT, - ASL_MSG_RESERVED_VALUE, - ASL_MSG_FLAG_VALUE, - ASL_MSG_ZERO_VALUE, - ASL_MSG_UNKNOWN_TABLE, - ASL_MSG_UNKNOWN_SUBTABLE, - ASL_MSG_OEM_TABLE - -} ASL_MESSAGE_IDS; - -#ifdef ASL_EXCEPTIONS - -char *AslMessages [] = { -/* The zeroth message is reserved */ "", -/* ASL_MSG_ALPHANUMERIC_STRING */ "String must be entirely alphanumeric", -/* ASL_MSG_AML_NOT_IMPLEMENTED */ "Opcode is not implemented in compiler AML code generator", -/* ASL_MSG_ARG_COUNT_HI */ "Too many arguments", -/* ASL_MSG_ARG_COUNT_LO */ "Too few arguments", -/* ASL_MSG_ARG_INIT */ "Method argument is not initialized", -/* ASL_MSG_BACKWARDS_OFFSET */ "Invalid backwards offset", -/* ASL_MSG_BITS_TO_BYTES */ "Field offset is in bits, but a byte offset is required", -/* ASL_MSG_BUFFER_LENGTH */ "Effective AML buffer length is zero", -/* ASL_MSG_BYTES_TO_BITS */ "Field offset is in bytes, but a bit offset is required", -/* ASL_MSG_CLOSE */ "Could not close file", -/* ASL_MSG_COMPILER_INTERNAL */ "Internal compiler error", -/* ASL_MSG_CONSTANT_EVALUATION */ "Could not evaluate constant expression", -/* ASL_MSG_CONSTANT_FOLDED */ "Constant expression evaluated and reduced", -/* ASL_MSG_CORE_EXCEPTION */ "From ACPI CA Subsystem", -/* ASL_MSG_DEBUG_FILE_OPEN */ "Could not open debug file", -/* ASL_MSG_DEBUG_FILENAME */ "Could not create debug filename", -/* ASL_MSG_DEPENDENT_NESTING */ "Dependent function macros cannot be nested",\ -/* ASL_MSG_DMA_CHANNEL */ "Invalid DMA channel (must be 0-7)", -/* ASL_MSG_DMA_LIST */ "Too many DMA channels (8 max)", -/* ASL_MSG_DUPLICATE_CASE */ "Case value already specified", -/* ASL_MSG_DUPLICATE_ITEM */ "Duplicate value in list", -/* ASL_MSG_EARLY_EOF */ "Premature end-of-file reached", -/* ASL_MSG_ENCODING_LENGTH */ "Package length too long to encode", -/* ASL_MSG_EX_INTERRUPT_LIST */ "Too many interrupts (255 max)", -/* ASL_MSG_EX_INTERRUPT_LIST_MIN */ "Too few interrupts (1 minimum required)", -/* ASL_MSG_EX_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 32 bits)", -/* ASL_MSG_FIELD_ACCESS_WIDTH */ "Access width is greater than region size", -/* ASL_MSG_FIELD_UNIT_ACCESS_WIDTH */ "Access width of Field Unit extends beyond region limit", -/* ASL_MSG_FIELD_UNIT_OFFSET */ "Field Unit extends beyond region limit", -/* ASL_MSG_INCLUDE_FILE_OPEN */ "Could not open include file", -/* ASL_MSG_INPUT_FILE_OPEN */ "Could not open input file", -/* ASL_MSG_INTEGER_LENGTH */ "64-bit integer in 32-bit table, truncating", -/* ASL_MSG_INTEGER_OPTIMIZATION */ "Integer optimized to single-byte AML opcode", -/* ASL_MSG_INTERRUPT_LIST */ "Too many interrupts (16 max)", -/* ASL_MSG_INTERRUPT_NUMBER */ "Invalid interrupt number (must be 0-15)", -/* ASL_MSG_INVALID_CONSTANT_OP */ "Invalid operator in constant expression (not type 3/4/5)", -/* ASL_MSG_INVALID_EISAID */ "EISAID string must be of the form \"UUUXXXX\" (3 uppercase, 4 hex digits)", -/* ASL_MSG_INVALID_ESCAPE */ "Invalid or unknown escape sequence", -/* ASL_MSG_INVALID_OPERAND */ "Invalid operand", -/* ASL_MSG_INVALID_PERFORMANCE */ "Invalid performance/robustness value", -/* ASL_MSG_INVALID_PRIORITY */ "Invalid priority value", -/* ASL_MSG_INVALID_STRING */ "Invalid Hex/Octal Escape - Non-ASCII or NULL", -/* ASL_MSG_INVALID_TARGET */ "Target operand not allowed in constant expression", -/* ASL_MSG_INVALID_TIME */ "Time parameter too long (255 max)", -/* ASL_MSG_INVALID_TYPE */ "Invalid type", -/* ASL_MSG_INVALID_UUID */ "UUID string must be of the form \"aabbccdd-eeff-gghh-iijj-kkllmmnnoopp\"", -/* ASL_MSG_LIST_LENGTH_LONG */ "Initializer list longer than declared package length", -/* ASL_MSG_LIST_LENGTH_SHORT */ "Initializer list shorter than declared package length", -/* ASL_MSG_LISTING_FILE_OPEN */ "Could not open listing file", -/* ASL_MSG_LISTING_FILENAME */ "Could not create listing filename", -/* ASL_MSG_LOCAL_INIT */ "Method local variable is not initialized", -/* ASL_MSG_LONG_LINE */ "Splitting long input line", -/* ASL_MSG_MEMORY_ALLOCATION */ "Memory allocation failure", -/* ASL_MSG_MISSING_ENDDEPENDENT */ "Missing EndDependentFn() macro in dependent resource list", -/* ASL_MSG_MISSING_STARTDEPENDENT */ "Missing StartDependentFn() macro in dependent resource list", -/* ASL_MSG_MULTIPLE_TYPES */ "Multiple types", -/* ASL_MSG_NAME_EXISTS */ "Name already exists in scope", -/* ASL_MSG_NAME_OPTIMIZATION */ "NamePath optimized", -/* ASL_MSG_NESTED_COMMENT */ "Nested comment found", -/* ASL_MSG_NO_CASES */ "No Case statements under Switch", -/* ASL_MSG_NO_RETVAL */ "Called method returns no value", -/* ASL_MSG_NO_WHILE */ "No enclosing While statement", -/* ASL_MSG_NON_ASCII */ "Invalid characters found in file", -/* ASL_MSG_NOT_EXIST */ "Object does not exist", -/* ASL_MSG_NOT_FOUND */ "Object not found or not accessible from scope", -/* ASL_MSG_NOT_METHOD */ "Not a control method, cannot invoke", -/* ASL_MSG_NOT_PARAMETER */ "Not a parameter, used as local only", -/* ASL_MSG_NOT_REACHABLE */ "Object is not accessible from this scope", -/* ASL_MSG_OPEN */ "Could not open file", -/* ASL_MSG_OUTPUT_FILE_OPEN */ "Could not open output AML file", -/* ASL_MSG_OUTPUT_FILENAME */ "Could not create output filename", -/* ASL_MSG_PACKAGE_LENGTH */ "Effective AML package length is zero", -/* ASL_MSG_READ */ "Could not read file", -/* ASL_MSG_RECURSION */ "Recursive method call", -/* ASL_MSG_REGION_BUFFER_ACCESS */ "Host Operation Region requires BufferAcc access", -/* ASL_MSG_REGION_BYTE_ACCESS */ "Host Operation Region requires ByteAcc access", -/* ASL_MSG_RESERVED_ARG_COUNT_HI */ "Reserved method has too many arguments", -/* ASL_MSG_RESERVED_ARG_COUNT_LO */ "Reserved method has too few arguments", -/* ASL_MSG_RESERVED_METHOD */ "Reserved name must be a control method", -/* ASL_MSG_RESERVED_OPERAND_TYPE */ "Invalid object type for reserved name", -/* ASL_MSG_RESERVED_RETURN_VALUE */ "Reserved method must return a value", -/* ASL_MSG_RESERVED_USE */ "Invalid use of reserved name", -/* ASL_MSG_RESERVED_WORD */ "Use of reserved name", -/* ASL_MSG_RESOURCE_FIELD */ "Resource field name cannot be used as a target", -/* ASL_MSG_RESOURCE_INDEX */ "Missing ResourceSourceIndex (required)", -/* ASL_MSG_RESOURCE_LIST */ "Too many resource items (internal error)", -/* ASL_MSG_RESOURCE_SOURCE */ "Missing ResourceSource string (required)", -/* ASL_MSG_RETURN_TYPES */ "Not all control paths return a value", -/* ASL_MSG_SCOPE_FWD_REF */ "Forward references from Scope operator not allowed", -/* ASL_MSG_SCOPE_TYPE */ "Existing object has invalid type for Scope operator", -/* ASL_MSG_SEEK */ "Could not seek file", -/* ASL_MSG_SINGLE_NAME_OPTIMIZATION */ "NamePath optimized to NameSeg (uses run-time search path)", -/* ASL_MSG_SOME_NO_RETVAL */ "Called method may not always return a value", -/* ASL_MSG_SWITCH_TYPE */ "Switch expression is not a static Integer/Buffer/String data type, defaulting to Integer", -/* ASL_MSG_SYNC_LEVEL */ "SyncLevel must be in the range 0-15", -/* ASL_MSG_SYNTAX */ "", -/* ASL_MSG_TABLE_SIGNATURE */ "Invalid Table Signature", -/* ASL_MSG_TOO_MANY_TEMPS */ "Method requires too many temporary variables (_T_x)", -/* ASL_MSG_UNKNOWN_RESERVED_NAME */ "Unknown reserved name", -/* ASL_MSG_UNREACHABLE_CODE */ "Statement is unreachable", -/* ASL_MSG_UNSUPPORTED */ "Unsupported feature", -/* ASL_MSG_VENDOR_LIST */ "Too many vendor data bytes (7 max)", -/* ASL_MSG_WRITE */ "Could not write file", -/* ASL_MSG_MULTIPLE_DEFAULT */ "More than one Default statement within Switch construct", -/* ASL_MSG_TIMEOUT */ "Possible operator timeout is ignored", -/* ASL_MSG_RESULT_NOT_USED */ "Result is not used, operator has no effect", -/* ASL_MSG_NOT_REFERENCED */ "Namespace object is not referenced", -/* ASL_MSG_NON_ZERO */ "Operand evaluates to zero", -/* ASL_MSG_STRING_LENGTH */ "String literal too long", -/* ASL_MSG_SERIALIZED */ "Control Method marked Serialized", -/* ASL_MSG_COMPILER_RESERVED */ "Use of compiler reserved name", -/* ASL_MSG_NAMED_OBJECT_IN_WHILE */ "Creating a named object in a While loop", -/* ASL_MSG_LOCAL_OUTSIDE_METHOD */ "Local or Arg used outside a control method", -/* ASL_MSG_ALIGNMENT */ "Must be a multiple of alignment/granularity value", -/* ASL_MSG_ISA_ADDRESS */ "Maximum 10-bit ISA address (0x3FF)", -/* ASL_MSG_INVALID_MIN_MAX */ "Address Min is greater than Address Max", -/* ASL_MSG_INVALID_LENGTH */ "Length is larger than Min/Max window", -/* ASL_MSG_INVALID_LENGTH_FIXED */ "Length is not equal to fixed Min/Max window", -/* ASL_MSG_INVALID_GRANULARITY */ "Granularity must be zero or a power of two minus one", -/* ASL_MSG_INVALID_GRAN_FIXED */ "Granularity must be zero for fixed Min/Max", -/* ASL_MSG_INVALID_ACCESS_SIZE */ "Invalid AccessSize (Maximum is 4 - QWord access)", -/* ASL_MSG_INVALID_ADDR_FLAGS */ "Invalid combination of Length and Min/Max fixed flags", - -/* These messages are used by the data table compiler only */ - -/* ASL_MSG_INVALID_FIELD_NAME */ "Invalid Field Name", -/* ASL_MSG_INTEGER_SIZE */ "Integer too large for target", -/* ASL_MSG_INVALID_HEX_INTEGER */ "Invalid hex integer constant", -/* ASL_MSG_BUFFER_ELEMENT */ "Invalid element in buffer initializer list", -/* ASL_MSG_RESERVED_VALUE */ "Reserved field must be zero", -/* ASL_MSG_FLAG_VALUE */ "Flag value is too large", -/* ASL_MSG_ZERO_VALUE */ "Value must be non-zero", -/* ASL_MSG_UNKNOWN_TABLE */ "Unknown ACPI table signature", -/* ASL_MSG_UNKNOWN_SUBTABLE */ "Unknown subtable type", -/* ASL_MSG_OEM_TABLE */ "OEM table - unknown contents" - -}; - - -char *AslErrorLevel [ASL_NUM_REPORT_LEVELS] = { - "Warning ", - "Warning ", - "Warning ", - "Error ", - "Remark ", - "Optimize" -}; - -#define ASL_ERROR_LEVEL_LENGTH 8 /* Length of strings above */ - -#endif /* ASL_EXCEPTIONS */ - #endif /* __ASLTYPES_H */ diff --git a/sys/contrib/dev/acpica/compiler/aslutils.c b/sys/contrib/dev/acpica/compiler/aslutils.c index 3fbcc5bb945..38f3ba2be74 100644 --- a/sys/contrib/dev/acpica/compiler/aslutils.c +++ b/sys/contrib/dev/acpica/compiler/aslutils.c @@ -120,6 +120,7 @@ #include #include #include +#include #define _COMPONENT ACPI_COMPILER ACPI_MODULE_NAME ("aslutils") @@ -566,8 +567,8 @@ UtDisplaySummary ( { /* Compiler name and version number */ - FlPrintFile (FileId, "%s version %X\n", - CompilerId, (UINT32) ACPI_CA_VERSION); + FlPrintFile (FileId, "%s version %X%s\n", + ASL_COMPILER_NAME, (UINT32) ACPI_CA_VERSION, ACPI_WIDTH); } if (Gbl_FileType == ASL_INPUT_TYPE_ASCII_DATA) diff --git a/sys/contrib/dev/acpica/compiler/dtcompile.c b/sys/contrib/dev/acpica/compiler/dtcompile.c index 5bdc6b24d7a..908b25fb015 100644 --- a/sys/contrib/dev/acpica/compiler/dtcompile.c +++ b/sys/contrib/dev/acpica/compiler/dtcompile.c @@ -127,7 +127,7 @@ static char VersionString[9]; /* Local prototypes */ -static void +static ACPI_STATUS DtInitialize ( void); @@ -166,7 +166,12 @@ DtDoCompile ( /* Initialize globals */ - DtInitialize (); + Status = DtInitialize (); + if (ACPI_FAILURE (Status)) + { + printf ("Error during compiler initialization, 0x%X\n", Status); + return (Status); + } /* * Scan the input file (file is already open) and @@ -236,26 +241,38 @@ CleanupAndExit: * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Initialize data table compiler globals. Enables multiple * compiles per invocation. * *****************************************************************************/ -static void +static ACPI_STATUS DtInitialize ( void) { + ACPI_STATUS Status; - AcpiOsInitialize (); - AcpiUtInitGlobals (); + + Status = AcpiOsInitialize (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + Status = AcpiUtInitGlobals (); + if (ACPI_FAILURE (Status)) + { + return (Status); + } Gbl_FieldList = NULL; Gbl_RootTable = NULL; Gbl_SubtableStack = NULL; sprintf (VersionString, "%X", (UINT32) ACPI_CA_VERSION); + return (AE_OK); } @@ -297,7 +314,7 @@ DtInsertCompilerIds ( Next = Next->Next; } - Next->Value = CompilerCreatorId; + Next->Value = ASL_CREATOR_ID; Next->Flags = DT_FIELD_NOT_ALLOCATED; Next = Next->Next; diff --git a/sys/contrib/dev/acpica/compiler/dtio.c b/sys/contrib/dev/acpica/compiler/dtio.c index a2fc713743f..c81f919561e 100644 --- a/sys/contrib/dev/acpica/compiler/dtio.c +++ b/sys/contrib/dev/acpica/compiler/dtio.c @@ -158,7 +158,7 @@ DtWriteBinary ( #define DT_SLASH_SLASH_COMMENT 4 #define DT_END_COMMENT 5 -UINT32 Gbl_NextLineOffset; +static UINT32 Gbl_NextLineOffset; /****************************************************************************** diff --git a/sys/contrib/dev/acpica/compiler/dttemplate.c b/sys/contrib/dev/acpica/compiler/dttemplate.c index 6bbb54896c7..33c2cea0313 100644 --- a/sys/contrib/dev/acpica/compiler/dttemplate.c +++ b/sys/contrib/dev/acpica/compiler/dttemplate.c @@ -377,9 +377,9 @@ DtCreateOneTemplate ( AcpiOsRedirectOutput (File); - AcpiOsPrintf ("/*\n * %s\n", IntelAcpiCA); - AcpiOsPrintf (" * iASL Compiler/Disassembler version %8.8X\n *\n", - ACPI_CA_VERSION); + AcpiOsPrintf ("/*\n"); + AcpiOsPrintf (ACPI_COMMON_HEADER ("iASL Compiler/Disassembler", " * ")); + AcpiOsPrintf (" * Template for [%4.4s] ACPI Table\n", Signature); diff --git a/sys/contrib/dev/acpica/debugger/dbexec.c b/sys/contrib/dev/acpica/debugger/dbexec.c index 9a080b2d36e..07b6ad92c1d 100644 --- a/sys/contrib/dev/acpica/debugger/dbexec.c +++ b/sys/contrib/dev/acpica/debugger/dbexec.c @@ -567,14 +567,12 @@ AcpiDbMethodThread ( if (Info->InitArgs) { AcpiDbUInt32ToHexString (Info->NumCreated, Info->IndexOfThreadStr); - AcpiDbUInt32ToHexString (ACPI_TO_INTEGER (AcpiOsGetThreadId ()), - Info->IdOfThreadStr); + AcpiDbUInt32ToHexString ((UINT32) AcpiOsGetThreadId (), Info->IdOfThreadStr); } if (Info->Threads && (Info->NumCreated < Info->NumThreads)) { - Info->Threads[Info->NumCreated++] = - ACPI_TO_INTEGER (AcpiOsGetThreadId()); + Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId(); } LocalInfo = *Info; @@ -722,8 +720,8 @@ AcpiDbCreateExecutionThreads ( /* Array to store IDs of threads */ AcpiGbl_DbMethodInfo.NumThreads = NumThreads; - Size = 4 * AcpiGbl_DbMethodInfo.NumThreads; - AcpiGbl_DbMethodInfo.Threads = (UINT32 *) AcpiOsAllocate (Size); + Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads; + AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size); if (AcpiGbl_DbMethodInfo.Threads == NULL) { AcpiOsPrintf ("No memory for thread IDs array\n"); diff --git a/sys/contrib/dev/acpica/events/evrgnini.c b/sys/contrib/dev/acpica/events/evrgnini.c index 9ca4608e88b..16806548528 100644 --- a/sys/contrib/dev/acpica/events/evrgnini.c +++ b/sys/contrib/dev/acpica/events/evrgnini.c @@ -395,8 +395,8 @@ AcpiEvPciConfigRegionSetup ( } /* - * Get the PCI device and function numbers from the _ADR object contained - * in the parent's scope. + * Get the PCI device and function numbers from the _ADR object + * contained in the parent's scope. */ Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, PciDeviceNode, &PciValue); @@ -429,9 +429,14 @@ AcpiEvPciConfigRegionSetup ( PciId->Bus = ACPI_LOWORD (PciValue); } - /* Complete this device's PciId */ + /* Complete/update the PCI ID for this device */ - AcpiOsDerivePciId (PciRootNode, RegionObj->Region.Node, &PciId); + Status = AcpiHwDerivePciId (PciId, PciRootNode, RegionObj->Region.Node); + if (ACPI_FAILURE (Status)) + { + ACPI_FREE (PciId); + return_ACPI_STATUS (Status); + } *RegionContext = PciId; return_ACPI_STATUS (AE_OK); diff --git a/sys/contrib/dev/acpica/events/evxfregn.c b/sys/contrib/dev/acpica/events/evxfregn.c index d06c6f73db7..c3ac094d011 100644 --- a/sys/contrib/dev/acpica/events/evxfregn.c +++ b/sys/contrib/dev/acpica/events/evxfregn.c @@ -139,6 +139,12 @@ * * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. * + * NOTE: This function should only be called after AcpiEnableSubsystem has + * been called. This is because any _REG methods associated with the Space ID + * are executed here, and these methods can only be safely executed after + * the default handlers have been installed and the hardware has been + * initialized (via AcpiEnableSubsystem.) + * ******************************************************************************/ ACPI_STATUS diff --git a/sys/contrib/dev/acpica/executer/exmutex.c b/sys/contrib/dev/acpica/executer/exmutex.c index 315ad100e83..865c6348c0f 100644 --- a/sys/contrib/dev/acpica/executer/exmutex.c +++ b/sys/contrib/dev/acpica/executer/exmutex.c @@ -513,10 +513,10 @@ AcpiExReleaseMutex ( (ObjDesc != AcpiGbl_GlobalLockMutex)) { ACPI_ERROR ((AE_INFO, - "Thread %p cannot release Mutex [%4.4s] acquired by thread %p", - ACPI_CAST_PTR (void, WalkState->Thread->ThreadId), + "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", + (UINT32) WalkState->Thread->ThreadId, AcpiUtGetNodeName (ObjDesc->Mutex.Node), - ACPI_CAST_PTR (void, OwnerThread->ThreadId))); + (UINT32) OwnerThread->ThreadId)); return_ACPI_STATUS (AE_AML_NOT_OWNER); } diff --git a/sys/contrib/dev/acpica/hardware/hwpci.c b/sys/contrib/dev/acpica/hardware/hwpci.c new file mode 100644 index 00000000000..d0da8e31127 --- /dev/null +++ b/sys/contrib/dev/acpica/hardware/hwpci.c @@ -0,0 +1,531 @@ +/******************************************************************************* + * + * Module Name: hwpci - Obtain PCI bus, device, and function numbers + * + ******************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + *****************************************************************************/ + +#define __HWPCI_C__ + +#include +#include + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("hwpci") + + +/* PCI configuration space values */ + +#define PCI_CFG_HEADER_TYPE_REG 0x0E +#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 +#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 + +/* PCI header values */ + +#define PCI_HEADER_TYPE_MASK 0x7F +#define PCI_TYPE_BRIDGE 0x01 +#define PCI_TYPE_CARDBUS_BRIDGE 0x02 + +typedef struct acpi_pci_device +{ + ACPI_HANDLE Device; + struct acpi_pci_device *Next; + +} ACPI_PCI_DEVICE; + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead); + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead); + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead); + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge); + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDerivePciId + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * RootPciDevice - A handle to a PCI device object. This + * object must be a PCI Root Bridge having a + * _HID value of either PNP0A03 or PNP0A08 + * PciRegion - A handle to a PCI configuration space + * Operation Region being initialized + * + * RETURN: Status + * + * DESCRIPTION: This function derives a full PCI ID for a PCI device, + * consisting of a Segment number, Bus number, Device number, + * and function code. + * + * The PCI hardware dynamically configures PCI bus numbers + * depending on the bus topology discovered during system + * initialization. This function is invoked during configuration + * of a PCI_Config Operation Region in order to (possibly) update + * the Bus/Device/Function numbers in the PciId with the actual + * values as determined by the hardware and operating system + * configuration. + * + * The PciId parameter is initially populated during the Operation + * Region initialization. This function is then called, and is + * will make any necessary modifications to the Bus, Device, or + * Function number PCI ID subfields as appropriate for the + * current hardware and OS configuration. + * + * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId + * interface since this feature is OS-independent. This module + * specifically avoids any use of recursion by building a local + * temporary device list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion) +{ + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListHead = NULL; + + + ACPI_FUNCTION_TRACE (HwDerivePciId); + + + if (!PciId) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ + + Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); + if (ACPI_SUCCESS (Status)) + { + /* Walk the list, updating the PCI device/function/bus numbers */ + + Status = AcpiHwProcessPciList (PciId, ListHead); + } + + /* Always delete the list */ + + AcpiHwDeletePciList (ListHead); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwBuildPciList + * + * PARAMETERS: RootPciDevice - A handle to a PCI device object. This + * object is guaranteed to be a PCI Root + * Bridge having a _HID value of either + * PNP0A03 or PNP0A08 + * PciRegion - A handle to the PCI configuration space + * Operation Region + * ReturnListHead - Where the PCI device list is returned + * + * RETURN: Status + * + * DESCRIPTION: Builds a list of devices from the input PCI region up to the + * Root PCI device for this namespace subtree. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead) +{ + ACPI_HANDLE CurrentDevice; + ACPI_HANDLE ParentDevice; + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListElement; + ACPI_PCI_DEVICE *ListHead = NULL; + + + /* + * Ascend namespace branch until the RootPciDevice is reached, building + * a list of device nodes. Loop will exit when either the PCI device is + * found, or the root of the namespace is reached. + */ + CurrentDevice = PciRegion; + while (1) + { + Status = AcpiGetParent (CurrentDevice, &ParentDevice); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ + + if (ParentDevice == RootPciDevice) + { + *ReturnListHead = ListHead; + return (AE_OK); + } + + ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); + if (!ListElement) + { + return (AE_NO_MEMORY); + } + + /* Put new element at the head of the list */ + + ListElement->Next = ListHead; + ListElement->Device = ParentDevice; + ListHead = ListElement; + + CurrentDevice = ParentDevice; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwProcessPciList + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: Status + * + * DESCRIPTION: Walk downward through the PCI device list, getting the device + * info for each, via the PCI configuration space and updating + * the PCI ID as necessary. Deletes the list during traversal. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PCI_DEVICE *Info; + UINT16 BusNumber; + BOOLEAN IsBridge = TRUE; + + + ACPI_FUNCTION_NAME (HwProcessPciList); + + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); + + BusNumber = PciId->Bus; + + /* + * Descend down the namespace tree, collecting PCI device, function, + * and bus numbers. BusNumber is only important for PCI bridges. + * Algorithm: As we descend the tree, use the last valid PCI device, + * function, and bus numbers that are discovered, and assign them + * to the PCI ID for the target device. + */ + Info = ListHead; + while (Info) + { + Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, + &BusNumber, &IsBridge); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Info = Info->Next; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " + "Status %X BusNumber %X IsBridge %X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, + Status, BusNumber, IsBridge)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDeletePciList + * + * PARAMETERS: ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: None + * + * DESCRIPTION: Free the entire PCI list. + * + ******************************************************************************/ + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_PCI_DEVICE *Next; + ACPI_PCI_DEVICE *Previous; + + + Next = ListHead; + while (Next) + { + Previous = Next; + Next = Previous->Next; + ACPI_FREE (Previous); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetPciDeviceInfo + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * PciDevice - Handle for the PCI device object + * BusNumber - Where a PCI bridge bus number is returned + * IsBridge - Return value, indicates if this PCI + * device is a PCI bridge + * + * RETURN: Status + * + * DESCRIPTION: Get the device info for a single PCI device object. Get the + * _ADR (contains PCI device and function numbers), and for PCI + * bridge devices, get the bus number from PCI configuration + * space. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge) +{ + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + UINT64 ReturnValue; + UINT64 PciValue; + + + /* We only care about objects of type Device */ + + Status = AcpiGetType (PciDevice, &ObjectType); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (ObjectType != ACPI_TYPE_DEVICE) + { + return (AE_OK); + } + + /* We need an _ADR. Ignore device if not present */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, + PciDevice, &ReturnValue); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* + * From _ADR, get the PCI Device and Function and + * update the PCI ID. + */ + PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); + PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); + + /* + * If the previous device was a bridge, use the previous + * device bus number + */ + if (*IsBridge) + { + PciId->Bus = *BusNumber; + } + + /* + * Get the bus numbers from PCI Config space: + * + * First, get the PCI HeaderType + */ + *IsBridge = FALSE; + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ + + PciValue &= PCI_HEADER_TYPE_MASK; + + if ((PciValue != PCI_TYPE_BRIDGE) && + (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) + { + return (AE_OK); + } + + /* Bridge: Get the Primary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *IsBridge = TRUE; + PciId->Bus = (UINT16) PciValue; + + /* Bridge: Get the Secondary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *BusNumber = (UINT16) PciValue; + return (AE_OK); +} diff --git a/sys/contrib/dev/acpica/include/acapps.h b/sys/contrib/dev/acpica/include/acapps.h index 418e20fb084..1368c213431 100644 --- a/sys/contrib/dev/acpica/include/acapps.h +++ b/sys/contrib/dev/acpica/include/acapps.h @@ -121,6 +121,38 @@ #pragma warning(disable:4100) /* warning C4100: unreferenced formal parameter */ #endif +/* Common info for tool signons */ + +#define ACPICA_NAME "Intel ACPI Component Architecture" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2010 Intel Corporation" + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_WIDTH "-64" + +#elif ACPI_MACHINE_WIDTH == 32 +#define ACPI_WIDTH "-32" + +#else +#error unknown ACPI_MACHINE_WIDTH +#define ACPI_WIDTH "-??" + +#endif + +/* Macros for signons and file headers */ + +#define ACPI_COMMON_SIGNON(UtilityName) \ + "\n%s\n%s version %8.8X%s\n%s\n\n", \ + ACPICA_NAME, \ + UtilityName, ((UINT32) ACPI_CA_VERSION), ACPI_WIDTH, \ + ACPICA_COPYRIGHT + +#define ACPI_COMMON_HEADER(UtilityName, Prefix) \ + "%s%s\n%s%s version %8.8X%s\n%s%s\n%s\n", \ + Prefix, ACPICA_NAME, \ + Prefix, UtilityName, ((UINT32) ACPI_CA_VERSION), ACPI_WIDTH, \ + Prefix, ACPICA_COPYRIGHT, \ + Prefix + #define FILE_SUFFIX_DISASSEMBLY "dsl" #define ACPI_TABLE_FILE_SUFFIX ".dat" diff --git a/sys/contrib/dev/acpica/include/acglobal.h b/sys/contrib/dev/acpica/include/acglobal.h index 581fc76f376..2e158fbf79e 100644 --- a/sys/contrib/dev/acpica/include/acglobal.h +++ b/sys/contrib/dev/acpica/include/acglobal.h @@ -214,6 +214,7 @@ ACPI_TABLE_FADT AcpiGbl_FADT; UINT32 AcpiCurrentGpeCount; UINT32 AcpiGbl_TraceFlags; ACPI_NAME AcpiGbl_TraceMethodName; +BOOLEAN AcpiGbl_SystemAwakeAndRunning; #endif @@ -334,7 +335,6 @@ ACPI_EXTERN UINT8 AcpiGbl_DebuggerConfiguration; ACPI_EXTERN BOOLEAN AcpiGbl_StepToNextCall; ACPI_EXTERN BOOLEAN AcpiGbl_AcpiHardwarePresent; ACPI_EXTERN BOOLEAN AcpiGbl_EventsInitialized; -ACPI_EXTERN BOOLEAN AcpiGbl_SystemAwakeAndRunning; ACPI_EXTERN UINT8 AcpiGbl_OsiData; ACPI_EXTERN ACPI_INTERFACE_INFO *AcpiGbl_SupportedInterfaces; diff --git a/sys/contrib/dev/acpica/include/achware.h b/sys/contrib/dev/acpica/include/achware.h index db08293c0af..e63fe3f2152 100644 --- a/sys/contrib/dev/acpica/include/achware.h +++ b/sys/contrib/dev/acpica/include/achware.h @@ -250,6 +250,16 @@ AcpiHwEnableRuntimeGpeBlock ( void *Context); +/* + * hwpci - PCI configuration support + */ +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion); + + /* * hwtimer - ACPI Timer prototypes */ diff --git a/sys/contrib/dev/acpica/include/aclocal.h b/sys/contrib/dev/acpica/include/aclocal.h index 39b6616d66c..062972f8e1c 100644 --- a/sys/contrib/dev/acpica/include/aclocal.h +++ b/sys/contrib/dev/acpica/include/aclocal.h @@ -1080,6 +1080,7 @@ typedef struct acpi_bit_register_info ACPI_BITMASK_POWER_BUTTON_STATUS | \ ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_PCIEXP_WAKE_STATUS | \ ACPI_BITMASK_WAKE_STATUS) #define ACPI_BITMASK_TIMER_ENABLE 0x0001 @@ -1136,7 +1137,8 @@ typedef struct acpi_bit_register_info #define ACPI_OSI_WIN_VISTA 0x07 #define ACPI_OSI_WINSRV_2008 0x08 #define ACPI_OSI_WIN_VISTA_SP1 0x09 -#define ACPI_OSI_WIN_7 0x0A +#define ACPI_OSI_WIN_VISTA_SP2 0x0A +#define ACPI_OSI_WIN_7 0x0B #define ACPI_ALWAYS_ILLEGAL 0x00 @@ -1270,7 +1272,7 @@ typedef struct acpi_db_method_info ACPI_HANDLE MainThreadGate; ACPI_HANDLE ThreadCompleteGate; ACPI_HANDLE InfoGate; - UINT32 *Threads; + ACPI_THREAD_ID *Threads; UINT32 NumThreads; UINT32 NumCreated; UINT32 NumCompleted; diff --git a/sys/contrib/dev/acpica/include/acmacros.h b/sys/contrib/dev/acpica/include/acmacros.h index e9a6f42cbf2..417cdc3b003 100644 --- a/sys/contrib/dev/acpica/include/acmacros.h +++ b/sys/contrib/dev/acpica/include/acmacros.h @@ -400,8 +400,8 @@ * the plist contains a set of parens to allow variable-length lists. * These macros are used for both the debug and non-debug versions of the code. */ -#define ACPI_ERROR_NAMESPACE(s, e) AcpiNsReportError (AE_INFO, s, e); -#define ACPI_ERROR_METHOD(s, n, p, e) AcpiNsReportMethodError (AE_INFO, s, n, p, e); +#define ACPI_ERROR_NAMESPACE(s, e) AcpiUtNamespaceError (AE_INFO, s, e); +#define ACPI_ERROR_METHOD(s, n, p, e) AcpiUtMethodError (AE_INFO, s, n, p, e); #define ACPI_WARN_PREDEFINED(plist) AcpiUtPredefinedWarning plist #define ACPI_INFO_PREDEFINED(plist) AcpiUtPredefinedInfo plist diff --git a/sys/contrib/dev/acpica/include/acnamesp.h b/sys/contrib/dev/acpica/include/acnamesp.h index 5895e062fec..5840bbc5861 100644 --- a/sys/contrib/dev/acpica/include/acnamesp.h +++ b/sys/contrib/dev/acpica/include/acnamesp.h @@ -513,22 +513,6 @@ UINT32 AcpiNsLocal ( ACPI_OBJECT_TYPE Type); -void -AcpiNsReportError ( - const char *ModuleName, - UINT32 LineNumber, - const char *InternalName, - ACPI_STATUS LookupStatus); - -void -AcpiNsReportMethodError ( - const char *ModuleName, - UINT32 LineNumber, - const char *Message, - ACPI_NAMESPACE_NODE *Node, - const char *Path, - ACPI_STATUS LookupStatus); - void AcpiNsPrintNodePathname ( ACPI_NAMESPACE_NODE *Node, diff --git a/sys/contrib/dev/acpica/include/acpiosxf.h b/sys/contrib/dev/acpica/include/acpiosxf.h index dd086180cf3..5e7a2aa4382 100644 --- a/sys/contrib/dev/acpica/include/acpiosxf.h +++ b/sys/contrib/dev/acpica/include/acpiosxf.h @@ -405,16 +405,6 @@ AcpiOsWritePciConfiguration ( UINT32 Width); -/* - * Interim function needed for PCI IRQ routing - */ -void -AcpiOsDerivePciId( - ACPI_HANDLE Device, - ACPI_HANDLE Region, - ACPI_PCI_ID **PciId); - - /* * Miscellaneous */ diff --git a/sys/contrib/dev/acpica/include/acpixf.h b/sys/contrib/dev/acpica/include/acpixf.h index 2321e341de9..6d100c09bc1 100644 --- a/sys/contrib/dev/acpica/include/acpixf.h +++ b/sys/contrib/dev/acpica/include/acpixf.h @@ -120,7 +120,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20100806 +#define ACPI_CA_VERSION 0x20101013 #include #include @@ -130,6 +130,7 @@ */ extern UINT32 AcpiCurrentGpeCount; extern ACPI_TABLE_FADT AcpiGbl_FADT; +extern BOOLEAN AcpiGbl_SystemAwakeAndRunning; /* Runtime configuration of debug print levels */ diff --git a/sys/contrib/dev/acpica/include/actypes.h b/sys/contrib/dev/acpica/include/actypes.h index 0486f8eb63d..e4290ae55d3 100644 --- a/sys/contrib/dev/acpica/include/actypes.h +++ b/sys/contrib/dev/acpica/include/actypes.h @@ -188,7 +188,6 @@ * * ACPI_SIZE 16/32/64-bit unsigned value * ACPI_NATIVE_INT 16/32/64-bit signed value - * */ /******************************************************************************* @@ -205,6 +204,16 @@ typedef COMPILER_DEPENDENT_INT64 INT64; /*! [End] no source code translation !*/ +/* + * Value returned by AcpiOsGetThreadId. There is no standard "thread_id" + * across operating systems or even the various UNIX systems. Since ACPICA + * only needs the thread ID as a unique thread identifier, we use a UINT64 + * as the only common data type - it will accommodate any type of pointer or + * any type of integer. It is up to the host-dependent OSL to cast the + * native thread ID type to a UINT64 (in AcpiOsGetThreadId). + */ +#define ACPI_THREAD_ID UINT64 + /******************************************************************************* * @@ -286,12 +295,6 @@ typedef UINT32 ACPI_PHYSICAL_ADDRESS; * ******************************************************************************/ -/* Value returned by AcpiOsGetThreadId */ - -#ifndef ACPI_THREAD_ID -#define ACPI_THREAD_ID ACPI_SIZE -#endif - /* Flags for AcpiOsAcquireLock/AcpiOsReleaseLock */ #ifndef ACPI_CPU_FLAGS @@ -456,21 +459,6 @@ typedef UINT8 ACPI_OWNER_ID; #define ACPI_OWNER_ID_MAX 0xFF -typedef struct uint64_struct -{ - UINT32 Lo; - UINT32 Hi; - -} UINT64_STRUCT; - -typedef union uint64_overlay -{ - UINT64 Full; - UINT64_STRUCT Part; - -} UINT64_OVERLAY; - - #define ACPI_INTEGER_BIT_SIZE 64 #define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ #define ACPI_MAX64_DECIMAL_DIGITS 20 diff --git a/sys/contrib/dev/acpica/include/acutils.h b/sys/contrib/dev/acpica/include/acutils.h index f729399154d..2d73da64fa4 100644 --- a/sys/contrib/dev/acpica/include/acutils.h +++ b/sys/contrib/dev/acpica/include/acutils.h @@ -818,24 +818,6 @@ AcpiUtStrtoul64 ( UINT32 Base, UINT64 *RetInteger); -void ACPI_INTERNAL_VAR_XFACE -AcpiUtPredefinedWarning ( - const char *ModuleName, - UINT32 LineNumber, - char *Pathname, - UINT8 NodeFlags, - const char *Format, - ...); - -void ACPI_INTERNAL_VAR_XFACE -AcpiUtPredefinedInfo ( - const char *ModuleName, - UINT32 LineNumber, - char *Pathname, - UINT8 NodeFlags, - const char *Format, - ...); - /* Values for Base above (16=Hex, 10=Decimal) */ #define ACPI_ANY_BASE 0 @@ -985,7 +967,44 @@ AcpiUtCreateList ( UINT16 ObjectSize, ACPI_MEMORY_LIST **ReturnCache); +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ -#endif + +/* + * utxferror - various error/warning output functions + */ +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedWarning ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedInfo ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...); + +void +AcpiUtNamespaceError ( + const char *ModuleName, + UINT32 LineNumber, + const char *InternalName, + ACPI_STATUS LookupStatus); + +void +AcpiUtMethodError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Message, + ACPI_NAMESPACE_NODE *Node, + const char *Path, + ACPI_STATUS LookupStatus); #endif /* _ACUTILS_H */ diff --git a/sys/contrib/dev/acpica/include/platform/acenv.h b/sys/contrib/dev/acpica/include/platform/acenv.h index b9ef33fa4f4..f3526c7f623 100644 --- a/sys/contrib/dev/acpica/include/platform/acenv.h +++ b/sys/contrib/dev/acpica/include/platform/acenv.h @@ -148,9 +148,10 @@ #define ACPI_CONSTANT_EVAL_ONLY #define ACPI_LARGE_NAMESPACE_NODE #define ACPI_DATA_TABLE_DISASSEMBLY +#define ACPI_SINGLE_THREADED #endif -/* AcpiExec configuration */ +/* AcpiExec and AcpiBin configuration */ #ifdef ACPI_EXEC_APP #define ACPI_APPLICATION @@ -159,6 +160,11 @@ #define ACPI_DBG_TRACK_ALLOCATIONS #endif +#ifdef ACPI_BIN_APP +#define ACPI_APPLICATION +#define ACPI_SINGLE_THREADED +#endif + /* Linkable ACPICA library */ #ifdef ACPI_LIBRARY @@ -275,6 +281,12 @@ #define ACPI_FLUSH_CPU_CACHE() #endif +/* "inline" keywords - configurable since inline is not standardized */ + +#ifndef ACPI_INLINE +#define ACPI_INLINE +#endif + /* * Configurable calling conventions: * diff --git a/sys/contrib/dev/acpica/include/platform/acfreebsd.h b/sys/contrib/dev/acpica/include/platform/acfreebsd.h index c835aaf665d..ad18a2da742 100644 --- a/sys/contrib/dev/acpica/include/platform/acfreebsd.h +++ b/sys/contrib/dev/acpica/include/platform/acfreebsd.h @@ -139,7 +139,6 @@ #include "opt_acpi.h" -#define ACPI_THREAD_ID lwpid_t #define ACPI_MUTEX_TYPE ACPI_OSL_MUTEX #ifdef ACPI_DEBUG @@ -166,7 +165,7 @@ #include #endif -#define ACPI_THREAD_ID pthread_t +#define ACPI_CAST_PTHREAD_T(pthread) ((ACPI_THREAD_ID) ACPI_TO_INTEGER (pthread)) #define ACPI_USE_STANDARD_HEADERS diff --git a/sys/contrib/dev/acpica/include/platform/acgcc.h b/sys/contrib/dev/acpica/include/platform/acgcc.h index d0098b1800a..9c7c9b94441 100644 --- a/sys/contrib/dev/acpica/include/platform/acgcc.h +++ b/sys/contrib/dev/acpica/include/platform/acgcc.h @@ -116,6 +116,8 @@ #ifndef __ACGCC_H__ #define __ACGCC_H__ +#define ACPI_INLINE __inline__ + /* Function name is used for debug output. Non-ANSI, compiler-dependent */ #define ACPI_GET_FUNCTION_NAME __FUNCTION__ diff --git a/sys/contrib/dev/acpica/namespace/nsrepair2.c b/sys/contrib/dev/acpica/namespace/nsrepair2.c index 25fdcbb620d..1cf0395a008 100644 --- a/sys/contrib/dev/acpica/namespace/nsrepair2.c +++ b/sys/contrib/dev/acpica/namespace/nsrepair2.c @@ -152,11 +152,21 @@ AcpiNsRepair_ALR ( ACPI_PREDEFINED_DATA *Data, ACPI_OPERAND_OBJECT **ReturnObjectPtr); +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_PREDEFINED_DATA *Data, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + static ACPI_STATUS AcpiNsRepair_FDE ( ACPI_PREDEFINED_DATA *Data, ACPI_OPERAND_OBJECT **ReturnObjectPtr); +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_PREDEFINED_DATA *Data, + ACPI_OPERAND_OBJECT **ReturnObjectPtr); + static ACPI_STATUS AcpiNsRepair_PSS ( ACPI_PREDEFINED_DATA *Data, @@ -196,8 +206,10 @@ AcpiNsSortList ( * As necessary: * * _ALR: Sort the list ascending by AmbientIlluminance + * _CID: Strings: uppercase all, remove any leading asterisk * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs + * _HID: Strings: uppercase all, remove any leading asterisk * _PSS: Sort the list descending by Power * _TSS: Sort the list descending by Power * @@ -211,8 +223,10 @@ AcpiNsSortList ( static const ACPI_REPAIR_INFO AcpiNsRepairableNames[] = { {"_ALR", AcpiNsRepair_ALR}, + {"_CID", AcpiNsRepair_CID}, {"_FDE", AcpiNsRepair_FDE}, {"_GTM", AcpiNsRepair_FDE}, /* _GTM has same repair as _FDE */ + {"_HID", AcpiNsRepair_HID}, {"_PSS", AcpiNsRepair_PSS}, {"_TSS", AcpiNsRepair_TSS}, {{0,0,0,0}, NULL} /* Table terminator */ @@ -425,6 +439,172 @@ AcpiNsRepair_FDE ( } +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_CID + * + * PARAMETERS: Data - Pointer to validation data structure + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _CID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * If a Package, ensure same for all string elements. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_CID ( + ACPI_PREDEFINED_DATA *Data, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT **ElementPtr; + ACPI_OPERAND_OBJECT *OriginalElement; + UINT16 OriginalRefCount; + UINT32 i; + + + /* Check for _CID as a simple string */ + + if (ReturnObject->Common.Type == ACPI_TYPE_STRING) + { + Status = AcpiNsRepair_HID (Data, ReturnObjectPtr); + return (Status); + } + + /* Exit if not a Package */ + + if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + return (AE_OK); + } + + /* Examine each element of the _CID package */ + + ElementPtr = ReturnObject->Package.Elements; + for (i = 0; i < ReturnObject->Package.Count; i++) + { + OriginalElement = *ElementPtr; + OriginalRefCount = OriginalElement->Common.ReferenceCount; + + Status = AcpiNsRepair_HID (Data, ElementPtr); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Take care with reference counts */ + + if (OriginalElement != *ElementPtr) + { + /* Element was replaced */ + + (*ElementPtr)->Common.ReferenceCount = + OriginalRefCount; + + AcpiUtRemoveReference (OriginalElement); + } + + ElementPtr++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiNsRepair_HID + * + * PARAMETERS: Data - Pointer to validation data structure + * ReturnObjectPtr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if object is OK or was repaired successfully + * + * DESCRIPTION: Repair for the _HID object. If a string, ensure that all + * letters are uppercase and that there is no leading asterisk. + * + *****************************************************************************/ + +static ACPI_STATUS +AcpiNsRepair_HID ( + ACPI_PREDEFINED_DATA *Data, + ACPI_OPERAND_OBJECT **ReturnObjectPtr) +{ + ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; + ACPI_OPERAND_OBJECT *NewString; + char *Source; + char *Dest; + + + ACPI_FUNCTION_NAME (NsRepair_HID); + + + /* We only care about string _HID objects (not integers) */ + + if (ReturnObject->Common.Type != ACPI_TYPE_STRING) + { + return (AE_OK); + } + + if (ReturnObject->String.Length == 0) + { + ACPI_WARN_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags, + "Invalid zero-length _HID or _CID string")); + + /* Return AE_OK anyway, let driver handle it */ + + Data->Flags |= ACPI_OBJECT_REPAIRED; + return (AE_OK); + } + + /* It is simplest to always create a new string object */ + + NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); + if (!NewString) + { + return (AE_NO_MEMORY); + } + + /* + * Remove a leading asterisk if present. For some unknown reason, there + * are many machines in the field that contains IDs like this. + * + * Examples: "*PNP0C03", "*ACPI0003" + */ + Source = ReturnObject->String.Pointer; + if (*Source == '*') + { + Source++; + NewString->String.Length--; + + ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, + "%s: Removed invalid leading asterisk\n", Data->Pathname)); + } + + /* + * Copy and uppercase the string. From the ACPI specification: + * + * A valid PNP ID must be of the form "AAA####" where A is an uppercase + * letter and # is a hex digit. A valid ACPI ID must be of the form + * "ACPI####" where # is a hex digit. + */ + for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) + { + *Dest = (char) ACPI_TOUPPER (*Source); + } + + AcpiUtRemoveReference (ReturnObject); + *ReturnObjectPtr = NewString; + return (AE_OK); +} + + /****************************************************************************** * * FUNCTION: AcpiNsRepair_TSS diff --git a/sys/contrib/dev/acpica/namespace/nsutils.c b/sys/contrib/dev/acpica/namespace/nsutils.c index 681f85dc545..1ddfc38da5e 100644 --- a/sys/contrib/dev/acpica/namespace/nsutils.c +++ b/sys/contrib/dev/acpica/namespace/nsutils.c @@ -137,118 +137,6 @@ AcpiNsFindParentName ( #endif -/******************************************************************************* - * - * FUNCTION: AcpiNsReportError - * - * PARAMETERS: ModuleName - Caller's module name (for error output) - * LineNumber - Caller's line number (for error output) - * InternalName - Name or path of the namespace node - * LookupStatus - Exception code from NS lookup - * - * RETURN: None - * - * DESCRIPTION: Print warning message with full pathname - * - ******************************************************************************/ - -void -AcpiNsReportError ( - const char *ModuleName, - UINT32 LineNumber, - const char *InternalName, - ACPI_STATUS LookupStatus) -{ - ACPI_STATUS Status; - UINT32 BadName; - char *Name = NULL; - - - AcpiOsPrintf ("ACPI Error (%s-%04d): ", ModuleName, LineNumber); - - if (LookupStatus == AE_BAD_CHARACTER) - { - /* There is a non-ascii character in the name */ - - ACPI_MOVE_32_TO_32 (&BadName, ACPI_CAST_PTR (UINT32, InternalName)); - AcpiOsPrintf ("[0x%4.4X] (NON-ASCII)", BadName); - } - else - { - /* Convert path to external format */ - - Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, - InternalName, NULL, &Name); - - /* Print target name */ - - if (ACPI_SUCCESS (Status)) - { - AcpiOsPrintf ("[%s]", Name); - } - else - { - AcpiOsPrintf ("[COULD NOT EXTERNALIZE NAME]"); - } - - if (Name) - { - ACPI_FREE (Name); - } - } - - AcpiOsPrintf (" Namespace lookup failure, %s\n", - AcpiFormatException (LookupStatus)); -} - - -/******************************************************************************* - * - * FUNCTION: AcpiNsReportMethodError - * - * PARAMETERS: ModuleName - Caller's module name (for error output) - * LineNumber - Caller's line number (for error output) - * Message - Error message to use on failure - * PrefixNode - Prefix relative to the path - * Path - Path to the node (optional) - * MethodStatus - Execution status - * - * RETURN: None - * - * DESCRIPTION: Print warning message with full pathname - * - ******************************************************************************/ - -void -AcpiNsReportMethodError ( - const char *ModuleName, - UINT32 LineNumber, - const char *Message, - ACPI_NAMESPACE_NODE *PrefixNode, - const char *Path, - ACPI_STATUS MethodStatus) -{ - ACPI_STATUS Status; - ACPI_NAMESPACE_NODE *Node = PrefixNode; - - - AcpiOsPrintf ("ACPI Error (%s-%04d): ", ModuleName, LineNumber); - - if (Path) - { - Status = AcpiNsGetNode (PrefixNode, Path, ACPI_NS_NO_UPSEARCH, - &Node); - if (ACPI_FAILURE (Status)) - { - AcpiOsPrintf ("[Could not get node by pathname]"); - } - } - - AcpiNsPrintNodePathname (Node, Message); - AcpiOsPrintf (", %s\n", AcpiFormatException (MethodStatus)); -} - - /******************************************************************************* * * FUNCTION: AcpiNsPrintNodePathname diff --git a/sys/contrib/dev/acpica/osunixxf.c b/sys/contrib/dev/acpica/osunixxf.c index 2e3e7287abd..fcb9c002c71 100644 --- a/sys/contrib/dev/acpica/osunixxf.c +++ b/sys/contrib/dev/acpica/osunixxf.c @@ -115,12 +115,11 @@ /* - * These interfaces are required in order to compile the ASL compiler under - * Linux or other Unix-like system. + * These interfaces are required in order to compile the ASL compiler and the + * various ACPICA tools under Linux or other Unix-like system. * * Note: Use #define __APPLE__ for OS X generation. */ - #include #include #include @@ -157,6 +156,12 @@ AeTableOverride ( typedef void* (*PTHREAD_CALLBACK) (void *); +/* Apple-specific */ + +#ifdef __APPLE__ +#define sem_destroy sem_close +#endif + /****************************************************************************** * @@ -166,12 +171,13 @@ typedef void* (*PTHREAD_CALLBACK) (void *); * * RETURN: Status * - * DESCRIPTION: Init and terminate. Nothing to do. + * DESCRIPTION: Init and terminate. Nothing to do. * *****************************************************************************/ ACPI_STATUS -AcpiOsInitialize (void) +AcpiOsInitialize ( + void) { AcpiGbl_OutputFile = stdout; @@ -180,7 +186,8 @@ AcpiOsInitialize (void) ACPI_STATUS -AcpiOsTerminate (void) +AcpiOsTerminate ( + void) { return (AE_OK); @@ -195,7 +202,7 @@ AcpiOsTerminate (void) * * RETURN: RSDP physical address * - * DESCRIPTION: Gets the root pointer (RSDP) + * DESCRIPTION: Gets the ACPI root pointer (RSDP) * *****************************************************************************/ @@ -212,10 +219,10 @@ AcpiOsGetRootPointer ( * * FUNCTION: AcpiOsPredefinedOverride * - * PARAMETERS: InitVal - Initial value of the predefined object - * NewVal - The new value for the object + * PARAMETERS: InitVal - Initial value of the predefined object + * NewVal - The new value for the object * - * RETURN: Status, pointer to value. Null pointer returned if not + * RETURN: Status, pointer to value. Null pointer returned if not * overriding. * * DESCRIPTION: Allow the OS to override predefined names @@ -242,10 +249,11 @@ AcpiOsPredefinedOverride ( * * FUNCTION: AcpiOsTableOverride * - * PARAMETERS: ExistingTable - Header of current table (probably firmware) - * NewTable - Where an entire new table is returned. + * PARAMETERS: ExistingTable - Header of current table (probably + * firmware) + * NewTable - Where an entire new table is returned. * - * RETURN: Status, pointer to new table. Null pointer returned if no + * RETURN: Status, pointer to new table. Null pointer returned if no * table is available to override * * DESCRIPTION: Return a different version of a table if one is available @@ -301,7 +309,7 @@ AcpiOsRedirectOutput ( * * FUNCTION: AcpiOsPrintf * - * PARAMETERS: fmt, ... Standard printf format + * PARAMETERS: fmt, ... - Standard printf format * * RETURN: None * @@ -327,8 +335,8 @@ AcpiOsPrintf ( * * FUNCTION: AcpiOsVprintf * - * PARAMETERS: fmt Standard printf format - * args Argument list + * PARAMETERS: fmt - Standard printf format + * args - Argument list * * RETURN: None * @@ -375,8 +383,8 @@ AcpiOsVprintf ( * * FUNCTION: AcpiOsGetLine * - * PARAMETERS: fmt Standard printf format - * args Argument list + * PARAMETERS: fmt - Standard printf format + * args - Argument list * * RETURN: Actual bytes read * @@ -412,14 +420,15 @@ AcpiOsGetLine ( return (i); } + /****************************************************************************** * * FUNCTION: AcpiOsMapMemory * - * PARAMETERS: where Physical address of memory to be mapped - * length How much memory to map + * PARAMETERS: where - Physical address of memory to be mapped + * length - How much memory to map * - * RETURN: Pointer to mapped memory. Null on error. + * RETURN: Pointer to mapped memory. Null on error. * * DESCRIPTION: Map physical memory into caller's address space * @@ -439,12 +448,12 @@ AcpiOsMapMemory ( * * FUNCTION: AcpiOsUnmapMemory * - * PARAMETERS: where Logical address of memory to be unmapped - * length How much memory to unmap + * PARAMETERS: where - Logical address of memory to be unmapped + * length - How much memory to unmap * * RETURN: None. * - * DESCRIPTION: Delete a previously created mapping. Where and Length must + * DESCRIPTION: Delete a previously created mapping. Where and Length must * correspond to a previous mapping exactly. * *****************************************************************************/ @@ -463,11 +472,11 @@ AcpiOsUnmapMemory ( * * FUNCTION: AcpiOsAllocate * - * PARAMETERS: Size Amount to allocate, in bytes + * PARAMETERS: Size - Amount to allocate, in bytes * - * RETURN: Pointer to the new allocation. Null on error. + * RETURN: Pointer to the new allocation. Null on error. * - * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. + * DESCRIPTION: Allocate memory. Algorithm is dependent on the OS. * *****************************************************************************/ @@ -487,7 +496,7 @@ AcpiOsAllocate ( * * FUNCTION: AcpiOsFree * - * PARAMETERS: mem Pointer to previously allocated memory + * PARAMETERS: mem - Pointer to previously allocated memory * * RETURN: None. * @@ -504,6 +513,52 @@ AcpiOsFree ( } +#ifdef ACPI_SINGLE_THREADED +/****************************************************************************** + * + * FUNCTION: Semaphore stub functions + * + * DESCRIPTION: Stub functions used for single-thread applications that do + * not require semaphore synchronization. Full implementations + * of these functions appear after the stubs. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiOsCreateSemaphore ( + UINT32 MaxUnits, + UINT32 InitialUnits, + ACPI_HANDLE *OutHandle) +{ + *OutHandle = (ACPI_HANDLE) 1; + return (AE_OK); +} + +ACPI_STATUS +AcpiOsDeleteSemaphore ( + ACPI_HANDLE Handle) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsWaitSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units, + UINT16 Timeout) +{ + return (AE_OK); +} + +ACPI_STATUS +AcpiOsSignalSemaphore ( + ACPI_HANDLE Handle, + UINT32 Units) +{ + return (AE_OK); +} + +#else /****************************************************************************** * * FUNCTION: AcpiOsCreateSemaphore @@ -532,10 +587,15 @@ AcpiOsCreateSemaphore ( } #ifdef __APPLE__ - Sem = sem_open (tmpnam (NULL), O_EXCL|O_CREAT, 0755, InitialUnits); - if (!Sem) { - return (AE_NO_MEMORY); + char *SemaphoreName = tmpnam (NULL); + + Sem = sem_open (SemaphoreName, O_EXCL|O_CREAT, 0755, InitialUnits); + if (!Sem) + { + return (AE_NO_MEMORY); + } + sem_unlink (SemaphoreName); /* This just deletes the name */ } #else @@ -719,6 +779,8 @@ AcpiOsSignalSemaphore ( return (AE_OK); } +#endif /* ACPI_SINGLE_THREADED */ + /****************************************************************************** * @@ -767,13 +829,13 @@ AcpiOsReleaseLock ( * * FUNCTION: AcpiOsInstallInterruptHandler * - * PARAMETERS: InterruptNumber Level handler should respond to. - * Isr Address of the ACPI interrupt handler - * ExceptPtr Where status is returned + * PARAMETERS: InterruptNumber - Level handler should respond to. + * Isr - Address of the ACPI interrupt handler + * ExceptPtr - Where status is returned * * RETURN: Handle to the newly installed handler. * - * DESCRIPTION: Install an interrupt handler. Used to install the ACPI + * DESCRIPTION: Install an interrupt handler. Used to install the ACPI * OS-independent handler. * *****************************************************************************/ @@ -793,7 +855,7 @@ AcpiOsInstallInterruptHandler ( * * FUNCTION: AcpiOsRemoveInterruptHandler * - * PARAMETERS: Handle Returned when handler was installed + * PARAMETERS: Handle - Returned when handler was installed * * RETURN: Status * @@ -815,9 +877,9 @@ AcpiOsRemoveInterruptHandler ( * * FUNCTION: AcpiOsExecute * - * PARAMETERS: Type - Type of execution - * Function - Address of the function to execute - * Context - Passed as a parameter to the function + * PARAMETERS: Type - Type of execution + * Function - Address of the function to execute + * Context - Passed as a parameter to the function * * RETURN: Status. * @@ -848,7 +910,7 @@ AcpiOsExecute ( * * FUNCTION: AcpiOsStall * - * PARAMETERS: microseconds To sleep + * PARAMETERS: microseconds - Time to sleep * * RETURN: Blocks until sleep is completed. * @@ -872,7 +934,7 @@ AcpiOsStall ( * * FUNCTION: AcpiOsSleep * - * PARAMETERS: milliseconds To sleep + * PARAMETERS: milliseconds - Time to sleep * * RETURN: Blocks until sleep is completed. * @@ -893,6 +955,7 @@ AcpiOsSleep ( usleep ((milliseconds % 1000) * 1000); /* Sleep for remaining usecs */ } + /****************************************************************************** * * FUNCTION: AcpiOsGetTimer @@ -906,7 +969,8 @@ AcpiOsSleep ( *****************************************************************************/ UINT64 -AcpiOsGetTimer (void) +AcpiOsGetTimer ( + void) { struct timeval time; @@ -923,10 +987,10 @@ AcpiOsGetTimer (void) * * FUNCTION: AcpiOsReadPciConfiguration * - * PARAMETERS: PciId Seg/Bus/Dev - * Register Device Register - * Value Buffer where value is placed - * Width Number of bits + * PARAMETERS: PciId - Seg/Bus/Dev + * Register - Device Register + * Value - Buffer where value is placed + * Width - Number of bits * * RETURN: Status * @@ -950,10 +1014,10 @@ AcpiOsReadPciConfiguration ( * * FUNCTION: AcpiOsWritePciConfiguration * - * PARAMETERS: PciId Seg/Bus/Dev - * Register Device Register - * Value Value to be written - * Width Number of bits + * PARAMETERS: PciId - Seg/Bus/Dev + * Register - Device Register + * Value - Value to be written + * Width - Number of bits * * RETURN: Status. * @@ -972,24 +1036,14 @@ AcpiOsWritePciConfiguration ( return (AE_OK); } -/* TEMPORARY STUB FUNCTION */ -void -AcpiOsDerivePciId( - ACPI_HANDLE Device, - ACPI_HANDLE Region, - ACPI_PCI_ID **PciId) -{ - -} - /****************************************************************************** * * FUNCTION: AcpiOsReadPort * - * PARAMETERS: Address Address of I/O port/register to read - * Value Where value is placed - * Width Number of bits + * PARAMETERS: Address - Address of I/O port/register to read + * Value - Where value is placed + * Width - Number of bits * * RETURN: Value read from port * @@ -1030,9 +1084,9 @@ AcpiOsReadPort ( * * FUNCTION: AcpiOsWritePort * - * PARAMETERS: Address Address of I/O port/register to write - * Value Value to write - * Width Number of bits + * PARAMETERS: Address - Address of I/O port/register to write + * Value - Value to write + * Width - Number of bits * * RETURN: None * @@ -1055,9 +1109,9 @@ AcpiOsWritePort ( * * FUNCTION: AcpiOsReadMemory * - * PARAMETERS: Address Physical Memory Address to read - * Value Where value is placed - * Width Number of bits + * PARAMETERS: Address - Physical Memory Address to read + * Value - Where value is placed + * Width - Number of bits * * RETURN: Value read from physical memory address * @@ -1091,9 +1145,9 @@ AcpiOsReadMemory ( * * FUNCTION: AcpiOsWriteMemory * - * PARAMETERS: Address Physical Memory Address to write - * Value Value to write - * Width Number of bits + * PARAMETERS: Address - Physical Memory Address to write + * Value - Value to write + * Width - Number of bits * * RETURN: None * @@ -1166,18 +1220,16 @@ AcpiOsWritable ( * * RETURN: Id of the running thread * - * DESCRIPTION: Get the Id of the current (running) thread - * - * NOTE: The environment header should contain this line: - * #define ACPI_THREAD_ID pthread_t + * DESCRIPTION: Get the ID of the current (running) thread * *****************************************************************************/ ACPI_THREAD_ID -AcpiOsGetThreadId (void) +AcpiOsGetThreadId ( + void) { - return (pthread_self ()); + return (ACPI_CAST_PTHREAD_T (pthread_self())); } @@ -1185,8 +1237,8 @@ AcpiOsGetThreadId (void) * * FUNCTION: AcpiOsSignal * - * PARAMETERS: Function ACPI CA signal function code - * Info Pointer to function-dependent structure + * PARAMETERS: Function - ACPI CA signal function code + * Info - Pointer to function-dependent structure * * RETURN: Status * @@ -1214,5 +1266,3 @@ AcpiOsSignal ( return (AE_OK); } - - diff --git a/sys/contrib/dev/acpica/tables/tbfadt.c b/sys/contrib/dev/acpica/tables/tbfadt.c index af7d068b862..d03dae42559 100644 --- a/sys/contrib/dev/acpica/tables/tbfadt.c +++ b/sys/contrib/dev/acpica/tables/tbfadt.c @@ -124,7 +124,7 @@ /* Local prototypes */ -static inline void +static ACPI_INLINE void AcpiTbInitGenericAddress ( ACPI_GENERIC_ADDRESS *GenericAddress, UINT8 SpaceId, @@ -273,7 +273,7 @@ static ACPI_FADT_PM_INFO FadtPmInfoTable[] = * ******************************************************************************/ -static inline void +static ACPI_INLINE void AcpiTbInitGenericAddress ( ACPI_GENERIC_ADDRESS *GenericAddress, UINT8 SpaceId, diff --git a/sys/contrib/dev/acpica/tools/acpiexec/aecommon.h b/sys/contrib/dev/acpica/tools/acpiexec/aecommon.h index 0ceddea4960..06bdece4518 100644 --- a/sys/contrib/dev/acpica/tools/acpiexec/aecommon.h +++ b/sys/contrib/dev/acpica/tools/acpiexec/aecommon.h @@ -139,6 +139,18 @@ extern FILE *AcpiGbl_DebugFile; extern BOOLEAN AcpiGbl_IgnoreErrors; extern UINT8 AcpiGbl_RegionFillValue; +/* Check for unexpected exceptions */ + +#define AE_CHECK_STATUS(Name, Status, Expected) \ + if (Status != Expected) \ + { \ + AcpiOsPrintf ("Unexpected %s from %s (%s-%d)\n", \ + AcpiFormatException (Status), #Name, _AcpiModuleName, __LINE__); \ + } + +/* Check for unexpected non-AE_OK errors */ + +#define AE_CHECK_OK(Name, Status) AE_CHECK_STATUS (Name, Status, AE_OK); typedef struct ae_table_desc { @@ -173,7 +185,7 @@ typedef struct ae_debug_regions #define OSD_PRINT(lvl,fp) TEST_OUTPUT_LEVEL(lvl) {\ AcpiOsPrintf PARAM_LIST(fp);} -void __cdecl +void ACPI_SYSTEM_XFACE AeCtrlCHandler ( int Sig); diff --git a/sys/contrib/dev/acpica/utilities/utdebug.c b/sys/contrib/dev/acpica/utilities/utdebug.c index 99670b58f36..8d7b942c488 100644 --- a/sys/contrib/dev/acpica/utilities/utdebug.c +++ b/sys/contrib/dev/acpica/utilities/utdebug.c @@ -279,9 +279,8 @@ AcpiDebugPrint ( if (ACPI_LV_THREADS & AcpiDbgLevel) { AcpiOsPrintf ( - "\n**** Context Switch from TID %p to TID %p ****\n\n", - ACPI_CAST_PTR (void, AcpiGbl_PrevThreadId), - ACPI_CAST_PTR (void, ThreadId)); + "\n**** Context Switch from TID %u to TID %u ****\n\n", + (UINT32) AcpiGbl_PrevThreadId, (UINT32) ThreadId); } AcpiGbl_PrevThreadId = ThreadId; @@ -295,7 +294,7 @@ AcpiDebugPrint ( if (ACPI_LV_THREADS & AcpiDbgLevel) { - AcpiOsPrintf ("[%p] ", ACPI_CAST_PTR (void, ThreadId)); + AcpiOsPrintf ("[%u] ", (UINT32) ThreadId); } AcpiOsPrintf ("[%02ld] %-22.22s: ", diff --git a/sys/contrib/dev/acpica/utilities/utglobal.c b/sys/contrib/dev/acpica/utilities/utglobal.c index d0bde78685e..ca2ce7ff907 100644 --- a/sys/contrib/dev/acpica/utilities/utglobal.c +++ b/sys/contrib/dev/acpica/utilities/utglobal.c @@ -244,7 +244,9 @@ ACPI_EXPORT_SYMBOL (AcpiFormatException) * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run * during the initialization sequence. * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to - * perform a Notify() operation on it. + * perform a Notify() operation on it. 09/2010: Changed to type Device. + * This still allows notifies, but does not confuse host code that + * searches for valid ThermalZone objects. */ const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames[] = { @@ -252,7 +254,7 @@ const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames[] = {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_SB_", ACPI_TYPE_DEVICE, NULL}, {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL}, - {"_TZ_", ACPI_TYPE_THERMAL, NULL}, + {"_TZ_", ACPI_TYPE_DEVICE, NULL}, {"_REV", ACPI_TYPE_INTEGER, (char *) ACPI_CA_SUPPORT_LEVEL}, {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, (char *) 1}, diff --git a/sys/contrib/dev/acpica/utilities/utids.c b/sys/contrib/dev/acpica/utilities/utids.c index 6e5f8333ffb..a369598d868 100644 --- a/sys/contrib/dev/acpica/utilities/utids.c +++ b/sys/contrib/dev/acpica/utilities/utids.c @@ -123,51 +123,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utids") -/* Local prototypes */ - -static void -AcpiUtCopyIdString ( - char *Destination, - char *Source); - - -/******************************************************************************* - * - * FUNCTION: AcpiUtCopyIdString - * - * PARAMETERS: Destination - Where to copy the string - * Source - Source string - * - * RETURN: None - * - * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods. - * Performs removal of a leading asterisk if present -- workaround - * for a known issue on a bunch of machines. - * - ******************************************************************************/ - -static void -AcpiUtCopyIdString ( - char *Destination, - char *Source) -{ - - /* - * Workaround for ID strings that have a leading asterisk. This construct - * is not allowed by the ACPI specification (ID strings must be - * alphanumeric), but enough existing machines have this embedded in their - * ID strings that the following code is useful. - */ - if (*Source == '*') - { - Source++; - } - - /* Do the actual copy */ - - ACPI_STRCPY (Destination, Source); -} - /******************************************************************************* * @@ -240,7 +195,7 @@ AcpiUtExecute_HID ( } else { - AcpiUtCopyIdString (Hid->String, ObjDesc->String.Pointer); + ACPI_STRCPY (Hid->String, ObjDesc->String.Pointer); } Hid->Length = Length; @@ -327,7 +282,7 @@ AcpiUtExecute_UID ( } else { - AcpiUtCopyIdString (Uid->String, ObjDesc->String.Pointer); + ACPI_STRCPY (Uid->String, ObjDesc->String.Pointer); } Uid->Length = Length; @@ -471,7 +426,7 @@ AcpiUtExecute_CID ( { /* Copy the String CID from the returned object */ - AcpiUtCopyIdString (NextIdString, CidObjects[i]->String.Pointer); + ACPI_STRCPY (NextIdString, CidObjects[i]->String.Pointer); Length = CidObjects[i]->String.Length + 1; } diff --git a/sys/contrib/dev/acpica/utilities/utmath.c b/sys/contrib/dev/acpica/utilities/utmath.c index f6d5f7cddb5..508ed2a86cb 100644 --- a/sys/contrib/dev/acpica/utilities/utmath.c +++ b/sys/contrib/dev/acpica/utilities/utmath.c @@ -124,12 +124,32 @@ ACPI_MODULE_NAME ("utmath") /* - * Support for double-precision integer divide. This code is included here - * in order to support kernel environments where the double-precision math - * library is not available. + * Optional support for 64-bit double-precision integer divide. This code + * is configurable and is implemented in order to support 32-bit kernel + * environments where a 64-bit double-precision math library is not available. + * + * Support for a more normal 64-bit divide/modulo (with check for a divide- + * by-zero) appears after this optional section of code. */ - #ifndef ACPI_USE_NATIVE_DIVIDE + +/* Structures used only for 64-bit divide */ + +typedef struct uint64_struct +{ + UINT32 Lo; + UINT32 Hi; + +} UINT64_STRUCT; + +typedef union uint64_overlay +{ + UINT64 Full; + UINT64_STRUCT Part; + +} UINT64_OVERLAY; + + /******************************************************************************* * * FUNCTION: AcpiUtShortDivide diff --git a/sys/contrib/dev/acpica/utilities/utmisc.c b/sys/contrib/dev/acpica/utilities/utmisc.c index f3ada2f625d..7bcfd575e52 100644 --- a/sys/contrib/dev/acpica/utilities/utmisc.c +++ b/sys/contrib/dev/acpica/utilities/utmisc.c @@ -124,12 +124,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utmisc") -/* - * Common suffix for messages - */ -#define ACPI_COMMON_MSG_SUFFIX \ - AcpiOsPrintf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, ModuleName, LineNumber) - /******************************************************************************* * @@ -1337,196 +1331,3 @@ AcpiUtWalkPackageTree ( } -/******************************************************************************* - * - * FUNCTION: AcpiError, AcpiException, AcpiWarning, AcpiInfo - * - * PARAMETERS: ModuleName - Caller's module name (for error output) - * LineNumber - Caller's line number (for error output) - * Format - Printf format string + additional args - * - * RETURN: None - * - * DESCRIPTION: Print message with module/line/version info - * - ******************************************************************************/ - -void ACPI_INTERNAL_VAR_XFACE -AcpiError ( - const char *ModuleName, - UINT32 LineNumber, - const char *Format, - ...) -{ - va_list args; - - - AcpiOsPrintf ("ACPI Error: "); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - ACPI_COMMON_MSG_SUFFIX; - va_end (args); -} - -void ACPI_INTERNAL_VAR_XFACE -AcpiException ( - const char *ModuleName, - UINT32 LineNumber, - ACPI_STATUS Status, - const char *Format, - ...) -{ - va_list args; - - - AcpiOsPrintf ("ACPI Exception: %s, ", AcpiFormatException (Status)); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - ACPI_COMMON_MSG_SUFFIX; - va_end (args); -} - -void ACPI_INTERNAL_VAR_XFACE -AcpiWarning ( - const char *ModuleName, - UINT32 LineNumber, - const char *Format, - ...) -{ - va_list args; - - - AcpiOsPrintf ("ACPI Warning: "); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - ACPI_COMMON_MSG_SUFFIX; - va_end (args); -} - -void ACPI_INTERNAL_VAR_XFACE -AcpiInfo ( - const char *ModuleName, - UINT32 LineNumber, - const char *Format, - ...) -{ - va_list args; - -#ifdef _KERNEL - /* Temporarily hide too verbose printfs. */ - if (!bootverbose) - return; -#endif - - AcpiOsPrintf ("ACPI: "); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - AcpiOsPrintf ("\n"); - va_end (args); -} - -ACPI_EXPORT_SYMBOL (AcpiError) -ACPI_EXPORT_SYMBOL (AcpiException) -ACPI_EXPORT_SYMBOL (AcpiWarning) -ACPI_EXPORT_SYMBOL (AcpiInfo) - - -/******************************************************************************* - * - * FUNCTION: AcpiUtPredefinedWarning - * - * PARAMETERS: ModuleName - Caller's module name (for error output) - * LineNumber - Caller's line number (for error output) - * Pathname - Full pathname to the node - * NodeFlags - From Namespace node for the method/object - * Format - Printf format string + additional args - * - * RETURN: None - * - * DESCRIPTION: Warnings for the predefined validation module. Messages are - * only emitted the first time a problem with a particular - * method/object is detected. This prevents a flood of error - * messages for methods that are repeatedly evaluated. - * - ******************************************************************************/ - -void ACPI_INTERNAL_VAR_XFACE -AcpiUtPredefinedWarning ( - const char *ModuleName, - UINT32 LineNumber, - char *Pathname, - UINT8 NodeFlags, - const char *Format, - ...) -{ - va_list args; - - - /* - * Warning messages for this method/object will be disabled after the - * first time a validation fails or an object is successfully repaired. - */ - if (NodeFlags & ANOBJ_EVALUATED) - { - return; - } - - AcpiOsPrintf ("ACPI Warning for %s: ", Pathname); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - ACPI_COMMON_MSG_SUFFIX; - va_end (args); -} - -/******************************************************************************* - * - * FUNCTION: AcpiUtPredefinedInfo - * - * PARAMETERS: ModuleName - Caller's module name (for error output) - * LineNumber - Caller's line number (for error output) - * Pathname - Full pathname to the node - * NodeFlags - From Namespace node for the method/object - * Format - Printf format string + additional args - * - * RETURN: None - * - * DESCRIPTION: Info messages for the predefined validation module. Messages - * are only emitted the first time a problem with a particular - * method/object is detected. This prevents a flood of - * messages for methods that are repeatedly evaluated. - * - ******************************************************************************/ - -void ACPI_INTERNAL_VAR_XFACE -AcpiUtPredefinedInfo ( - const char *ModuleName, - UINT32 LineNumber, - char *Pathname, - UINT8 NodeFlags, - const char *Format, - ...) -{ - va_list args; - - - /* - * Warning messages for this method/object will be disabled after the - * first time a validation fails or an object is successfully repaired. - */ - if (NodeFlags & ANOBJ_EVALUATED) - { - return; - } - - AcpiOsPrintf ("ACPI Info for %s: ", Pathname); - - va_start (args, Format); - AcpiOsVprintf (Format, args); - ACPI_COMMON_MSG_SUFFIX; - va_end (args); -} diff --git a/sys/contrib/dev/acpica/utilities/utmutex.c b/sys/contrib/dev/acpica/utilities/utmutex.c index 14cab79d6bb..43204bae9fc 100644 --- a/sys/contrib/dev/acpica/utilities/utmutex.c +++ b/sys/contrib/dev/acpica/utilities/utmutex.c @@ -348,16 +348,16 @@ AcpiUtAcquireMutex ( if (i == MutexId) { ACPI_ERROR ((AE_INFO, - "Mutex [%s] already acquired by this thread [%p]", + "Mutex [%s] already acquired by this thread [%u]", AcpiUtGetMutexName (MutexId), - ACPI_CAST_PTR (void, ThisThreadId))); + (UINT32) ThisThreadId)); return (AE_ALREADY_ACQUIRED); } ACPI_ERROR ((AE_INFO, - "Invalid acquire order: Thread %p owns [%s], wants [%s]", - ACPI_CAST_PTR (void, ThisThreadId), AcpiUtGetMutexName (i), + "Invalid acquire order: Thread %u owns [%s], wants [%s]", + (UINT32) ThisThreadId, AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId))); return (AE_ACQUIRE_DEADLOCK); @@ -367,15 +367,15 @@ AcpiUtAcquireMutex ( #endif ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, - "Thread %p attempting to acquire Mutex [%s]\n", - ACPI_CAST_PTR (void, ThisThreadId), AcpiUtGetMutexName (MutexId))); + "Thread %u attempting to acquire Mutex [%s]\n", + (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId))); Status = AcpiOsAcquireMutex (AcpiGbl_MutexInfo[MutexId].Mutex, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %p acquired Mutex [%s]\n", - ACPI_CAST_PTR (void, ThisThreadId), AcpiUtGetMutexName (MutexId))); + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n", + (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId))); AcpiGbl_MutexInfo[MutexId].UseCount++; AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId; @@ -383,8 +383,8 @@ AcpiUtAcquireMutex ( else { ACPI_EXCEPTION ((AE_INFO, Status, - "Thread %p could not acquire Mutex [0x%X]", - ACPI_CAST_PTR (void, ThisThreadId), MutexId)); + "Thread %u could not acquire Mutex [0x%X]", + (UINT32) ThisThreadId, MutexId)); } return (Status); @@ -414,8 +414,8 @@ AcpiUtReleaseMutex ( ThisThreadId = AcpiOsGetThreadId (); - ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n", - ACPI_CAST_PTR (void, ThisThreadId), AcpiUtGetMutexName (MutexId))); + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", + (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId))); if (MutexId > ACPI_MAX_MUTEX) { diff --git a/sys/contrib/dev/acpica/utilities/utosi.c b/sys/contrib/dev/acpica/utilities/utosi.c index 49ff73b9224..ea37f251332 100644 --- a/sys/contrib/dev/acpica/utilities/utosi.c +++ b/sys/contrib/dev/acpica/utilities/utosi.c @@ -147,6 +147,7 @@ static ACPI_INTERFACE_INFO AcpiDefaultSupportedInterfaces[] = {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */ {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ + {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ /* Feature Group Strings */ diff --git a/sys/contrib/dev/acpica/utilities/utxferror.c b/sys/contrib/dev/acpica/utilities/utxferror.c new file mode 100644 index 00000000000..8e2cd93f6f9 --- /dev/null +++ b/sys/contrib/dev/acpica/utilities/utxferror.c @@ -0,0 +1,555 @@ +/******************************************************************************* + * + * Module Name: utxferror - Various error/warning output functions + * + ******************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + *****************************************************************************/ + +#define __UTXFERROR_C__ + +#include +#include +#include + + +#define _COMPONENT ACPI_UTILITIES + ACPI_MODULE_NAME ("utxferror") + +/* + * This module is used for the in-kernel ACPICA as well as the ACPICA + * tools/applications. + * + * For the iASL compiler case, the output is redirected to stderr so that + * any of the various ACPI errors and warnings do not appear in the output + * files, for either the compiler or disassembler portions of the tool. + */ +#ifdef ACPI_ASL_COMPILER +#include + +extern FILE *AcpiGbl_OutputFile; + +#define ACPI_MSG_REDIRECT_BEGIN \ + FILE *OutputFile = AcpiGbl_OutputFile; \ + AcpiOsRedirectOutput (stderr); + +#define ACPI_MSG_REDIRECT_END \ + AcpiOsRedirectOutput (OutputFile); + +#else +/* + * non-iASL case - no redirection, nothing to do + */ +#define ACPI_MSG_REDIRECT_BEGIN +#define ACPI_MSG_REDIRECT_END +#endif + +/* + * Common message prefixes + */ +#define ACPI_MSG_ERROR "ACPI Error: " +#define ACPI_MSG_EXCEPTION "ACPI Exception: " +#define ACPI_MSG_WARNING "ACPI Warning: " +#define ACPI_MSG_INFO "ACPI: " + +/* + * Common message suffix + */ +#define ACPI_MSG_SUFFIX \ + AcpiOsPrintf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, ModuleName, LineNumber) + + +/******************************************************************************* + * + * FUNCTION: AcpiError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Error" message with module/line/version info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiError) + + +/******************************************************************************* + * + * FUNCTION: AcpiException + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Status - Status to be formatted + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Exception" message with module/line/version info + * and decoded ACPI_STATUS. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiException ( + const char *ModuleName, + UINT32 LineNumber, + ACPI_STATUS Status, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_EXCEPTION "%s, ", AcpiFormatException (Status)); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiException) + + +/******************************************************************************* + * + * FUNCTION: AcpiWarning + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print "ACPI Warning" message with module/line/version info + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiWarning ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_WARNING); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiWarning) + + +/******************************************************************************* + * + * FUNCTION: AcpiInfo + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Print generic "ACPI:" information message. There is no + * module/line/version info in order to keep the message simple. + * + * TBD: ModuleName and LineNumber args are not needed, should be removed. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiInfo ( + const char *ModuleName, + UINT32 LineNumber, + const char *Format, + ...) +{ + va_list ArgList; + +#ifdef _KERNEL + /* Temporarily hide too verbose printfs. */ + if (!bootverbose) + return; +#endif + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_INFO); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + AcpiOsPrintf ("\n"); + va_end (ArgList); + + ACPI_MSG_REDIRECT_END; +} + +ACPI_EXPORT_SYMBOL (AcpiInfo) + + +/* + * The remainder of this module contains internal error functions that may + * be configured out. + */ +#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP) + +/******************************************************************************* + * + * FUNCTION: AcpiUtPredefinedWarning + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Pathname - Full pathname to the node + * NodeFlags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Warnings for the predefined validation module. Messages are + * only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of error + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedWarning ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...) +{ + va_list ArgList; + + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (NodeFlags & ANOBJ_EVALUATED) + { + return; + } + + AcpiOsPrintf (ACPI_MSG_WARNING "For %s: ", Pathname); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtPredefinedInfo + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Pathname - Full pathname to the node + * NodeFlags - From Namespace node for the method/object + * Format - Printf format string + additional args + * + * RETURN: None + * + * DESCRIPTION: Info messages for the predefined validation module. Messages + * are only emitted the first time a problem with a particular + * method/object is detected. This prevents a flood of + * messages for methods that are repeatedly evaluated. + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE +AcpiUtPredefinedInfo ( + const char *ModuleName, + UINT32 LineNumber, + char *Pathname, + UINT8 NodeFlags, + const char *Format, + ...) +{ + va_list ArgList; + + + /* + * Warning messages for this method/object will be disabled after the + * first time a validation fails or an object is successfully repaired. + */ + if (NodeFlags & ANOBJ_EVALUATED) + { + return; + } + + AcpiOsPrintf (ACPI_MSG_INFO "For %s: ", Pathname); + + va_start (ArgList, Format); + AcpiOsVprintf (Format, ArgList); + ACPI_MSG_SUFFIX; + va_end (ArgList); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtNamespaceError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * InternalName - Name or path of the namespace node + * LookupStatus - Exception code from NS lookup + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname for the NS node. + * + ******************************************************************************/ + +void +AcpiUtNamespaceError ( + const char *ModuleName, + UINT32 LineNumber, + const char *InternalName, + ACPI_STATUS LookupStatus) +{ + ACPI_STATUS Status; + UINT32 BadName; + char *Name = NULL; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + if (LookupStatus == AE_BAD_CHARACTER) + { + /* There is a non-ascii character in the name */ + + ACPI_MOVE_32_TO_32 (&BadName, ACPI_CAST_PTR (UINT32, InternalName)); + AcpiOsPrintf ("[0x%4.4X] (NON-ASCII)", BadName); + } + else + { + /* Convert path to external format */ + + Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, + InternalName, NULL, &Name); + + /* Print target name */ + + if (ACPI_SUCCESS (Status)) + { + AcpiOsPrintf ("[%s]", Name); + } + else + { + AcpiOsPrintf ("[COULD NOT EXTERNALIZE NAME]"); + } + + if (Name) + { + ACPI_FREE (Name); + } + } + + AcpiOsPrintf (" Namespace lookup failure, %s", + AcpiFormatException (LookupStatus)); + + ACPI_MSG_SUFFIX; + ACPI_MSG_REDIRECT_END; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiUtMethodError + * + * PARAMETERS: ModuleName - Caller's module name (for error output) + * LineNumber - Caller's line number (for error output) + * Message - Error message to use on failure + * PrefixNode - Prefix relative to the path + * Path - Path to the node (optional) + * MethodStatus - Execution status + * + * RETURN: None + * + * DESCRIPTION: Print error message with the full pathname for the method. + * + ******************************************************************************/ + +void +AcpiUtMethodError ( + const char *ModuleName, + UINT32 LineNumber, + const char *Message, + ACPI_NAMESPACE_NODE *PrefixNode, + const char *Path, + ACPI_STATUS MethodStatus) +{ + ACPI_STATUS Status; + ACPI_NAMESPACE_NODE *Node = PrefixNode; + + + ACPI_MSG_REDIRECT_BEGIN; + AcpiOsPrintf (ACPI_MSG_ERROR); + + if (Path) + { + Status = AcpiNsGetNode (PrefixNode, Path, ACPI_NS_NO_UPSEARCH, + &Node); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("[Could not get node by pathname]"); + } + } + + AcpiNsPrintNodePathname (Node, Message); + AcpiOsPrintf (", %s", AcpiFormatException (MethodStatus)); + + ACPI_MSG_SUFFIX; + ACPI_MSG_REDIRECT_END; +} + +#endif /* ACPI_NO_ERROR_MESSAGES */ diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index 36048e4bb06..6dcb82159d3 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -204,7 +204,7 @@ ipf_modload() } if (!c) c = str; - ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, c); + ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c); } error = ipf_pfil_hook(); diff --git a/sys/contrib/ngatm/netnatm/api/cc_conn.c b/sys/contrib/ngatm/netnatm/api/cc_conn.c index 2ba972aa009..3350e2cb380 100644 --- a/sys/contrib/ngatm/netnatm/api/cc_conn.c +++ b/sys/contrib/ngatm/netnatm/api/cc_conn.c @@ -977,25 +977,25 @@ cc_conn_sig_handle(struct ccconn *conn, enum conn_sig sig, /* * attributes */ - if (conn->dirty_attr && CCDIRTY_AAL) + if (conn->dirty_attr & CCDIRTY_AAL) resp->connect.aal = conn->aal; - if (conn->dirty_attr && CCDIRTY_BLLI) + if (conn->dirty_attr & CCDIRTY_BLLI) resp->connect.blli = conn->blli[conn->blli_selector - 1]; - if (conn->dirty_attr && CCDIRTY_CONNID) + if (conn->dirty_attr & CCDIRTY_CONNID) resp->connect.connid = conn->connid; /* XXX NOTIFY */ - if (conn->dirty_attr && CCDIRTY_EETD) + if (conn->dirty_attr & CCDIRTY_EETD) resp->connect.eetd = conn->eetd; /* XXX GIT */ /* XXX UU */ - if (conn->dirty_attr && CCDIRTY_TRAFFIC) + if (conn->dirty_attr & CCDIRTY_TRAFFIC) resp->connect.traffic = conn->traffic; - if (conn->dirty_attr && CCDIRTY_EXQOS) + if (conn->dirty_attr & CCDIRTY_EXQOS) resp->connect.exqos = conn->exqos; - if (conn->dirty_attr && CCDIRTY_ABRSETUP) + if (conn->dirty_attr & CCDIRTY_ABRSETUP) resp->connect.abrsetup = conn->abrsetup; - if (conn->dirty_attr && CCDIRTY_ABRADD) + if (conn->dirty_attr & CCDIRTY_ABRADD) resp->connect.abradd = conn->abradd; /* diff --git a/sys/contrib/ngatm/netnatm/msg/privmsg.c b/sys/contrib/ngatm/netnatm/msg/privmsg.c index 3540efdb8ce..76a7f69aa3c 100644 --- a/sys/contrib/ngatm/netnatm/msg/privmsg.c +++ b/sys/contrib/ngatm/netnatm/msg/privmsg.c @@ -145,7 +145,7 @@ uni_decode_body_internal(enum uni_msgtype mtype, struct uni_msg *msg, msg->b_rptr = msg->b_wptr; else msg->b_rptr += ielen; - UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); err = -1; continue; } @@ -200,16 +200,16 @@ uni_decode_body_internal(enum uni_msgtype mtype, struct uni_msg *msg, * Unexpected but recognized. * Q.2931 5.6.8.3 */ - UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK); err = -1; break; case DEC_ERR: /* bad IE */ if (iedecl->flags & UNIFL_ACCESS) /* this may be wrong: 5.6.8.2 */ - UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_ACC); + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_ACC); else - UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_BAD); + (void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_BAD); err = -1; break; diff --git a/sys/contrib/ngatm/netnatm/msg/uni_ie.c b/sys/contrib/ngatm/netnatm/msg/uni_ie.c index c58377c90c3..2388251ca63 100644 --- a/sys/contrib/ngatm/netnatm/msg/uni_ie.c +++ b/sys/contrib/ngatm/netnatm/msg/uni_ie.c @@ -214,7 +214,7 @@ uni_encode_msg_hdr(struct uni_msg *msg, struct uni_msghdr *h, { u_char byte; - uni_msg_ensure(msg, 9); + (void)uni_msg_ensure(msg, 9); APP_BYTE(msg, cx->pnni ? PNNI_PROTO : UNI_PROTO); APP_BYTE(msg, 3); @@ -652,7 +652,7 @@ uni_encode_ie_hdr(struct uni_msg *msg, enum uni_ietype type, { u_char byte; - uni_msg_ensure(msg, 4 + len); + (void)uni_msg_ensure(msg, 4 + len); *msg->b_wptr++ = type; byte = 0x80 | (h->coding << 5); diff --git a/sys/contrib/ngatm/netnatm/sig/sig_call.c b/sys/contrib/ngatm/netnatm/sig/sig_call.c index 96edd777497..d2e3b7f9af2 100644 --- a/sys/contrib/ngatm/netnatm/sig/sig_call.c +++ b/sys/contrib/ngatm/netnatm/sig/sig_call.c @@ -398,7 +398,7 @@ un0_setup(struct call *c, struct uni_msg *m, struct uni_all *u, if (IE_ISGOOD(u->u.setup.epref) && u->u.setup.epref.flag == 1) { IE_SETERROR(u->u.setup.epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, u->u.setup.epref.h.act, UNI_IERR_BAD); } uni_mandate_epref(c->uni, &u->u.setup.epref); @@ -578,7 +578,7 @@ u1n6_call_proc(struct call *c, struct uni_msg *m, struct uni_all *u, (cp->epref.flag != 1 || cp->epref.epref != c->msg_setup.epref.epref)) { IE_SETERROR(cp->epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, cp->epref.h.act, UNI_IERR_BAD); } } @@ -763,7 +763,7 @@ unx_alerting(struct call *c, struct uni_msg *m, struct uni_all *u, (al->epref.flag != 1 || al->epref.epref != c->msg_setup.epref.epref)) { IE_SETERROR(al->epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, al->epref.h.act, UNI_IERR_BAD); } } @@ -1065,7 +1065,7 @@ unx_connect(struct call *c, struct uni_msg *m, struct uni_all *u, if (IE_ISGOOD(co->epref) && co->epref.flag != 1) { IE_SETERROR(co->epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, co->epref.h.act, UNI_IERR_BAD); } } @@ -2757,7 +2757,7 @@ unx_add_party(struct call *c, struct uni_msg *m, struct uni_all *u, if (IE_ISGOOD(u->u.add_party.epref) && p == NULL && u->u.add_party.epref.flag) { IE_SETERROR(u->u.add_party.epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, u->u.add_party.epref.h.act, UNI_IERR_BAD); } @@ -2802,7 +2802,7 @@ un10n8_add_party_ack(struct call *c, struct uni_msg *m, struct uni_all *u, if (IE_ISGOOD(u->u.add_party_ack.epref)) { if (u->u.add_party_ack.epref.flag == 0) { IE_SETERROR(u->u.add_party_ack.epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, u->u.add_party_ack.epref.h.act, UNI_IERR_BAD); } else { p = uni_find_partyx(c, u->u.add_party_ack.epref.epref, 1); @@ -2902,7 +2902,7 @@ unx_party_alerting(struct call *c, struct uni_msg *m, struct uni_all *u, if (IE_ISGOOD(u->u.party_alerting.epref)) { if (u->u.party_alerting.epref.flag == 0) { IE_SETERROR(u->u.party_alerting.epref); - UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, + (void)UNI_SAVE_IERR(&c->uni->cx, UNI_IE_EPREF, u->u.party_alerting.epref.h.act, UNI_IERR_BAD); } else { p = uni_find_partyx(c, u->u.party_alerting.epref.epref, 1); diff --git a/sys/contrib/ngatm/netnatm/sig/sig_reset.c b/sys/contrib/ngatm/netnatm/sig/sig_reset.c index 29a57bdd92b..469b9f762a6 100644 --- a/sys/contrib/ngatm/netnatm/sig/sig_reset.c +++ b/sys/contrib/ngatm/netnatm/sig/sig_reset.c @@ -270,7 +270,7 @@ start_restart_ack(struct uni *uni, struct uni_msg *m, struct uni_all *u) */ if (u->u.restart_ack.restart.rclass == UNI_RESTART_ALL && IE_ISGOOD(u->u.restart_ack.connid)) { - UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, u->u.restart_ack.connid.h.act, UNI_IERR_UNK); } else if ((u->u.restart_ack.restart.rclass == UNI_RESTART_PATH || @@ -547,7 +547,7 @@ response_restart(struct uni *uni, struct uni_msg *m, struct uni_all *u) */ if (u->u.restart.restart.rclass == UNI_RESTART_ALL && IE_ISGOOD(u->u.restart.connid)) { - UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, + (void)UNI_SAVE_IERR(&uni->cx, UNI_IE_CONNID, u->u.restart.connid.h.act, UNI_IERR_UNK); } else if ((u->u.restart.restart.rclass == UNI_RESTART_PATH || diff --git a/sys/contrib/octeon-sdk/cvmx-app-init.h b/sys/contrib/octeon-sdk/cvmx-app-init.h index 6becb91024b..8f768ed7834 100644 --- a/sys/contrib/octeon-sdk/cvmx-app-init.h +++ b/sys/contrib/octeon-sdk/cvmx-app-init.h @@ -182,7 +182,11 @@ enum cvmx_board_types_enum { CVMX_BOARD_TYPE_CUST_ITB101 = 10005, CVMX_BOARD_TYPE_CUST_NTE102 = 10006, CVMX_BOARD_TYPE_CUST_AGS103 = 10007, +#if !defined(OCTEON_VENDOR_LANNER) CVMX_BOARD_TYPE_CUST_GST104 = 10008, +#else + CVMX_BOARD_TYPE_CUST_LANNER_MR955= 10008, +#endif CVMX_BOARD_TYPE_CUST_GCT105 = 10009, CVMX_BOARD_TYPE_CUST_AGS106 = 10010, CVMX_BOARD_TYPE_CUST_SGM107 = 10011, @@ -257,7 +261,11 @@ static inline const char *cvmx_board_type_to_string(enum cvmx_board_types_enum t ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103) +#if !defined(OCTEON_VENDOR_LANNER) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104) +#else + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_LANNER_MR955) +#endif ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107) diff --git a/sys/contrib/octeon-sdk/cvmx-helper-board.c b/sys/contrib/octeon-sdk/cvmx-helper-board.c index b890185635e..cca2b22bd76 100644 --- a/sys/contrib/octeon-sdk/cvmx-helper-board.c +++ b/sys/contrib/octeon-sdk/cvmx-helper-board.c @@ -114,6 +114,9 @@ int cvmx_helper_board_get_mii_address(int ipd_port) case CVMX_BOARD_TYPE_EBT5800: case CVMX_BOARD_TYPE_THUNDER: case CVMX_BOARD_TYPE_NICPRO2: +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: +#endif /* Interface 0 is SPI4, interface 1 is RGMII */ if ((ipd_port >= 16) && (ipd_port < 20)) return ipd_port - 16; @@ -178,10 +181,11 @@ int cvmx_helper_board_get_mii_address(int ipd_port) /* Private vendor-defined boards. */ #if defined(OCTEON_VENDOR_LANNER) case CVMX_BOARD_TYPE_CUST_LANNER_MR320: + /* Port 0 is a Marvell 88E6161 switch, ports 1 and 2 are Marvell + 88E1111 interfaces. */ switch (ipd_port) { case 0: - /* XXX Switch PHY? */ - return -1; + return 16; case 1: return 1; case 2: @@ -616,6 +620,12 @@ int __cvmx_helper_board_interface_probe(int interface, int supported_ports) if (interface == 1) return 0; break; +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + if (interface == 1) + return 12; + break; +#endif } #ifdef CVMX_BUILD_FOR_UBOOT if (CVMX_HELPER_INTERFACE_MODE_SPI == cvmx_helper_interface_get_mode(interface) && getenv("disable_spi")) diff --git a/sys/contrib/octeon-sdk/cvmx-helper-spi.c b/sys/contrib/octeon-sdk/cvmx-helper-spi.c index 9ee1aab179e..bc056628d6a 100644 --- a/sys/contrib/octeon-sdk/cvmx-helper-spi.c +++ b/sys/contrib/octeon-sdk/cvmx-helper-spi.c @@ -82,6 +82,21 @@ int __cvmx_helper_spi_probe(int interface) { num_ports = 10; } +#if defined(OCTEON_VENDOR_LANNER) + else if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CUST_LANNER_MR955) + { + cvmx_pko_reg_crc_enable_t enable; + if (interface == 1) { + num_ports = 12; + } else { + /* XXX This is not entirely true. */ + num_ports = 0; + } + enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE); + enable.s.enable &= 0xffff << (16 - (interface*16)); + cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64); + } +#endif else { cvmx_pko_reg_crc_enable_t enable; diff --git a/sys/contrib/octeon-sdk/cvmx-helper.c b/sys/contrib/octeon-sdk/cvmx-helper.c index cc52749945c..cd155bb9ff6 100644 --- a/sys/contrib/octeon-sdk/cvmx-helper.c +++ b/sys/contrib/octeon-sdk/cvmx-helper.c @@ -101,6 +101,15 @@ static CVMX_SHARED cvmx_helper_link_info_t port_link_info[CVMX_PIP_NUM_INPUT_POR */ int cvmx_helper_get_number_of_interfaces(void) { + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + return 2; +#endif + default: + break; + } + if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) return 4; else diff --git a/sys/contrib/octeon-sdk/cvmx-spi.c b/sys/contrib/octeon-sdk/cvmx-spi.c index 012d03b7b5d..cbb48a5ebe5 100644 --- a/sys/contrib/octeon-sdk/cvmx-spi.c +++ b/sys/contrib/octeon-sdk/cvmx-spi.c @@ -515,7 +515,11 @@ int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout) // Wait for the training sequence to complete cvmx_dprintf ("SPI%d: Waiting for training\n", interface); cvmx_wait (1000 * MS); +#if !defined(OCTEON_VENDOR_LANNER) timeout_time = cvmx_get_cycle() + 1000ull * MS * 600; /* Wait a really long time here */ +#else + timeout_time = cvmx_get_cycle() + 1000ull * MS * 10; +#endif /* The HRM says we must wait for 34 + 16 * MAXDIST training sequences. We'll be pessimistic and wait for a lot more */ rx_training_needed = 500; diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index ebe73c2e932..242834d80af 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -6375,6 +6375,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, m0->m_pkthdr.csum_flags &= ifp->if_hwassist; if (ntohs(ip->ip_len) <= ifp->if_mtu || + (m0->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0 || (ifp->if_hwassist & CSUM_FRAGMENT && ((ip->ip_off & htons(IP_DF)) == 0))) { /* @@ -6449,7 +6450,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. */ - if (ip->ip_off & htons(IP_DF)) { + if (ip->ip_off & htons(IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) { KMOD_IPSTAT_INC(ips_cantfrag); if (r->rt != PF_DUPTO) { #ifdef __FreeBSD__ diff --git a/sys/contrib/pf/netinet/in4_cksum.c b/sys/contrib/pf/netinet/in4_cksum.c index 24a04d01456..bf25baf97a0 100644 --- a/sys/contrib/pf/netinet/in4_cksum.c +++ b/sys/contrib/pf/netinet/in4_cksum.c @@ -75,7 +75,7 @@ #include #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) -#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} +#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);} int in4_cksum(struct mbuf *, u_int8_t, int, int); diff --git a/sys/crypto/aesni/aeskeys_i386.S b/sys/crypto/aesni/aeskeys_i386.S index 60a6a430006..f575512cc98 100644 --- a/sys/crypto/aesni/aeskeys_i386.S +++ b/sys/crypto/aesni/aeskeys_i386.S @@ -52,7 +52,7 @@ _key_expansion_256a: pxor %xmm1,%xmm0 movaps %xmm0,(%edx) addl $0x10,%edx - retq + retl .cfi_endproc END(_key_expansion_128) @@ -76,7 +76,7 @@ ENTRY(_key_expansion_192a) shufps $0b01001110,%xmm2,%xmm1 movaps %xmm1,0x10(%edx) addl $0x20,%edx - retq + retl .cfi_endproc END(_key_expansion_192a) diff --git a/sys/crypto/aesni/aesni.c b/sys/crypto/aesni/aesni.c index 93ee042cd05..ed12f28dcfd 100644 --- a/sys/crypto/aesni/aesni.c +++ b/sys/crypto/aesni/aesni.c @@ -69,14 +69,12 @@ aesni_identify(driver_t *drv, device_t parent) static int aesni_probe(device_t dev) { - char capp[32]; if ((cpu_feature2 & CPUID2_AESNI) == 0) { device_printf(dev, "No AESNI support.\n"); return (EINVAL); } - strlcpy(capp, "AES-CBC", sizeof(capp)); - device_set_desc_copy(dev, capp); + device_set_desc_copy(dev, "AES-CBC,AES-XTS"); return (0); } @@ -96,6 +94,7 @@ aesni_attach(device_t dev) rw_init(&sc->lock, "aesni_lock"); crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0); return (0); } @@ -142,6 +141,7 @@ aesni_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri) for (; cri != NULL; cri = cri->cri_next) { switch (cri->cri_alg) { case CRYPTO_AES_CBC: + case CRYPTO_AES_XTS: if (encini != NULL) return (EINVAL); encini = cri; @@ -174,6 +174,7 @@ aesni_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri) ses->used = 1; TAILQ_INSERT_TAIL(&sc->sessions, ses, next); rw_wunlock(&sc->lock); + ses->algo = encini->cri_alg; error = aesni_cipher_setup(ses, encini); if (error != 0) { @@ -245,6 +246,7 @@ aesni_process(device_t dev, struct cryptop *crp, int hint __unused) for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { switch (crd->crd_alg) { case CRYPTO_AES_CBC: + case CRYPTO_AES_XTS: if (enccrd != NULL) { error = EINVAL; goto out; diff --git a/sys/crypto/aesni/aesni.h b/sys/crypto/aesni/aesni.h index 23da5980834..b07ec8b1e35 100644 --- a/sys/crypto/aesni/aesni.h +++ b/sys/crypto/aesni/aesni.h @@ -55,7 +55,9 @@ struct aesni_session { uint8_t enc_schedule[AES_SCHED_LEN] __aligned(16); uint8_t dec_schedule[AES_SCHED_LEN] __aligned(16); + uint8_t xts_schedule[AES_SCHED_LEN] __aligned(16); uint8_t iv[AES_BLOCK_LEN]; + int algo; int rounds; /* uint8_t *ses_ictx; */ /* uint8_t *ses_octx; */ diff --git a/sys/crypto/aesni/aesni_wrap.c b/sys/crypto/aesni/aesni_wrap.c index fd08222e5d1..36c66eac13f 100644 --- a/sys/crypto/aesni/aesni_wrap.c +++ b/sys/crypto/aesni/aesni_wrap.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2010 Konstantin Belousov + * Copyright (c) 2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -105,34 +106,153 @@ aesni_decrypt_ecb(int rounds, const void *key_schedule, size_t len, } } +#define AES_XTS_BLOCKSIZE 16 +#define AES_XTS_IVSIZE 8 +#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ + +static void +aesni_crypt_xts_block(int rounds, const void *key_schedule, uint8_t *tweak, + const uint8_t *from, uint8_t *to, int do_encrypt) +{ + uint8_t block[AES_XTS_BLOCKSIZE]; + u_int i, carry_in, carry_out; + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + block[i] = from[i] ^ tweak[i]; + + if (do_encrypt) + aesni_enc(rounds - 1, key_schedule, block, to, NULL); + else + aesni_dec(rounds - 1, key_schedule, block, to, NULL); + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + to[i] ^= tweak[i]; + + /* Exponentiate tweak. */ + carry_in = 0; + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) { + carry_out = tweak[i] & 0x80; + tweak[i] = (tweak[i] << 1) | (carry_in ? 1 : 0); + carry_in = carry_out; + } + if (carry_in) + tweak[0] ^= AES_XTS_ALPHA; + bzero(block, sizeof(block)); +} + +static void +aesni_crypt_xts(int rounds, const void *data_schedule, + const void *tweak_schedule, size_t len, const uint8_t *from, uint8_t *to, + const uint8_t iv[AES_BLOCK_LEN], int do_encrypt) +{ + uint8_t tweak[AES_XTS_BLOCKSIZE]; + uint64_t blocknum; + size_t i; + + /* + * Prepare tweak as E_k2(IV). IV is specified as LE representation + * of a 64-bit block number which we allow to be passed in directly. + */ + bcopy(iv, &blocknum, AES_XTS_IVSIZE); + for (i = 0; i < AES_XTS_IVSIZE; i++) { + tweak[i] = blocknum & 0xff; + blocknum >>= 8; + } + /* Last 64 bits of IV are always zero. */ + bzero(tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE); + aesni_enc(rounds - 1, tweak_schedule, tweak, tweak, NULL); + + len /= AES_XTS_BLOCKSIZE; + for (i = 0; i < len; i++) { + aesni_crypt_xts_block(rounds, data_schedule, tweak, from, to, + do_encrypt); + from += AES_XTS_BLOCKSIZE; + to += AES_XTS_BLOCKSIZE; + } + + bzero(tweak, sizeof(tweak)); +} + +static void +aesni_encrypt_xts(int rounds, const void *data_schedule, + const void *tweak_schedule, size_t len, const uint8_t *from, uint8_t *to, + const uint8_t iv[AES_BLOCK_LEN]) +{ + + aesni_crypt_xts(rounds, data_schedule, tweak_schedule, len, from, to, + iv, 1); +} + +static void +aesni_decrypt_xts(int rounds, const void *data_schedule, + const void *tweak_schedule, size_t len, const uint8_t *from, uint8_t *to, + const uint8_t iv[AES_BLOCK_LEN]) +{ + + aesni_crypt_xts(rounds, data_schedule, tweak_schedule, len, from, to, + iv, 0); +} + +static int +aesni_cipher_setup_common(struct aesni_session *ses, const uint8_t *key, + int keylen) +{ + + switch (ses->algo) { + case CRYPTO_AES_CBC: + switch (keylen) { + case 128: + ses->rounds = AES128_ROUNDS; + break; + case 192: + ses->rounds = AES192_ROUNDS; + break; + case 256: + ses->rounds = AES256_ROUNDS; + break; + default: + return (EINVAL); + } + break; + case CRYPTO_AES_XTS: + switch (keylen) { + case 256: + ses->rounds = AES128_ROUNDS; + break; + case 512: + ses->rounds = AES256_ROUNDS; + break; + default: + return (EINVAL); + } + break; + default: + return (EINVAL); + } + + aesni_set_enckey(key, ses->enc_schedule, ses->rounds); + aesni_set_deckey(ses->enc_schedule, ses->dec_schedule, ses->rounds); + if (ses->algo == CRYPTO_AES_CBC) + arc4rand(ses->iv, sizeof(ses->iv), 0); + else /* if (ses->algo == CRYPTO_AES_XTS) */ { + aesni_set_enckey(key + keylen / 16, ses->xts_schedule, + ses->rounds); + } + + return (0); +} + int aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini) { struct thread *td; int error; - switch (encini->cri_klen) { - case 128: - ses->rounds = AES128_ROUNDS; - break; - case 192: - ses->rounds = AES192_ROUNDS; - break; - case 256: - ses->rounds = AES256_ROUNDS; - break; - default: - return (EINVAL); - } - td = curthread; error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL); if (error == 0) { - aesni_set_enckey(encini->cri_key, ses->enc_schedule, - ses->rounds); - aesni_set_deckey(ses->enc_schedule, ses->dec_schedule, - ses->rounds); - arc4rand(ses->iv, sizeof(ses->iv), 0); + error = aesni_cipher_setup_common(ses, encini->cri_key, + encini->cri_klen); fpu_kern_leave(td, &ses->fpu_ctx); } return (error); @@ -147,34 +267,49 @@ aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd, int error, allocated; buf = aesni_cipher_alloc(enccrd, crp, &allocated); - if (buf == NULL) { - error = ENOMEM; - goto out; - } + if (buf == NULL) + return (ENOMEM); td = curthread; error = fpu_kern_enter(td, &ses->fpu_ctx, FPU_KERN_NORMAL); if (error != 0) - goto out1; + goto out; + + if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) { + error = aesni_cipher_setup_common(ses, enccrd->crd_key, + enccrd->crd_klen); + if (error != 0) + goto out; + } if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) { if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN); - if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_inject, AES_BLOCK_LEN, ses->iv); - - aesni_encrypt_cbc(ses->rounds, ses->enc_schedule, - enccrd->crd_len, buf, buf, ses->iv); + if (ses->algo == CRYPTO_AES_CBC) { + aesni_encrypt_cbc(ses->rounds, ses->enc_schedule, + enccrd->crd_len, buf, buf, ses->iv); + } else /* if (ses->algo == CRYPTO_AES_XTS) */ { + aesni_encrypt_xts(ses->rounds, ses->enc_schedule, + ses->xts_schedule, enccrd->crd_len, buf, buf, + ses->iv); + } } else { if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN); else crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_inject, AES_BLOCK_LEN, ses->iv); - aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, - enccrd->crd_len, buf, ses->iv); + if (ses->algo == CRYPTO_AES_CBC) { + aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, + enccrd->crd_len, buf, ses->iv); + } else /* if (ses->algo == CRYPTO_AES_XTS) */ { + aesni_decrypt_xts(ses->rounds, ses->dec_schedule, + ses->xts_schedule, enccrd->crd_len, buf, buf, + ses->iv); + } } fpu_kern_leave(td, &ses->fpu_ctx); if (allocated) @@ -184,11 +319,10 @@ aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd, crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN, AES_BLOCK_LEN, ses->iv); - out1: + out: if (allocated) { bzero(buf, enccrd->crd_len); free(buf, M_AESNI); } - out: return (error); } diff --git a/sys/dev/aac/aac.c b/sys/dev/aac/aac.c index b928dba0299..e3f47edaf2a 100644 --- a/sys/dev/aac/aac.c +++ b/sys/dev/aac/aac.c @@ -189,9 +189,9 @@ static char *aac_describe_code(struct aac_code_lookup *table, /* Management Interface */ static d_open_t aac_open; -static d_close_t aac_close; static d_ioctl_t aac_ioctl; static d_poll_t aac_poll; +static void aac_cdevpriv_dtor(void *arg); static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); static void aac_handle_aif(struct aac_softc *sc, @@ -214,7 +214,6 @@ static struct cdevsw aac_cdevsw = { .d_version = D_VERSION, .d_flags = D_NEEDGIANT, .d_open = aac_open, - .d_close = aac_close, .d_ioctl = aac_ioctl, .d_poll = aac_poll, .d_name = "aac", @@ -392,7 +391,7 @@ aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) if (aac_sync_fib(sc, ContainerCommand, 0, fib, sizeof(struct aac_mntinfo))) { - printf("Error probing container %d\n", cid); + device_printf(sc->aac_dev, "Error probing container %d\n", cid); return (NULL); } @@ -660,9 +659,6 @@ aac_detach(device_t dev) sc = device_get_softc(dev); fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); - if (sc->aac_state & AAC_STATE_OPEN) - return(EBUSY); - callout_drain(&sc->aac_daemontime); /* Remove the child containers */ @@ -1129,6 +1125,11 @@ aac_complete(void *context, int pending) AAC_PRINT_FIB(sc, fib); break; } + if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0) + device_printf(sc->aac_dev, + "COMMAND %p COMPLETED AFTER %d SECONDS\n", + cm, (int)(time_uptime-cm->cm_timestamp)); + aac_remove_busy(cm); aac_unmap_command(cm); @@ -2348,7 +2349,7 @@ aac_timeout(struct aac_softc *sc) deadline = time_uptime - AAC_CMD_TIMEOUT; TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { if ((cm->cm_timestamp < deadline) - /* && !(cm->cm_flags & AAC_CMD_TIMEDOUT) */) { + && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { cm->cm_flags |= AAC_CMD_TIMEDOUT; device_printf(sc->aac_dev, "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", @@ -2799,23 +2800,8 @@ aac_open(struct cdev *dev, int flags, int fmt, struct thread *td) sc = dev->si_drv1; fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); - sc->aac_open_cnt++; - sc->aac_state |= AAC_STATE_OPEN; - - return 0; -} - -static int -aac_close(struct cdev *dev, int flags, int fmt, struct thread *td) -{ - struct aac_softc *sc; - - sc = dev->si_drv1; - fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); - sc->aac_open_cnt--; - /* Mark this unit as no longer open */ - if (sc->aac_open_cnt == 0) - sc->aac_state &= ~AAC_STATE_OPEN; + device_busy(sc->aac_dev); + devfs_set_cdevpriv(sc, aac_cdevpriv_dtor); return 0; } @@ -3202,6 +3188,21 @@ out: return(error); } +/* + * cdevpriv interface private destructor. + */ +static void +aac_cdevpriv_dtor(void *arg) +{ + struct aac_softc *sc; + + sc = arg; + fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); + mtx_lock(&Giant); + device_unbusy(sc->aac_dev); + mtx_unlock(&Giant); +} + /* * Handle an AIF sent to us by the controller; queue it for later reference. * If the queue fills up, then drop the older entries. @@ -3215,6 +3216,7 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) struct aac_mntinforesp *mir; int next, current, found; int count = 0, added = 0, i = 0; + uint32_t channel; fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); @@ -3323,6 +3325,27 @@ aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) break; + case AifEnEnclosureManagement: + switch (aif->data.EN.data.EEE.eventType) { + case AIF_EM_DRIVE_INSERTION: + case AIF_EM_DRIVE_REMOVAL: + channel = aif->data.EN.data.EEE.unitID; + if (sc->cam_rescan_cb != NULL) + sc->cam_rescan_cb(sc, + (channel >> 24) & 0xF, + (channel & 0xFFFF)); + break; + } + break; + + case AifEnAddJBOD: + case AifEnDeleteJBOD: + channel = aif->data.EN.data.ECE.container; + if (sc->cam_rescan_cb != NULL) + sc->cam_rescan_cb(sc, (channel >> 24) & 0xF, + AAC_CAM_TARGET_WILDCARD); + break; + default: break; } diff --git a/sys/dev/aac/aac_cam.c b/sys/dev/aac/aac_cam.c index 4bfe0ed5747..44f4e196cac 100644 --- a/sys/dev/aac/aac_cam.c +++ b/sys/dev/aac/aac_cam.c @@ -37,12 +37,15 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -76,6 +79,9 @@ static int aac_cam_detach(device_t dev); static void aac_cam_action(struct cam_sim *, union ccb *); static void aac_cam_poll(struct cam_sim *); static void aac_cam_complete(struct aac_command *); +static void aac_cam_rescan(struct aac_softc *sc, uint32_t channel, + uint32_t target_id); + static u_int32_t aac_cam_reset_bus(struct cam_sim *, union ccb *); static u_int32_t aac_cam_abort_ccb(struct cam_sim *, union ccb *); static u_int32_t aac_cam_term_io(struct cam_sim *, union ccb *); @@ -100,6 +106,43 @@ MODULE_DEPEND(aacp, cam, 1, 1, 1); MALLOC_DEFINE(M_AACCAM, "aaccam", "AAC CAM info"); +static void +aac_cam_rescan(struct aac_softc *sc, uint32_t channel, uint32_t target_id) +{ + union ccb *ccb; + struct aac_sim *sim; + struct aac_cam *camsc; + + if (target_id == AAC_CAM_TARGET_WILDCARD) + target_id = CAM_TARGET_WILDCARD; + + TAILQ_FOREACH(sim, &sc->aac_sim_tqh, sim_link) { + camsc = sim->aac_cam; + if (camsc == NULL || camsc->inf == NULL || + camsc->inf->BusNumber != channel) + continue; + + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + device_printf(sc->aac_dev, + "Cannot allocate ccb for bus rescan.\n"); + return; + } + + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, + cam_sim_path(camsc->sim), + target_id, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + device_printf(sc->aac_dev, + "Cannot create path for bus rescan.\n"); + return; + } + xpt_rescan(ccb); + break; + } +} + + static void aac_cam_event(struct aac_softc *sc, struct aac_event *event, void *arg) { @@ -141,6 +184,7 @@ aac_cam_detach(device_t dev) camsc = (struct aac_cam *)device_get_softc(dev); sc = camsc->inf->aac_sc; + camsc->inf->aac_cam = NULL; mtx_lock(&sc->aac_io_lock); @@ -149,6 +193,8 @@ aac_cam_detach(device_t dev) xpt_bus_deregister(cam_sim_path(camsc->sim)); cam_sim_free(camsc->sim, /*free_devq*/TRUE); + sc->cam_rescan_cb = NULL; + mtx_unlock(&sc->aac_io_lock); return (0); @@ -171,6 +217,7 @@ aac_cam_attach(device_t dev) camsc = (struct aac_cam *)device_get_softc(dev); inf = (struct aac_sim *)device_get_ivars(dev); camsc->inf = inf; + camsc->inf->aac_cam = camsc; devq = cam_simq_alloc(inf->TargetsPerBus); if (devq == NULL) @@ -198,6 +245,7 @@ aac_cam_attach(device_t dev) mtx_unlock(&inf->aac_sc->aac_io_lock); return (EIO); } + inf->aac_sc->cam_rescan_cb = aac_cam_rescan; mtx_unlock(&inf->aac_sc->aac_io_lock); camsc->sim = sim; @@ -569,7 +617,7 @@ aac_cam_reset_bus(struct cam_sim *sim, union ccb *ccb) sc = camsc->inf->aac_sc; if (sc == NULL) { - printf("Null sc?\n"); + printf("aac: Null sc?\n"); return (CAM_REQ_ABORTED); } diff --git a/sys/dev/aac/aac_disk.c b/sys/dev/aac/aac_disk.c index fa3b66b87c1..3c9720ddbc1 100644 --- a/sys/dev/aac/aac_disk.c +++ b/sys/dev/aac/aac_disk.c @@ -106,8 +106,9 @@ aac_disk_open(struct disk *dp) /* check that the controller is up and running */ if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) { - printf("Controller Suspended controller state = 0x%x\n", - sc->ad_controller->aac_state); + device_printf(sc->ad_controller->aac_dev, + "Controller Suspended controller state = 0x%x\n", + sc->ad_controller->aac_state); return(ENXIO); } @@ -252,7 +253,8 @@ aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size if (!first) { first = 1; if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) { - printf("bus_dmamap_create failed\n"); + device_printf(sc->aac_dev, + "bus_dmamap_create failed\n"); return (ENOMEM); } } @@ -305,8 +307,9 @@ aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size size += fib->Header.Size; if (aac_sync_fib(sc, command, 0, fib, size)) { - printf("Error dumping block 0x%jx\n", - (uintmax_t)physical); + device_printf(sc->aac_dev, + "Error dumping block 0x%jx\n", + (uintmax_t)physical); return (EIO); } diff --git a/sys/dev/aac/aacreg.h b/sys/dev/aac/aacreg.h index ccec8b214b7..99597787dcb 100644 --- a/sys/dev/aac/aacreg.h +++ b/sys/dev/aac/aacreg.h @@ -306,7 +306,9 @@ struct aac_adapter_init { u_int32_t HostElapsedSeconds; /* ADAPTER_INIT_STRUCT_REVISION_4 begins here */ u_int32_t InitFlags; /* flags for supported features */ -#define AAC_INITFLAGS_NEW_COMM_SUPPORTED 1 +#define AAC_INITFLAGS_NEW_COMM_SUPPORTED 1 +#define AAC_INITFLAGS_DRIVER_USES_UTC_TIME 0x10 +#define AAC_INITFLAGS_DRIVER_SUPPORTS_PM 0x20 u_int32_t MaxIoCommands; /* max outstanding commands */ u_int32_t MaxIoSize; /* largest I/O command */ u_int32_t MaxFibSize; /* largest FIB to adapter */ @@ -885,6 +887,17 @@ typedef enum { AifEnBatteryNeedsRecond, /* The battery needs reconditioning */ AifEnClusterEvent, /* Some cluster event */ AifEnDiskSetEvent, /* A disk set event occured. */ + AifEnContainerScsiEvent, /* a container event with no. and scsi id */ + AifEnPicBatteryEvent, /* An event gen. by pic_battery.c for an ABM */ + AifEnExpEvent, /* Exp. Event Type to replace CTPopUp messages */ + AifEnRAID6RebuildDone, /* RAID6 rebuild finished */ + AifEnSensorOverHeat, /* Heat Sensor indicate overheat */ + AifEnSensorCoolDown, /* Heat Sensor ind. cooled down after overheat */ + AifFeatureKeysModified, /* notif. of updated feature keys */ + AifApplicationExpirationEvent, /* notif. on app. expiration status */ + AifEnBackgroundConsistencyCheck,/* BCC notif. for NEC - DDTS 94700 */ + AifEnAddJBOD, /* A new JBOD type drive was created (30) */ + AifEnDeleteJBOD, /* A JBOD type drive was deleted (31) */ AifDriverNotifyStart=199, /* Notifies for host driver go here */ /* Host driver notifications start here */ AifDenMorphComplete, /* A morph operation completed */ @@ -922,6 +935,11 @@ struct aac_AifEnsEnclosureEvent { u_int32_t eventType; /* event type */ } __packed; +typedef enum { + AIF_EM_DRIVE_INSERTION=31, + AIF_EM_DRIVE_REMOVAL +} aac_AifEMEventType; + struct aac_AifEnsBatteryEvent { AAC_NVBATT_TRANSITION transition_type; /* eg from low to ok */ AAC_NVBATTSTATUS current_state; /* current batt state */ diff --git a/sys/dev/aac/aacvar.h b/sys/dev/aac/aacvar.h index 29eb8169e02..2371ad2210b 100644 --- a/sys/dev/aac/aacvar.h +++ b/sys/dev/aac/aacvar.h @@ -113,6 +113,7 @@ struct aac_container /* * Per-SIM data structure */ +struct aac_cam; struct aac_sim { device_t sim_dev; @@ -120,6 +121,7 @@ struct aac_sim int BusNumber; int InitiatorBusId; struct aac_softc *aac_sc; + struct aac_cam *aac_cam; TAILQ_ENTRY(aac_sim) sim_link; }; @@ -319,10 +321,9 @@ struct aac_softc /* controller features, limits and status */ int aac_state; #define AAC_STATE_SUSPEND (1<<0) -#define AAC_STATE_OPEN (1<<1) +#define AAC_STATE_UNUSED0 (1<<1) #define AAC_STATE_INTERRUPTS_ON (1<<2) #define AAC_STATE_AIF_SLEEPER (1<<3) - int aac_open_cnt; struct FsaRevision aac_revision; /* controller hardware interface */ @@ -421,6 +422,9 @@ struct aac_softc u_int32_t aac_max_fib_size; /* max. FIB size */ u_int32_t aac_sg_tablesize; /* max. sg count from host */ u_int32_t aac_max_sectors; /* max. I/O size from host (blocks) */ +#define AAC_CAM_TARGET_WILDCARD ~0 + void (*cam_rescan_cb)(struct aac_softc *, uint32_t, + uint32_t); }; /* diff --git a/sys/dev/acpi_support/acpi_hp.c b/sys/dev/acpi_support/acpi_hp.c index b0e85bed92e..edc04b75b40 100644 --- a/sys/dev/acpi_support/acpi_hp.c +++ b/sys/dev/acpi_support/acpi_hp.c @@ -116,7 +116,6 @@ struct acpi_hp_inst_seq_pair { struct acpi_hp_softc { device_t dev; - ACPI_HANDLE handle; device_t wmi_dev; int has_notify; /* notification GUID found */ int has_cmi; /* CMI GUID found */ @@ -289,6 +288,7 @@ static struct { ACPI_SERIAL_DECL(hp, "HP ACPI-WMI Mapping"); +static void acpi_hp_identify(driver_t *driver, device_t parent); static int acpi_hp_probe(device_t dev); static int acpi_hp_attach(device_t dev); static int acpi_hp_detach(device_t dev); @@ -320,6 +320,7 @@ static struct cdevsw hpcmi_cdevsw = { }; static device_method_t acpi_hp_methods[] = { + DEVMETHOD(device_identify, acpi_hp_identify), DEVMETHOD(device_probe, acpi_hp_probe), DEVMETHOD(device_attach, acpi_hp_attach), DEVMETHOD(device_detach, acpi_hp_detach), @@ -334,7 +335,7 @@ static driver_t acpi_hp_driver = { static devclass_t acpi_hp_devclass; -DRIVER_MODULE(acpi_hp, acpi, acpi_hp_driver, acpi_hp_devclass, +DRIVER_MODULE(acpi_hp, acpi_wmi, acpi_hp_driver, acpi_hp_devclass, 0, 0); MODULE_DEPEND(acpi_hp, acpi_wmi, 1, 1, 1); MODULE_DEPEND(acpi_hp, acpi, 1, 1, 1); @@ -405,7 +406,7 @@ acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc) "WLAN on air changed to %i " "(new_wlan_status is %i)\n", sc->was_wlan_on_air, new_wlan_status); - acpi_UserNotify("HP", sc->handle, + acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 0xc0+sc->was_wlan_on_air); } } @@ -420,7 +421,7 @@ acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc) " to %i (new_bluetooth_status is %i)\n", sc->was_bluetooth_on_air, new_bluetooth_status); - acpi_UserNotify("HP", sc->handle, + acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 0xd0+sc->was_bluetooth_on_air); } } @@ -433,19 +434,33 @@ acpi_hp_evaluate_auto_on_off(struct acpi_hp_softc *sc) "WWAN on air changed to %i" " (new_wwan_status is %i)\n", sc->was_wwan_on_air, new_wwan_status); - acpi_UserNotify("HP", sc->handle, + acpi_UserNotify("HP", ACPI_ROOT_OBJECT, 0xe0+sc->was_wwan_on_air); } } } +static void +acpi_hp_identify(driver_t *driver, device_t parent) +{ + + /* Don't do anything if driver is disabled. */ + if (acpi_disabled("hp")) + return; + + /* Add only a single device instance. */ + if (device_find_child(parent, "acpi_hp", -1) != NULL) + return; + + if (BUS_ADD_CHILD(parent, 0, "acpi_hp", -1) == NULL) + device_printf(parent, "add acpi_hp child failed\n"); +} + static int acpi_hp_probe(device_t dev) { - if (acpi_disabled("hp") || device_get_unit(dev) != 0) - return (ENXIO); - device_set_desc(dev, "HP ACPI-WMI Mapping"); + device_set_desc(dev, "HP ACPI-WMI Mapping"); return (0); } @@ -453,14 +468,12 @@ static int acpi_hp_attach(device_t dev) { struct acpi_hp_softc *sc; - devclass_t wmi_devclass; int arg; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); sc = device_get_softc(dev); sc->dev = dev; - sc->handle = acpi_get_handle(dev); sc->has_notify = 0; sc->has_cmi = 0; sc->bluetooth_enable_if_radio_on = 0; @@ -477,14 +490,7 @@ acpi_hp_attach(device_t dev) sc->verbose = 0; memset(sc->cmi_order, 0, sizeof(sc->cmi_order)); - if (!(wmi_devclass = devclass_find ("acpi_wmi"))) { - device_printf(dev, "Couldn't find acpi_wmi devclass\n"); - return (EINVAL); - } - if (!(sc->wmi_dev = devclass_get_device(wmi_devclass, 0))) { - device_printf(dev, "Couldn't find acpi_wmi device\n"); - return (EINVAL); - } + sc->wmi_dev = device_get_parent(dev); if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev, ACPI_HP_WMI_BIOS_GUID)) { device_printf(dev, diff --git a/sys/dev/acpi_support/acpi_wmi.c b/sys/dev/acpi_support/acpi_wmi.c index 9da790c5fda..5b95cc926cb 100644 --- a/sys/dev/acpi_support/acpi_wmi.c +++ b/sys/dev/acpi_support/acpi_wmi.c @@ -173,6 +173,10 @@ static device_method_t acpi_wmi_methods[] = { DEVMETHOD(device_attach, acpi_wmi_attach), DEVMETHOD(device_detach, acpi_wmi_detach), + /* bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_print_child, bus_generic_print_child), + /* acpi_wmi interface */ DEVMETHOD(acpi_wmi_provides_guid_string, acpi_wmi_provides_guid_string_method), @@ -198,7 +202,7 @@ static devclass_t acpi_wmi_devclass; DRIVER_MODULE(acpi_wmi, acpi, acpi_wmi_driver, acpi_wmi_devclass, 0, 0); MODULE_VERSION(acpi_wmi, 1); MODULE_DEPEND(acpi_wmi, acpi, 1, 1, 1); -static char *wmi_ids[] = {"PNP0C14", "PNP0c14", NULL}; +static char *wmi_ids[] = {"PNP0C14", NULL}; /* * Probe for the PNP0C14 ACPI node @@ -269,6 +273,11 @@ acpi_wmi_attach(device_t dev) } ACPI_SERIAL_END(acpi_wmi); + if (ret == 0) { + bus_generic_probe(dev); + ret = bus_generic_attach(dev); + } + return (ret); } diff --git a/sys/dev/acpica/Osd/OsdHardware.c b/sys/dev/acpica/Osd/OsdHardware.c index 15ab02670ba..1761670da57 100644 --- a/sys/dev/acpica/Osd/OsdHardware.c +++ b/sys/dev/acpica/Osd/OsdHardware.c @@ -34,12 +34,8 @@ __FBSDID("$FreeBSD$"); #include -#include -#include #include #include -#include -#include /* * ACPICA's rather gung-ho approach to hardware resource ownership is a little @@ -122,94 +118,3 @@ AcpiOsWritePciConfiguration (ACPI_PCI_ID *PciId, UINT32 Register, return (AE_OK); } - -/* - * Depth-first recursive case for finding the bus, given the slot/function. - */ -static int -acpi_bus_number(ACPI_HANDLE root, ACPI_HANDLE curr, ACPI_PCI_ID *PciId) -{ - ACPI_HANDLE parent; - ACPI_STATUS status; - ACPI_OBJECT_TYPE type; - UINT32 adr; - int bus, slot, func, class, subclass, header; - - /* Try to get the _BBN object of the root, otherwise assume it is 0. */ - bus = 0; - if (root == curr) { - status = acpi_GetInteger(root, "_BBN", &bus); - if (ACPI_FAILURE(status) && bootverbose) - printf("acpi_bus_number: root bus has no _BBN, assuming 0\n"); - return (bus); - } - status = AcpiGetParent(curr, &parent); - if (ACPI_FAILURE(status)) - return (bus); - - /* First, recurse up the tree until we find the host bus. */ - bus = acpi_bus_number(root, parent, PciId); - - /* Validate parent bus device type. */ - if (ACPI_FAILURE(AcpiGetType(parent, &type)) || type != ACPI_TYPE_DEVICE) { - printf("acpi_bus_number: not a device, type %d\n", type); - return (bus); - } - - /* Get the parent's slot and function. */ - status = acpi_GetInteger(parent, "_ADR", &adr); - if (ACPI_FAILURE(status)) - return (bus); - slot = ACPI_HIWORD(adr); - func = ACPI_LOWORD(adr); - - /* Is this a PCI-PCI or Cardbus-PCI bridge? */ - class = pci_cfgregread(bus, slot, func, PCIR_CLASS, 1); - if (class != PCIC_BRIDGE) - return (bus); - subclass = pci_cfgregread(bus, slot, func, PCIR_SUBCLASS, 1); - - /* Find the header type, masking off the multifunction bit. */ - header = pci_cfgregread(bus, slot, func, PCIR_HDRTYPE, 1) & PCIM_HDRTYPE; - if (header == PCIM_HDRTYPE_BRIDGE && subclass == PCIS_BRIDGE_PCI) - bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_1, 1); - else if (header == PCIM_HDRTYPE_CARDBUS && subclass == PCIS_BRIDGE_CARDBUS) - bus = pci_cfgregread(bus, slot, func, PCIR_SECBUS_2, 1); - return (bus); -} - -/* - * Find the bus number for a device - * - * Device: handle for the PCI root bridge device - * Region: handle for the PCI configuration space operation region - * PciId: pointer to device slot and function, we fill out bus - */ -void -AcpiOsDerivePciId(ACPI_HANDLE Device, ACPI_HANDLE Region, ACPI_PCI_ID **PciId) -{ - ACPI_HANDLE parent; - ACPI_STATUS status; - int bus; - - if (pci_cfgregopen() == 0) - panic("AcpiOsDerivePciId unable to initialize pci bus"); - - /* Try to read _BBN for bus number if we're at the root. */ - bus = 0; - if (Device == Region) { - status = acpi_GetInteger(Device, "_BBN", &bus); - if (ACPI_FAILURE(status) && bootverbose) - printf("AcpiOsDerivePciId: root bus has no _BBN, assuming 0\n"); - } - - /* Get the parent handle and call the recursive case. */ - if (ACPI_SUCCESS(AcpiGetParent(Region, &parent))) - bus = acpi_bus_number(Device, parent, *PciId); - (*PciId)->Bus = bus; - if (bootverbose) { - printf("AcpiOsDerivePciId: %s -> bus %d dev %d func %d\n", - acpi_name(Region), (*PciId)->Bus, (*PciId)->Device, - (*PciId)->Function); - } -} diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index f173dc34eb7..24982fe7def 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -66,10 +66,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include "pci_if.h" -#include -#include - #include MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices"); @@ -105,7 +101,7 @@ static int acpi_attach(device_t dev); static int acpi_suspend(device_t dev); static int acpi_resume(device_t dev); static int acpi_shutdown(device_t dev); -static device_t acpi_add_child(device_t bus, int order, const char *name, +static device_t acpi_add_child(device_t bus, u_int order, const char *name, int unit); static int acpi_print_child(device_t bus, device_t child); static void acpi_probe_nomatch(device_t bus, device_t child); @@ -129,14 +125,11 @@ static char *acpi_device_id_probe(device_t bus, device_t dev, char **ids); static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters, ACPI_BUFFER *ret); -static int acpi_device_pwr_for_sleep(device_t bus, device_t dev, - int *dstate); static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *context, void **retval); static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev, int max_depth, acpi_scan_cb_t user_fn, void *arg); -static int acpi_set_powerstate_method(device_t bus, device_t child, - int state); +static int acpi_set_powerstate(device_t child, int state); static int acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids); static void acpi_probe_children(device_t bus); @@ -207,9 +200,6 @@ static device_method_t acpi_methods[] = { DEVMETHOD(acpi_pwr_for_sleep, acpi_device_pwr_for_sleep), DEVMETHOD(acpi_scan_children, acpi_device_scan_children), - /* PCI emulation */ - DEVMETHOD(pci_set_powerstate, acpi_set_powerstate_method), - /* ISA emulation */ DEVMETHOD(isa_pnp_probe, acpi_isa_pnp_probe), @@ -264,12 +254,6 @@ TUNABLE_INT("debug.acpi.interpreter_slack", &acpi_interpreter_slack); SYSCTL_INT(_debug_acpi, OID_AUTO, interpreter_slack, CTLFLAG_RDTUN, &acpi_interpreter_slack, 1, "Turn on interpreter slack mode."); -/* Power devices off and on in suspend and resume. XXX Remove once tested. */ -static int acpi_do_powerstate = 1; -TUNABLE_INT("debug.acpi.do_powerstate", &acpi_do_powerstate); -SYSCTL_INT(_debug_acpi, OID_AUTO, do_powerstate, CTLFLAG_RW, - &acpi_do_powerstate, 1, "Turn off devices when suspending."); - /* Reset system clock while resuming. XXX Remove once tested. */ static int acpi_reset_clock = 1; TUNABLE_INT("debug.acpi.reset_clock", &acpi_reset_clock); @@ -496,29 +480,6 @@ acpi_attach(device_t dev) acpi_enable_pcie(); #endif - /* Install the default address space handlers. */ - status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, - ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); - if (ACPI_FAILURE(status)) { - device_printf(dev, "Could not initialise SystemMemory handler: %s\n", - AcpiFormatException(status)); - goto out; - } - status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, - ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); - if (ACPI_FAILURE(status)) { - device_printf(dev, "Could not initialise SystemIO handler: %s\n", - AcpiFormatException(status)); - goto out; - } - status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, - ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); - if (ACPI_FAILURE(status)) { - device_printf(dev, "could not initialise PciConfig handler: %s\n", - AcpiFormatException(status)); - goto out; - } - /* * Note that some systems (specifically, those with namespace evaluation * issues that require the avoidance of parts of the namespace) must @@ -612,6 +573,10 @@ acpi_attach(device_t dev) freeenv(env); } + /* Only enable reboot by default if the FADT says it is available. */ + if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) + sc->acpi_handle_reboot = 1; + /* Only enable S4BIOS by default if the FACS says it is available. */ if (AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT) sc->acpi_s4bios = 1; @@ -689,45 +654,43 @@ acpi_attach(device_t dev) return_VALUE (error); } +static void +acpi_set_power_children(device_t dev, int state) +{ + device_t child, parent; + device_t *devlist; + struct pci_devinfo *dinfo; + int dstate, i, numdevs; + + if (device_get_children(dev, &devlist, &numdevs) != 0) + return; + + /* + * Retrieve and set D-state for the sleep state if _SxD is present. + * Skip children who aren't attached since they are handled separately. + */ + parent = device_get_parent(dev); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = device_get_ivars(child); + dstate = state; + if (device_is_attached(child) && + acpi_device_pwr_for_sleep(parent, dev, &dstate) == 0) + acpi_set_powerstate(child, dstate); + } + free(devlist, M_TEMP); +} + static int acpi_suspend(device_t dev) { - device_t child, *devlist; - int error, i, numdevs, pstate; + int error; GIANT_REQUIRED; - /* First give child devices a chance to suspend. */ error = bus_generic_suspend(dev); - if (error) - return (error); - - /* - * Now, set them into the appropriate power state, usually D3. If the - * device has an _SxD method for the next sleep state, use that power - * state instead. - */ - error = device_get_children(dev, &devlist, &numdevs); - if (error) - return (error); - for (i = 0; i < numdevs; i++) { - /* If the device is not attached, we've powered it down elsewhere. */ - child = devlist[i]; - if (!device_is_attached(child)) - continue; - - /* - * Default to D3 for all sleep states. The _SxD method is optional - * so set the powerstate even if it's absent. - */ - pstate = PCI_POWERSTATE_D3; - error = acpi_device_pwr_for_sleep(device_get_parent(child), - child, &pstate); - if ((error == 0 || error == ESRCH) && acpi_do_powerstate) - pci_set_powerstate(child, pstate); - } - free(devlist, M_TEMP); - error = 0; + if (error == 0) + acpi_set_power_children(dev, ACPI_STATE_D3); return (error); } @@ -735,28 +698,10 @@ acpi_suspend(device_t dev) static int acpi_resume(device_t dev) { - ACPI_HANDLE handle; - int i, numdevs, error; - device_t child, *devlist; GIANT_REQUIRED; - /* - * Put all devices in D0 before resuming them. Call _S0D on each one - * since some systems expect this. - */ - error = device_get_children(dev, &devlist, &numdevs); - if (error) - return (error); - for (i = 0; i < numdevs; i++) { - child = devlist[i]; - handle = acpi_get_handle(child); - if (handle) - AcpiEvaluateObject(handle, "_S0D", NULL, NULL); - if (device_is_attached(child) && acpi_do_powerstate) - pci_set_powerstate(child, PCI_POWERSTATE_D0); - } - free(devlist, M_TEMP); + acpi_set_power_children(dev, ACPI_STATE_D0); return (bus_generic_resume(dev)); } @@ -783,7 +728,7 @@ acpi_shutdown(device_t dev) * Handle a new device being added */ static device_t -acpi_add_child(device_t bus, int order, const char *name, int unit) +acpi_add_child(device_t bus, u_int order, const char *name, int unit) { struct acpi_device *ad; device_t child; @@ -832,7 +777,7 @@ static void acpi_probe_nomatch(device_t bus, device_t child) { #ifdef ACPI_ENABLE_POWERDOWN_NODRIVER - pci_set_powerstate(child, PCI_POWERSTATE_D3); + acpi_set_powerstate(child, ACPI_STATE_D3); #endif } @@ -854,9 +799,9 @@ acpi_driver_added(device_t dev, driver_t *driver) child = devlist[i]; if (device_get_state(child) == DS_NOTPRESENT) { #ifdef ACPI_ENABLE_POWERDOWN_NODRIVER - pci_set_powerstate(child, PCI_POWERSTATE_D0); + acpi_set_powerstate(child, ACPI_STATE_D0); if (device_probe_and_attach(child) != 0) - pci_set_powerstate(child, PCI_POWERSTATE_D3); + acpi_set_powerstate(child, ACPI_STATE_D3); #else device_probe_and_attach(child); #endif @@ -1415,16 +1360,14 @@ acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname, return (AcpiEvaluateObject(h, pathname, parameters, ret)); } -static int +int acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate) { struct acpi_softc *sc; ACPI_HANDLE handle; ACPI_STATUS status; char sxd[8]; - int error; - sc = device_get_softc(bus); handle = acpi_get_handle(dev); /* @@ -1433,7 +1376,7 @@ acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate) * set to D3 and it appears that such legacy devices may * need special handling in their drivers. */ - if (handle == NULL || + if (dstate == NULL || handle == NULL || acpi_MatchHid(handle, "PNP0500") || acpi_MatchHid(handle, "PNP0501") || acpi_MatchHid(handle, "PNP0502") || @@ -1442,28 +1385,19 @@ acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate) return (ENXIO); /* - * Override next state with the value from _SxD, if present. If no - * dstate argument was provided, don't fetch the return value. + * Override next state with the value from _SxD, if present. + * Note illegal _S0D is evaluated because some systems expect this. */ + sc = device_get_softc(bus); snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate); - if (dstate) - status = acpi_GetInteger(handle, sxd, dstate); - else - status = AcpiEvaluateObject(handle, sxd, NULL, NULL); - - switch (status) { - case AE_OK: - error = 0; - break; - case AE_NOT_FOUND: - error = ESRCH; - break; - default: - error = ENXIO; - break; + status = acpi_GetInteger(handle, sxd, dstate); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + device_printf(dev, "failed to get %s on %s: %s\n", sxd, + acpi_name(handle), AcpiFormatException(status)); + return (ENXIO); } - return (error); + return (0); } /* Callback arg for our implementation of walking the namespace. */ @@ -1545,13 +1479,11 @@ acpi_device_scan_children(device_t bus, device_t dev, int max_depth, * device power states since it's close enough to ACPI. */ static int -acpi_set_powerstate_method(device_t bus, device_t child, int state) +acpi_set_powerstate(device_t child, int state) { ACPI_HANDLE h; ACPI_STATUS status; - int error; - error = 0; h = acpi_get_handle(child); if (state < ACPI_STATE_D0 || state > ACPI_D_STATES_MAX) return (EINVAL); @@ -1560,12 +1492,16 @@ acpi_set_powerstate_method(device_t bus, device_t child, int state) /* Ignore errors if the power methods aren't present. */ status = acpi_pwr_switch_consumer(h, state); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND - && status != AE_BAD_PARAMETER) - device_printf(bus, "failed to set ACPI power state D%d on %s: %s\n", - state, acpi_name(h), AcpiFormatException(status)); + if (ACPI_SUCCESS(status)) { + if (bootverbose) + device_printf(child, "set ACPI power state D%d on %s\n", + state, acpi_name(h)); + } else if (status != AE_NOT_FOUND) + device_printf(child, + "failed to set ACPI power state D%d on %s: %s\n", state, + acpi_name(h), AcpiFormatException(status)); - return (error); + return (0); } static int @@ -1692,10 +1628,10 @@ acpi_probe_order(ACPI_HANDLE handle, int *order) ACPI_OBJECT_TYPE type; /* - * 1. I/O port and memory system resource holders - * 2. Embedded controllers (to handle early accesses) - * 3. PCI Link Devices - * 100000. CPUs + * 1. CPUs + * 2. I/O port and memory system resource holders + * 3. Embedded controllers (to handle early accesses) + * 4. PCI Link Devices */ AcpiGetType(handle, &type); if (type == ACPI_TYPE_PROCESSOR) @@ -1755,8 +1691,7 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status) * placeholder so that the probe/attach passes will run * breadth-first. Orders less than ACPI_DEV_BASE_ORDER * are reserved for special objects (i.e., system - * resources). CPU devices have a very high order to - * ensure they are probed after other devices. + * resources). */ ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str)); order = level * 10 + 100; @@ -1845,19 +1780,15 @@ acpi_shutdown_final(void *arg, int howto) DELAY(1000000); device_printf(sc->acpi_dev, "power-off failed - timeout\n"); } - } else if ((howto & RB_HALT) == 0 && - (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) && - sc->acpi_handle_reboot) { + } else if ((howto & RB_HALT) == 0 && sc->acpi_handle_reboot) { /* Reboot using the reset register. */ - status = AcpiWrite( - AcpiGbl_FADT.ResetValue, &AcpiGbl_FADT.ResetRegister); - if (ACPI_FAILURE(status)) - device_printf(sc->acpi_dev, "reset failed - %s\n", - AcpiFormatException(status)); - else { + status = AcpiReset(); + if (ACPI_SUCCESS(status)) { DELAY(1000000); device_printf(sc->acpi_dev, "reset failed - timeout\n"); - } + } else if (status != AE_NOT_EXIST) + device_printf(sc->acpi_dev, "reset failed - %s\n", + AcpiFormatException(status)); } else if (sc->acpi_do_disable && panicstr == NULL) { /* * Only disable ACPI if the user requested. On some systems, writing diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 45882a23ce9..52934af690a 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -148,7 +148,7 @@ static int acpi_cpu_resume(device_t dev); static int acpi_pcpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id); static struct resource_list *acpi_cpu_get_rlist(device_t dev, device_t child); -static device_t acpi_cpu_add_child(device_t dev, int order, const char *name, +static device_t acpi_cpu_add_child(device_t dev, u_int order, const char *name, int unit); static int acpi_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result); @@ -479,7 +479,7 @@ acpi_cpu_get_rlist(device_t dev, device_t child) } static device_t -acpi_cpu_add_child(device_t dev, int order, const char *name, int unit) +acpi_cpu_add_child(device_t dev, u_int order, const char *name, int unit) { struct acpi_cpu_device *ad; device_t child; @@ -690,19 +690,11 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc) sc->cpu_cx_count++; continue; case ACPI_STATE_C2: - if (cx_ptr->trans_lat > 100) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "acpi_cpu%d: C2[%d] not available.\n", - device_get_unit(sc->cpu_dev), i)); - continue; - } sc->cpu_non_c3 = i; break; case ACPI_STATE_C3: default: - if (cx_ptr->trans_lat > 1000 || - (cpu_quirks & CPU_QUIRK_NO_C3) != 0) { - + if ((cpu_quirks & CPU_QUIRK_NO_C3) != 0) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "acpi_cpu%d: C3[%d] not available.\n", device_get_unit(sc->cpu_dev), i)); @@ -900,7 +892,13 @@ acpi_cpu_idle() /* Find the lowest state that has small enough latency. */ cx_next_idx = 0; - for (i = sc->cpu_cx_lowest; i >= 0; i--) { +#ifndef __ia64__ + if (cpu_disable_deep_sleep) + i = min(sc->cpu_cx_lowest, sc->cpu_non_c3); + else +#endif + i = sc->cpu_cx_lowest; + for (; i >= 0; i--) { if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) { cx_next_idx = i; break; @@ -929,15 +927,17 @@ acpi_cpu_idle() /* * Execute HLT (or equivalent) and wait for an interrupt. We can't * precisely calculate the time spent in C1 since the place we wake up - * is an ISR. Assume we slept no more then half of quantum. + * is an ISR. Assume we slept no more then half of quantum, unless + * we are called inside critical section, delaying context switch. */ if (cx_next->type == ACPI_STATE_C1) { AcpiHwRead(&start_time, &AcpiGbl_FADT.XPmTimerBlock); acpi_cpu_c1(); AcpiHwRead(&end_time, &AcpiGbl_FADT.XPmTimerBlock); - end_time = acpi_TimerDelta(end_time, start_time); - sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + - min(PM_USEC(end_time), 500000 / hz)) / 4; + end_time = PM_USEC(acpi_TimerDelta(end_time, start_time)); + if (curthread->td_critnest == 0) + end_time = min(end_time, 500000 / hz); + sc->cpu_prev_sleep = (sc->cpu_prev_sleep * 3 + end_time) / 4; return; } diff --git a/sys/dev/acpica/acpi_ec.c b/sys/dev/acpica/acpi_ec.c index 2c189726361..f8649830406 100644 --- a/sys/dev/acpica/acpi_ec.c +++ b/sys/dev/acpica/acpi_ec.c @@ -153,7 +153,7 @@ struct acpi_ec_softc { int ec_glkhandle; int ec_burstactive; int ec_sci_pend; - u_int ec_gencount; + volatile u_int ec_gencount; int ec_suspending; }; @@ -165,7 +165,7 @@ struct acpi_ec_softc { #define EC_LOCK_TIMEOUT 1000 /* Default delay in microseconds between each run of the status polling loop. */ -#define EC_POLL_DELAY 5 +#define EC_POLL_DELAY 50 /* Total time in ms spent waiting for a response from EC. */ #define EC_TIMEOUT 750 @@ -599,12 +599,32 @@ acpi_ec_write_method(device_t dev, u_int addr, UINT64 val, int width) return (0); } +static ACPI_STATUS +EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event) +{ + ACPI_STATUS status; + EC_STATUS ec_status; + + status = AE_NO_HARDWARE_RESPONSE; + ec_status = EC_GET_CSR(sc); + if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) { + CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg); + sc->ec_burstactive = FALSE; + } + if (EVENT_READY(event, ec_status)) { + CTR2(KTR_ACPI, "ec %s wait ready, status %#x", msg, ec_status); + status = AE_OK; + } + return (status); +} + static void EcGpeQueryHandler(void *Context) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; UINT8 Data; ACPI_STATUS Status; + int retry; char qxx[5]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -625,7 +645,16 @@ EcGpeQueryHandler(void *Context) * that may arise from running the query from causing another query * to be queued, we clear the pending flag only after running it. */ - Status = EcCommand(sc, EC_COMMAND_QUERY); + for (retry = 0; retry < 2; retry++) { + Status = EcCommand(sc, EC_COMMAND_QUERY); + if (ACPI_SUCCESS(Status)) + break; + if (EcCheckStatus(sc, "retr_check", + EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) + continue; + else + break; + } sc->ec_sci_pend = FALSE; if (ACPI_FAILURE(Status)) { EcUnlock(sc); @@ -678,7 +707,7 @@ EcGpeHandler(void *Context) * address and then data values.) */ atomic_add_int(&sc->ec_gencount, 1); - wakeup(&sc->ec_gencount); + wakeup(&sc); /* * If the EC_SCI bit of the status register is set, queue a query handler. @@ -788,69 +817,28 @@ EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 Width, return_ACPI_STATUS (Status); } -static ACPI_STATUS -EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event) -{ - ACPI_STATUS status; - EC_STATUS ec_status; - - status = AE_NO_HARDWARE_RESPONSE; - ec_status = EC_GET_CSR(sc); - if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) { - CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg); - sc->ec_burstactive = FALSE; - } - if (EVENT_READY(event, ec_status)) { - CTR2(KTR_ACPI, "ec %s wait ready, status %#x", msg, ec_status); - status = AE_OK; - } - return (status); -} - static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count) { + static int no_intr = 0; ACPI_STATUS Status; - int count, i, slp_ival; + int count, i, need_poll, slp_ival; ACPI_SERIAL_ASSERT(ec); Status = AE_NO_HARDWARE_RESPONSE; - int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending; - /* - * The main CPU should be much faster than the EC. So the status should - * be "not ready" when we start waiting. But if the main CPU is really - * slow, it's possible we see the current "ready" response. Since that - * can't be distinguished from the previous response in polled mode, - * this is a potential issue. We really should have interrupts enabled - * during boot so there is no ambiguity in polled mode. - * - * If this occurs, we add an additional delay before actually entering - * the status checking loop, hopefully to allow the EC to go to work - * and produce a non-stale status. - */ - if (need_poll) { - static int once; - - if (EcCheckStatus(sc, "pre-check", Event) == AE_OK) { - if (!once) { - device_printf(sc->ec_dev, - "warning: EC done before starting event wait\n"); - once = 1; - } - AcpiOsStall(10); - } - } + need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending; /* Wait for event by polling or GPE (interrupt). */ if (need_poll) { count = (ec_timeout * 1000) / EC_POLL_DELAY; if (count == 0) count = 1; + DELAY(10); for (i = 0; i < count; i++) { Status = EcCheckStatus(sc, "poll", Event); if (Status == AE_OK) break; - AcpiOsStall(EC_POLL_DELAY); + DELAY(EC_POLL_DELAY); } } else { slp_ival = hz / 1000; @@ -869,34 +857,37 @@ EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count) * EC query). */ for (i = 0; i < count; i++) { - if (gen_count != sc->ec_gencount) { - /* - * Record new generation count. It's possible the GPE was - * just to notify us that a query is needed and we need to - * wait for a second GPE to signal the completion of the - * event we are actually waiting for. - */ - gen_count = sc->ec_gencount; - Status = EcCheckStatus(sc, "sleep", Event); - if (Status == AE_OK) - break; + if (gen_count == sc->ec_gencount) + tsleep(&sc, 0, "ecgpe", slp_ival); + /* + * Record new generation count. It's possible the GPE was + * just to notify us that a query is needed and we need to + * wait for a second GPE to signal the completion of the + * event we are actually waiting for. + */ + Status = EcCheckStatus(sc, "sleep", Event); + if (Status == AE_OK) { + if (gen_count == sc->ec_gencount) + no_intr++; + else + no_intr = 0; + break; } - tsleep(&sc->ec_gencount, PZERO, "ecgpe", slp_ival); + gen_count = sc->ec_gencount; } /* * We finished waiting for the GPE and it never arrived. Try to * read the register once and trust whatever value we got. This is - * the best we can do at this point. Then, force polled mode on - * since this system doesn't appear to generate GPEs. + * the best we can do at this point. */ - if (Status != AE_OK) { + if (Status != AE_OK) Status = EcCheckStatus(sc, "sleep_end", Event); - device_printf(sc->ec_dev, - "wait timed out (%sresponse), forcing polled mode\n", - Status == AE_OK ? "" : "no "); - ec_polled_mode = TRUE; - } + } + if (!need_poll && no_intr > 10) { + device_printf(sc->ec_dev, + "not getting interrupts, switched to polled mode\n"); + ec_polled_mode = 1; } if (Status != AE_OK) CTR0(KTR_ACPI, "error: ec wait timed out"); @@ -933,6 +924,14 @@ EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd) return (AE_BAD_PARAMETER); } + /* + * Ensure empty input buffer before issuing command. + * Use generation count of zero to force a quick check. + */ + status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, 0); + if (ACPI_FAILURE(status)) + return (status); + /* Run the command and wait for the chosen event. */ CTR1(KTR_ACPI, "ec running command %#x", cmd); gen_count = sc->ec_gencount; @@ -955,24 +954,31 @@ EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) { ACPI_STATUS status; u_int gen_count; + int retry; ACPI_SERIAL_ASSERT(ec); CTR1(KTR_ACPI, "ec read from %#x", Address); - status = EcCommand(sc, EC_COMMAND_READ); - if (ACPI_FAILURE(status)) - return (status); + for (retry = 0; retry < 2; retry++) { + status = EcCommand(sc, EC_COMMAND_READ); + if (ACPI_FAILURE(status)) + return (status); - gen_count = sc->ec_gencount; - EC_SET_DATA(sc, Address); - status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); - if (ACPI_FAILURE(status)) { - device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); - return (status); + gen_count = sc->ec_gencount; + EC_SET_DATA(sc, Address); + status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); + if (ACPI_FAILURE(status)) { + if (EcCheckStatus(sc, "retr_check", + EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) + continue; + else + break; + } + *Data = EC_GET_DATA(sc); + return (AE_OK); } - *Data = EC_GET_DATA(sc); - - return (AE_OK); + device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); + return (status); } static ACPI_STATUS @@ -992,7 +998,7 @@ EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 Data) EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { - device_printf(sc->ec_dev, "EcRead: failed waiting for sent address\n"); + device_printf(sc->ec_dev, "EcWrite: failed waiting for sent address\n"); return (status); } diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c index b94309245ab..7ce494e8a79 100644 --- a/sys/dev/acpica/acpi_hpet.c +++ b/sys/dev/acpica/acpi_hpet.c @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #define HPET_VENDID_AMD 0x4353 #define HPET_VENDID_INTEL 0x8086 +#define HPET_VENDID_NVIDIA 0x10de ACPI_SERIAL_DECL(hpet, "ACPI HPET support"); @@ -74,6 +75,8 @@ struct hpet_softc { int irq; int useirq; int legacy_route; + int per_cpu; + uint32_t allowed_irqs; struct resource *mem_res; struct resource *intr_res; void *intr_handle; @@ -88,6 +91,8 @@ struct hpet_softc { int mode; int intr_rid; int irq; + int pcpu_cpu; + int pcpu_misrouted; int pcpu_master; int pcpu_slaves[MAXCPU]; struct resource *intr_res; @@ -95,7 +100,7 @@ struct hpet_softc { uint32_t caps; uint32_t vectors; uint32_t div; - uint32_t last; + uint32_t next; char name[8]; } t[32]; int num_timers; @@ -146,7 +151,7 @@ hpet_start(struct eventtimer *et, struct hpet_timer *mt = (struct hpet_timer *)et->et_priv; struct hpet_timer *t; struct hpet_softc *sc = mt->sc; - uint32_t fdiv; + uint32_t fdiv, now; t = (mt->pcpu_master < 0) ? mt : &sc->t[mt->pcpu_slaves[curcpu]]; if (period != NULL) { @@ -164,23 +169,35 @@ hpet_start(struct eventtimer *et, fdiv += sc->freq * first->sec; } else fdiv = t->div; - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + if (t->irq < 0) + bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); + t->caps |= HPET_TCNF_INT_ENB; + now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); +restart: + t->next = now + fdiv; if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) { t->caps |= HPET_TCNF_TYPE; bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps | HPET_TCNF_VAL_SET); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + fdiv); - bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); + t->next); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div); } else { + t->caps &= ~HPET_TCNF_TYPE; + bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), + t->caps); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + fdiv); + t->next); + } + if (fdiv < 5000) { + bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); + now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + if ((int32_t)(now - t->next) >= 0) { + fdiv *= 2; + goto restart; + } } - t->caps |= HPET_TCNF_INT_ENB; - bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); - bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps); return (0); } @@ -206,14 +223,37 @@ hpet_intr_single(void *arg) struct hpet_softc *sc = t->sc; uint32_t now; + if (t->mode == 0) + return (FILTER_STRAY); + /* Check that per-CPU timer interrupt reached right CPU. */ + if (t->pcpu_cpu >= 0 && t->pcpu_cpu != curcpu) { + if ((++t->pcpu_misrouted) % 32 == 0) { + printf("HPET interrupt routed to the wrong CPU" + " (timer %d CPU %d -> %d)!\n", + t->num, t->pcpu_cpu, curcpu); + } + + /* + * Reload timer, hoping that next time may be more lucky + * (system will manage proper interrupt binding). + */ + if ((t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) || + t->mode == 2) { + t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER) + + sc->freq / 8; + bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), + t->next); + } + return (FILTER_HANDLED); + } if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT) == 0) { - t->last += t->div; + t->next += t->div; now = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); - if ((int32_t)(now - (t->last + t->div / 2)) > 0) - t->last = now - t->div / 2; + if ((int32_t)((now + t->div / 2) - t->next) > 0) + t->next = now + t->div / 2; bus_write_4(sc->mem_res, - HPET_TIMER_COMPARATOR(t->num), t->last + t->div); + HPET_TIMER_COMPARATOR(t->num), t->next); } else if (t->mode == 2) t->mode = 0; mt = (t->pcpu_master < 0) ? t : &sc->t[t->pcpu_master]; @@ -321,7 +361,7 @@ hpet_attach(device_t dev) int i, j, num_msi, num_timers, num_percpu_et, num_percpu_t, cur_cpu; int pcpu_master; static int maxhpetet = 0; - uint32_t val, val2, cvectors; + uint32_t val, val2, cvectors, dvectors; uint16_t vendor, rev; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); @@ -385,6 +425,8 @@ hpet_attach(device_t dev) t->mode = 0; t->intr_rid = -1; t->irq = -1; + t->pcpu_cpu = -1; + t->pcpu_misrouted = 0; t->pcpu_master = -1; t->caps = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i)); t->vectors = bus_read_4(sc->mem_res, HPET_TIMER_CAP_CNF(i) + 4); @@ -438,10 +480,9 @@ hpet_attach(device_t dev) sc->t[1].vectors = 0; } - num_msi = 0; - sc->useirq = 0; - /* Find common legacy IRQ vectors for all timers. */ - cvectors = 0xffff0000; + /* Check what IRQs we want use. */ + /* By default allow any PCI IRQs. */ + sc->allowed_irqs = 0xffff0000; /* * HPETs in AMD chipsets before SB800 have problems with IRQs >= 16 * Lower are also not always working for different reasons. @@ -450,7 +491,36 @@ hpet_attach(device_t dev) * interrupt loss. Avoid legacy IRQs for AMD. */ if (vendor == HPET_VENDID_AMD) - cvectors = 0x00000000; + sc->allowed_irqs = 0x00000000; + /* + * NVidia MCP5x chipsets have number of unexplained interrupt + * problems. For some reason, using HPET interrupts breaks HDA sound. + */ + if (vendor == HPET_VENDID_NVIDIA && rev <= 0x01) + sc->allowed_irqs = 0x00000000; + /* + * Neither QEMU nor VirtualBox report supported IRQs correctly. + * The only way to use HPET there is to specify IRQs manually + * and/or use legacy_route. Legacy_route mode work on both. + */ + if (vm_guest) + sc->allowed_irqs = 0x00000000; + /* Let user override. */ + resource_int_value(device_get_name(dev), device_get_unit(dev), + "allowed_irqs", &sc->allowed_irqs); + + /* Get how much per-CPU timers we should try to provide. */ + sc->per_cpu = 1; + resource_int_value(device_get_name(dev), device_get_unit(dev), + "per_cpu", &sc->per_cpu); + + num_msi = 0; + sc->useirq = 0; + /* Find IRQ vectors for all timers. */ + cvectors = sc->allowed_irqs & 0xffff0000; + dvectors = sc->allowed_irqs & 0x0000ffff; + if (sc->legacy_route) + dvectors &= 0x0000fefe; for (i = 0; i < num_timers; i++) { t = &sc->t[i]; if (sc->legacy_route && i < 2) @@ -465,6 +535,10 @@ hpet_attach(device_t dev) } } #endif + else if (dvectors & t->vectors) { + t->irq = ffs(dvectors & t->vectors) - 1; + dvectors &= ~(1 << t->irq); + } if (t->irq >= 0) { if (!(t->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, &t->intr_rid, @@ -495,7 +569,7 @@ hpet_attach(device_t dev) if (sc->legacy_route) hpet_enable(sc); /* Group timers for per-CPU operation. */ - num_percpu_et = min(num_msi / mp_ncpus, 2); + num_percpu_et = min(num_msi / mp_ncpus, sc->per_cpu); num_percpu_t = num_percpu_et * mp_ncpus; pcpu_master = 0; cur_cpu = CPU_FIRST(); @@ -504,13 +578,15 @@ hpet_attach(device_t dev) if (t->irq >= 0 && num_percpu_t > 0) { if (cur_cpu == CPU_FIRST()) pcpu_master = i; + t->pcpu_cpu = cur_cpu; t->pcpu_master = pcpu_master; sc->t[pcpu_master]. pcpu_slaves[cur_cpu] = i; bus_bind_intr(dev, t->intr_res, cur_cpu); cur_cpu = CPU_NEXT(cur_cpu); num_percpu_t--; - } + } else if (t->irq >= 0) + bus_bind_intr(dev, t->intr_res, CPU_FIRST()); } bus_write_4(sc->mem_res, HPET_ISR, 0xffffffff); sc->irq = -1; @@ -545,7 +621,7 @@ hpet_attach(device_t dev) /* Legacy route doesn't need more configuration. */ } else #ifdef DEV_APIC - if (t->irq >= 0) { + if ((t->caps & HPET_TCAP_FSB_INT_DEL) && t->irq >= 0) { uint64_t addr; uint32_t data; @@ -561,7 +637,9 @@ hpet_attach(device_t dev) t->irq = -2; } else #endif - if (sc->irq >= 0 && (t->vectors & (1 << sc->irq))) + if (t->irq >= 0) + t->caps |= (t->irq << 9); + else if (sc->irq >= 0 && (t->vectors & (1 << sc->irq))) t->caps |= (sc->irq << 9) | HPET_TCNF_INT_TYPE; bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(i), t->caps); /* Skip event timers without set up IRQ. */ @@ -585,7 +663,7 @@ hpet_attach(device_t dev) t->et.et_quality -= 10; t->et.et_frequency = sc->freq; t->et.et_min_period.sec = 0; - t->et.et_min_period.frac = 0x00004000LLU << 32; + t->et.et_min_period.frac = 0x00008000LLU << 32; t->et.et_max_period.sec = 0xfffffffeLLU / sc->freq; t->et.et_max_period.frac = ((0xfffffffeLLU << 32) / sc->freq) << 32; @@ -612,15 +690,15 @@ hpet_detach(device_t dev) static int hpet_suspend(device_t dev) { - struct hpet_softc *sc; +// struct hpet_softc *sc; /* * Disable the timer during suspend. The timer will not lose * its state in S1 or S2, but we are required to disable * it. */ - sc = device_get_softc(dev); - hpet_disable(sc); +// sc = device_get_softc(dev); +// hpet_disable(sc); return (0); } @@ -655,19 +733,21 @@ hpet_resume(device_t dev) #endif if (t->mode == 0) continue; - t->last = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); + t->next = bus_read_4(sc->mem_res, HPET_MAIN_COUNTER); if (t->mode == 1 && (t->caps & HPET_TCAP_PER_INT)) { t->caps |= HPET_TCNF_TYPE; + t->next += t->div; bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps | HPET_TCNF_VAL_SET); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + t->div); + t->next); bus_read_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num)); bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), t->div); } else { + t->next += sc->freq / 1024; bus_write_4(sc->mem_res, HPET_TIMER_COMPARATOR(t->num), - t->last + sc->freq / 1024); + t->next); } bus_write_4(sc->mem_res, HPET_ISR, 1 << t->num); bus_write_4(sc->mem_res, HPET_TIMER_CAP_CNF(t->num), t->caps); diff --git a/sys/dev/acpica/acpi_if.m b/sys/dev/acpica/acpi_if.m index 36fad85bd77..f0a68e3870d 100644 --- a/sys/dev/acpica/acpi_if.m +++ b/sys/dev/acpica/acpi_if.m @@ -123,8 +123,7 @@ METHOD ACPI_STATUS evaluate_object { # # int *dstate: if successful, contains the highest valid sleep state # -# Returns: 0 on success, ESRCH if device has no special state, or -# some other error value. +# Returns: 0 on success or some other error value. # METHOD int pwr_for_sleep { device_t bus; diff --git a/sys/dev/acpica/acpi_pci.c b/sys/dev/acpica/acpi_pci.c index 9cf064ee39d..a14e0ba4198 100644 --- a/sys/dev/acpica/acpi_pci.c +++ b/sys/dev/acpica/acpi_pci.c @@ -179,18 +179,22 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state) */ ACPI_SERIAL_BEGIN(pci_powerstate); old_state = pci_get_powerstate(child); - if (old_state < state) { + if (old_state < state && pci_do_power_suspend) { error = pci_set_powerstate_method(dev, child, state); if (error) goto out; } h = acpi_get_handle(child); status = acpi_pwr_switch_consumer(h, state); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + if (ACPI_SUCCESS(status)) { + if (bootverbose) + device_printf(dev, "set ACPI power state D%d on %s\n", + state, acpi_name(h)); + } else if (status != AE_NOT_FOUND) device_printf(dev, - "Failed to set ACPI power state D%d on %s: %s\n", + "failed to set ACPI power state D%d on %s: %s\n", state, acpi_name(h), AcpiFormatException(status)); - if (old_state > state) + if (old_state > state && pci_do_power_resume) error = pci_set_powerstate_method(dev, child, state); out: diff --git a/sys/dev/acpica/acpi_pcib.c b/sys/dev/acpica/acpi_pcib.c index 65996f5b066..1b26b4f6a1f 100644 --- a/sys/dev/acpica/acpi_pcib.c +++ b/sys/dev/acpica/acpi_pcib.c @@ -275,3 +275,14 @@ out: return_VALUE (interrupt); } + +int +acpi_pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) +{ + device_t acpi_dev; + + acpi_dev = devclass_get_device(devclass_find("acpi"), 0); + acpi_device_pwr_for_sleep(acpi_dev, dev, pstate); + return (0); +} + diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c index 72753303cc1..2ea9f2c1e1c 100644 --- a/sys/dev/acpica/acpi_pcib_acpi.c +++ b/sys/dev/acpica/acpi_pcib_acpi.c @@ -116,6 +116,7 @@ static device_method_t acpi_pcib_acpi_methods[] = { DEVMETHOD(pcib_alloc_msix, acpi_pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, acpi_pcib_map_msi), + DEVMETHOD(pcib_power_for_sleep, acpi_pcib_power_for_sleep), {0, 0} }; diff --git a/sys/dev/acpica/acpi_pcib_pci.c b/sys/dev/acpica/acpi_pcib_pci.c index 2196940c721..a76698141f0 100644 --- a/sys/dev/acpica/acpi_pcib_pci.c +++ b/sys/dev/acpica/acpi_pcib_pci.c @@ -80,6 +80,7 @@ static device_method_t acpi_pcib_pci_methods[] = { /* pcib interface */ DEVMETHOD(pcib_route_interrupt, acpi_pcib_pci_route_interrupt), + DEVMETHOD(pcib_power_for_sleep, acpi_pcib_power_for_sleep), {0, 0} }; diff --git a/sys/dev/acpica/acpi_pcibvar.h b/sys/dev/acpica/acpi_pcibvar.h index 00e03fa16bf..9a4be077f58 100644 --- a/sys/dev/acpica/acpi_pcibvar.h +++ b/sys/dev/acpica/acpi_pcibvar.h @@ -38,6 +38,8 @@ int acpi_pci_link_route_interrupt(device_t dev, int index); int acpi_pcib_attach(device_t bus, ACPI_BUFFER *prt, int busno); int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, ACPI_BUFFER *prtbuf); +int acpi_pcib_power_for_sleep(device_t pcib, device_t dev, + int *pstate); #endif /* _KERNEL */ diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index adc9d6ea66c..34284d5d8e1 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -393,6 +393,8 @@ EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t); /* Device power control. */ ACPI_STATUS acpi_pwr_wake_enable(ACPI_HANDLE consumer, int enable); ACPI_STATUS acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state); +int acpi_device_pwr_for_sleep(device_t bus, device_t dev, + int *dstate); /* Misc. */ static __inline struct acpi_softc * diff --git a/sys/dev/ae/if_ae.c b/sys/dev/ae/if_ae.c index d2812a4990b..1a8251623e9 100644 --- a/sys/dev/ae/if_ae.c +++ b/sys/dev/ae/if_ae.c @@ -360,9 +360,6 @@ ae_attach(device_t dev) if (error != 0) goto fail; - /* Set default PHY address. */ - sc->phyaddr = AE_PHYADDR_DEFAULT; - ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "could not allocate ifnet structure.\n"); @@ -390,10 +387,11 @@ ae_attach(device_t dev) /* * Configure and attach MII bus. */ - error = mii_phy_probe(dev, &sc->miibus, ae_mediachange, - ae_mediastatus); + error = mii_attach(dev, &sc->miibus, ifp, ae_mediachange, + ae_mediastatus, BMSR_DEFCAPMASK, AE_PHYADDR_DEFAULT, + MII_OFFSET_ANY, 0); if (error != 0) { - device_printf(dev, "no PHY found.\n"); + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -565,6 +563,8 @@ ae_init_locked(ae_softc_t *sc) AE_LOCK_ASSERT(sc); ifp = sc->ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return (0); mii = device_get_softc(sc->miibus); ae_stop(sc); @@ -811,9 +811,6 @@ ae_miibus_readreg(device_t dev, int phy, int reg) * Locking is done in upper layers. */ - if (phy != sc->phyaddr) - return (0); - val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE | ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK); @@ -849,9 +846,6 @@ ae_miibus_writereg(device_t dev, int phy, int reg, int val) * Locking is done in upper layers. */ - if (phy != sc->phyaddr) - return (0); - aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) | AE_MDIO_START | AE_MDIO_SUP_PREAMBLE | ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) | @@ -1786,7 +1780,10 @@ ae_int_task(void *arg, int pending) if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { if ((val & (AE_ISR_DMAR_TIMEOUT | AE_ISR_DMAW_TIMEOUT | AE_ISR_PHY_LINKDOWN)) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); + AE_UNLOCK(sc); + return; } if ((val & AE_ISR_TX_EVENT) != 0) ae_tx_intr(sc); @@ -1997,6 +1994,7 @@ ae_watchdog(ae_softc_t *sc) if_printf(ifp, "watchdog timeout - resetting.\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(sc->tq, &sc->tx_task); @@ -2107,8 +2105,10 @@ ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) else if (ifp->if_mtu != ifr->ifr_mtu) { AE_LOCK(sc); ifp->if_mtu = ifr->ifr_mtu; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ae_init_locked(sc); + } AE_UNLOCK(sc); } break; diff --git a/sys/dev/ae/if_aevar.h b/sys/dev/ae/if_aevar.h index eaef62e1f79..862340144d7 100644 --- a/sys/dev/ae/if_aevar.h +++ b/sys/dev/ae/if_aevar.h @@ -111,7 +111,6 @@ typedef struct ae_softc { struct mtx mtx; - int phyaddr; uint8_t eaddr[ETHER_ADDR_LEN]; uint8_t flags; int if_flags; diff --git a/sys/dev/age/if_age.c b/sys/dev/age/if_age.c index 15ce0eff851..c9ea4cdac88 100644 --- a/sys/dev/age/if_age.c +++ b/sys/dev/age/if_age.c @@ -210,8 +210,6 @@ age_miibus_readreg(device_t dev, int phy, int reg) int i; sc = device_get_softc(dev); - if (phy != sc->age_phyaddr) - return (0); CSR_WRITE_4(sc, AGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); @@ -241,8 +239,6 @@ age_miibus_writereg(device_t dev, int phy, int reg, int val) int i; sc = device_get_softc(dev); - if (phy != sc->age_phyaddr) - return (0); CSR_WRITE_4(sc, AGE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | @@ -621,9 +617,11 @@ age_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->age_miibus, age_mediachange, - age_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->age_miibus, ifp, age_mediachange, + age_mediastatus, BMSR_DEFCAPMASK, sc->age_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1565,6 +1563,7 @@ age_encap(struct age_softc *sc, struct mbuf **m_head) *m_head = NULL; return (ENOBUFS); } + ip = (struct ip *)(mtod(m, char *) + ip_off); tcp = (struct tcphdr *)(mtod(m, char *) + poff); /* * L1 requires IP/TCP header size and offset as @@ -1781,6 +1780,7 @@ age_watchdog(struct age_softc *sc) if ((sc->age_flags & AGE_FLAG_LINK) == 0) { if_printf(sc->age_ifp, "watchdog timeout (missed link)\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; age_init_locked(sc); return; } @@ -1793,6 +1793,7 @@ age_watchdog(struct age_softc *sc) } if_printf(sc->age_ifp, "watchdog timeout\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; age_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) taskqueue_enqueue(sc->age_tq, &sc->age_tx_task); @@ -1817,8 +1818,10 @@ age_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) else if (ifp->if_mtu != ifr->ifr_mtu) { AGE_LOCK(sc); ifp->if_mtu = ifr->ifr_mtu; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; age_init_locked(sc); + } AGE_UNLOCK(sc); } break; @@ -2165,6 +2168,7 @@ age_int_task(void *arg, int pending) if ((status & INTR_DMA_WR_TO_RST) != 0) device_printf(sc->age_dev, "DMA write error! -- resetting\n"); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; age_init_locked(sc); } if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) @@ -2529,6 +2533,9 @@ age_init_locked(struct age_softc *sc) ifp = sc->age_ifp; mii = device_get_softc(sc->age_miibus); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + /* * Cancel any pending I/O. */ diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 2f53f822a9d..d6357b2edcb 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -151,14 +151,16 @@ static struct { {0x3a058086, 0x00, "Intel ICH10", 0}, {0x3a228086, 0x00, "Intel ICH10", 0}, {0x3a258086, 0x00, "Intel ICH10", 0}, - {0x3b228086, 0x00, "Intel PCH", 0}, - {0x3b238086, 0x00, "Intel PCH", 0}, - {0x3b248086, 0x00, "Intel PCH", 0}, - {0x3b258086, 0x00, "Intel PCH", 0}, - {0x3b298086, 0x00, "Intel PCH", 0}, - {0x3b2b8086, 0x00, "Intel PCH", 0}, - {0x3b2c8086, 0x00, "Intel PCH", 0}, - {0x3b2f8086, 0x00, "Intel PCH", 0}, + {0x3b228086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b238086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b258086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b298086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b2c8086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b2f8086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x1c028086, 0x00, "Intel Cougar Point", 0}, + {0x1c038086, 0x00, "Intel Cougar Point", 0}, + {0x1c048086, 0x00, "Intel Cougar Point", 0}, + {0x1c058086, 0x00, "Intel Cougar Point", 0}, {0x2361197b, 0x00, "JMicron JMB361", AHCI_Q_NOFORCE}, {0x2363197b, 0x00, "JMicron JMB363", AHCI_Q_NOFORCE}, {0x2365197b, 0x00, "JMicron JMB365", AHCI_Q_NOFORCE}, @@ -1852,6 +1854,7 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) device_t dev = slot->dev; struct ahci_channel *ch = device_get_softc(dev); union ccb *ccb = slot->ccb; + int lastto; bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, BUS_DMASYNC_POSTWRITE); @@ -1953,11 +1956,6 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) ch->oslots &= ~(1 << slot->slot); ch->rslots &= ~(1 << slot->slot); ch->aslots &= ~(1 << slot->slot); - if (et != AHCI_ERR_TIMEOUT) { - if (ch->toslots == (1 << slot->slot)) - xpt_release_simq(ch->sim, TRUE); - ch->toslots &= ~(1 << slot->slot); - } slot->state = AHCI_SLOT_EMPTY; slot->ccb = NULL; /* Update channel stats. */ @@ -1968,6 +1966,13 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) ch->numtslots--; ch->numtslotspd[ccb->ccb_h.target_id]--; } + /* Cancel timeout state if request completed normally. */ + if (et != AHCI_ERR_TIMEOUT) { + lastto = (ch->toslots == (1 << slot->slot)); + ch->toslots &= ~(1 << slot->slot); + if (lastto) + xpt_release_simq(ch->sim, TRUE); + } /* If it was first request of reset sequence and there is no error, * proceed to second request. */ if ((ccb->ccb_h.func_code == XPT_ATA_IO) && diff --git a/sys/dev/aic7xxx/aicasm/Makefile b/sys/dev/aic7xxx/aicasm/Makefile index 9c7349390f0..c07728544ad 100644 --- a/sys/dev/aic7xxx/aicasm/Makefile +++ b/sys/dev/aic7xxx/aicasm/Makefile @@ -24,7 +24,7 @@ WARNS?= 5 DEPENDFILE= .depend_aicasm .endif -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" CFLAGS+= -restrict NOSTDINC= -X .else diff --git a/sys/dev/alc/if_alc.c b/sys/dev/alc/if_alc.c index 8830b0557e4..5f0f7eccfd8 100644 --- a/sys/dev/alc/if_alc.c +++ b/sys/dev/alc/if_alc.c @@ -235,9 +235,6 @@ alc_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (phy != sc->alc_phyaddr) - return (0); - /* * For AR8132 fast ethernet controller, do not report 1000baseT * capability to mii(4). Even though AR8132 uses the same @@ -274,9 +271,6 @@ alc_miibus_writereg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); - if (phy != sc->alc_phyaddr) - return (0); - CSR_WRITE_4(sc, ALC_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); @@ -978,9 +972,11 @@ alc_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->alc_miibus, alc_mediachange, - alc_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->alc_miibus, ifp, alc_mediachange, + alc_mediastatus, BMSR_DEFCAPMASK, sc->alc_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -2019,7 +2015,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) struct tcphdr *tcp; bus_dma_segment_t txsegs[ALC_MAXTXSEGS]; bus_dmamap_t map; - uint32_t cflags, hdrlen, poff, vtag; + uint32_t cflags, hdrlen, ip_off, poff, vtag; int error, idx, nsegs, prod; ALC_LOCK_ASSERT(sc); @@ -2029,7 +2025,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) m = *m_head; ip = NULL; tcp = NULL; - poff = 0; + ip_off = poff = 0; if ((m->m_pkthdr.csum_flags & (ALC_CSUM_FEATURES | CSUM_TSO)) != 0) { /* * AR813x/AR815x requires offset of TCP/UDP header in its @@ -2039,6 +2035,7 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) * cycles on FreeBSD so fast host CPU is required to get * smooth TSO performance. */ + struct ether_header *eh; if (M_WRITABLE(m) == 0) { /* Get a writable copy. */ @@ -2052,15 +2049,32 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) *m_head = m; } - m = m_pullup(m, sizeof(struct ether_header) + - sizeof(struct ip)); + ip_off = sizeof(struct ether_header); + m = m_pullup(m, ip_off); if (m == NULL) { *m_head = NULL; return (ENOBUFS); } - ip = (struct ip *)(mtod(m, char *) + - sizeof(struct ether_header)); - poff = sizeof(struct ether_header) + (ip->ip_hl << 2); + eh = mtod(m, struct ether_header *); + /* + * Check if hardware VLAN insertion is off. + * Additional check for LLC/SNAP frame? + */ + if (eh->ether_type == htons(ETHERTYPE_VLAN)) { + ip_off = sizeof(struct ether_vlan_header); + m = m_pullup(m, ip_off); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } + } + m = m_pullup(m, ip_off + sizeof(struct ip)); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } + ip = (struct ip *)(mtod(m, char *) + ip_off); + poff = ip_off + (ip->ip_hl << 2); if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { m = m_pullup(m, poff + sizeof(struct tcphdr)); if (m == NULL) { @@ -2086,6 +2100,8 @@ alc_encap(struct alc_softc *sc, struct mbuf **m_head) * Reset IP checksum and recompute TCP pseudo * checksum as NDIS specification said. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); + tcp = (struct tcphdr *)(mtod(m, char *) + poff); ip->ip_sum = 0; tcp->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htons(IPPROTO_TCP)); @@ -2948,8 +2964,8 @@ alc_rxeof(struct alc_softc *sc, struct rx_rdesc *rrd) * errored frames. */ status |= RRD_TCP_UDPCSUM_NOK | RRD_IPCSUM_NOK; - if ((RRD_ERR_CRC | RRD_ERR_ALIGN | RRD_ERR_TRUNC | - RRD_ERR_RUNT) != 0) + if ((status & (RRD_ERR_CRC | RRD_ERR_ALIGN | + RRD_ERR_TRUNC | RRD_ERR_RUNT)) != 0) return; } diff --git a/sys/dev/ale/if_ale.c b/sys/dev/ale/if_ale.c index ea6b53b6ff9..2122d75b7ae 100644 --- a/sys/dev/ale/if_ale.c +++ b/sys/dev/ale/if_ale.c @@ -208,9 +208,6 @@ ale_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (phy != sc->ale_phyaddr) - return (0); - CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_READ | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); for (i = ALE_PHY_TIMEOUT; i > 0; i--) { @@ -237,9 +234,6 @@ ale_miibus_writereg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); - if (phy != sc->ale_phyaddr) - return (0); - CSR_WRITE_4(sc, ALE_MDIO, MDIO_OP_EXECUTE | MDIO_OP_WRITE | (val & MDIO_DATA_MASK) << MDIO_DATA_SHIFT | MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg)); @@ -605,9 +599,11 @@ ale_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->ale_miibus, ale_mediachange, - ale_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->ale_miibus, ifp, ale_mediachange, + ale_mediastatus, BMSR_DEFCAPMASK, sc->ale_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1677,6 +1673,7 @@ ale_encap(struct ale_softc *sc, struct mbuf **m_head) *m_head = NULL; return (ENOBUFS); } + ip = (struct ip *)(mtod(m, char *) + ip_off); tcp = (struct tcphdr *)(mtod(m, char *) + poff); m = m_pullup(m, poff + (tcp->th_off << 2)); if (m == NULL) { diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 8c0ea9ddadc..f40dcc2edcb 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -83,6 +83,7 @@ static void bswap(int8_t *, int); static void btrim(int8_t *, int); static void bpack(int8_t *, int8_t *, int); static void ata_interrupt_locked(void *data); +static void ata_periodic_poll(void *data); /* global vars */ MALLOC_DEFINE(M_ATA, "ata_generic", "ATA driver generic layer"); @@ -173,6 +174,7 @@ ata_attach(device_t dev) ch->curr[i] = ch->user[i]; } #endif + callout_init(&ch->poll_callout, 1); /* reset the controller HW, the channel and device(s) */ while (ATA_LOCKING(dev, ATA_LF_LOCK) != ch->unit) @@ -200,6 +202,8 @@ ata_attach(device_t dev) device_printf(dev, "unable to setup interrupt\n"); return error; } + if (ch->flags & ATA_PERIODIC_POLL) + callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); #ifndef ATA_CAM /* probe and attach devices on this channel unless we are in early boot */ @@ -246,6 +250,8 @@ err2: err1: bus_release_resource(dev, SYS_RES_IRQ, rid, ch->r_irq); mtx_unlock(&ch->state_mtx); + if (ch->flags & ATA_PERIODIC_POLL) + callout_drain(&ch->poll_callout); return (error); #endif } @@ -267,6 +273,8 @@ ata_detach(device_t dev) mtx_lock(&ch->state_mtx); ch->state |= ATA_STALL_QUEUE; mtx_unlock(&ch->state_mtx); + if (ch->flags & ATA_PERIODIC_POLL) + callout_drain(&ch->poll_callout); #ifndef ATA_CAM /* detach & delete all children */ @@ -454,6 +462,8 @@ ata_suspend(device_t dev) if (!dev || !(ch = device_get_softc(dev))) return ENXIO; + if (ch->flags & ATA_PERIODIC_POLL) + callout_drain(&ch->poll_callout); #ifdef ATA_CAM mtx_lock(&ch->state_mtx); xpt_freeze_simq(ch->sim, 1); @@ -498,6 +508,8 @@ ata_resume(device_t dev) /* kick off requests on the queue */ ata_start(dev); #endif + if (ch->flags & ATA_PERIODIC_POLL) + callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); return error; } @@ -564,6 +576,15 @@ ata_interrupt_locked(void *data) #endif } +static void +ata_periodic_poll(void *data) +{ + struct ata_channel *ch = (struct ata_channel *)data; + + callout_reset(&ch->poll_callout, hz, ata_periodic_poll, ch); + ata_interrupt(ch); +} + void ata_print_cable(device_t dev, u_int8_t *who) { diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 87226cc11f2..17a28c0ac7f 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -114,13 +114,6 @@ #define ATA_SS_IPM_PARTIAL 0x00000200 #define ATA_SS_IPM_SLUMBER 0x00000600 -#define ATA_SS_CONWELL_MASK \ - (ATA_SS_DET_MASK|ATA_SS_SPD_MASK|ATA_SS_IPM_MASK) -#define ATA_SS_CONWELL_GEN1 \ - (ATA_SS_DET_PHY_ONLINE|ATA_SS_SPD_GEN1|ATA_SS_IPM_ACTIVE) -#define ATA_SS_CONWELL_GEN2 \ - (ATA_SS_DET_PHY_ONLINE|ATA_SS_SPD_GEN2|ATA_SS_IPM_ACTIVE) - #define ATA_SERROR 14 #define ATA_SE_DATA_CORRECTED 0x00000001 #define ATA_SE_COMM_CORRECTED 0x00000002 @@ -565,6 +558,9 @@ struct ata_channel { #define ATA_NO_ATAPI_DMA 0x40 #define ATA_SATA 0x80 #define ATA_DMA_BEFORE_CMD 0x100 +#define ATA_KNOWN_PRESENCE 0x200 +#define ATA_STATUS_IS_LONG 0x400 +#define ATA_PERIODIC_POLL 0x800 int pm_level; /* power management level */ int devices; /* what is present */ @@ -591,6 +587,7 @@ struct ata_channel { struct ata_cam_device user[16]; /* User-specified settings */ struct ata_cam_device curr[16]; /* Current settings */ #endif + struct callout poll_callout; /* Periodic status poll. */ }; /* disk bay/enclosure related */ @@ -664,7 +661,7 @@ void ata_dmainit(device_t); void ata_dmafini(device_t dev); /* ata-sata.c: */ -void ata_sata_phy_check_events(device_t dev); +void ata_sata_phy_check_events(device_t dev, int port); int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val); int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val); int ata_sata_phy_reset(device_t dev, int port, int quick); diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index 6c196d60a44..288fd174b01 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -474,7 +474,8 @@ ata_generic_reset(device_t dev) ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER)); DELAY(10); ostat0 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) { + if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && + ostat0 != 0xa5) { stat0 = ATA_S_BUSY; mask |= 0x01; } @@ -484,7 +485,8 @@ ata_generic_reset(device_t dev) ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE)); DELAY(10); ostat1 = ATA_IDX_INB(ch, ATA_STATUS); - if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) { + if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) && + ostat1 != 0xa5) { stat1 = ATA_S_BUSY; mask |= 0x02; } @@ -514,10 +516,13 @@ ata_generic_reset(device_t dev) if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER)); DELAY(10); + if (ch->flags & ATA_STATUS_IS_LONG) + stat0 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff; + else + stat0 = ATA_IDX_INB(ch, ATA_STATUS); err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat0 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) device_printf(dev, "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", @@ -544,10 +549,13 @@ ata_generic_reset(device_t dev) !((mask & 0x01) && (stat0 & ATA_S_BUSY))) { ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE)); DELAY(10); + if (ch->flags & ATA_STATUS_IS_LONG) + stat1 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff; + else + stat1 = ATA_IDX_INB(ch, ATA_STATUS); err = ATA_IDX_INB(ch, ATA_ERROR); lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); msb = ATA_IDX_INB(ch, ATA_CYL_MSB); - stat1 = ATA_IDX_INB(ch, ATA_STATUS); if (bootverbose) device_printf(dev, "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n", @@ -570,22 +578,16 @@ ata_generic_reset(device_t dev) } } - if (mask == 0x00) /* nothing to wait for */ - break; - if (mask == 0x01) /* wait for master only */ - if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10)) - break; - if (mask == 0x02) /* wait for slave only */ - if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 10)) - break; - if (mask == 0x03) { /* wait for both master & slave */ - if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY)) - break; - if ((stat0 == 0xff) && (timeout > 20)) - mask &= ~0x01; - if ((stat1 == 0xff) && (timeout > 20)) - mask &= ~0x02; + if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 && + timeout > ((mask == 0x03) ? 20 : 10)) { + if ((mask & 0x01) && stat0 == 0xff) + mask &= ~0x01; + if ((mask & 0x02) && stat1 == 0xff) + mask &= ~0x02; } + if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) && + ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY))) + break; ata_udelay(100000); } diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index c847e90c0dc..cf579f80f2d 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -615,6 +615,7 @@ ata_pcichannel_attach(device_t dev) return (0); ch->attached = 1; + ch->dev = dev; ch->unit = (intptr_t)device_get_ivars(dev); resource_int_value(device_get_name(dev), diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index 7fa76440ed6..258212eb9b6 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -204,6 +204,29 @@ struct ata_pci_controller { #define ATA_I82801JI_AH 0x3a228086 #define ATA_I82801JI_R1 0x3a258086 #define ATA_I82801JI_S2 0x3a268086 + +#define ATA_5Series_S1 0x3b208086 +#define ATA_5Series_S2 0x3b218086 +#define ATA_5Series_AH1 0x3b228086 +#define ATA_5Series_AH2 0x3b238086 +#define ATA_5Series_R1 0x3b258086 +#define ATA_5Series_S3 0x3b268086 +#define ATA_5Series_S4 0x3b288086 +#define ATA_5Series_AH3 0x3b298086 +#define ATA_5Series_R2 0x3b2c8086 +#define ATA_5Series_S5 0x3b2d8086 +#define ATA_5Series_S6 0x3b2e8086 +#define ATA_5Series_AH4 0x3b2f8086 + +#define ATA_CPT_S1 0x1c008086 +#define ATA_CPT_S2 0x1c018086 +#define ATA_CPT_AH1 0x1c028086 +#define ATA_CPT_AH2 0x1c038086 +#define ATA_CPT_R1 0x1c048086 +#define ATA_CPT_R2 0x1c058086 +#define ATA_CPT_S3 0x1c088086 +#define ATA_CPT_S4 0x1c098086 + #define ATA_I31244 0x32008086 #define ATA_ISCH 0x811a8086 diff --git a/sys/dev/ata/ata-sata.c b/sys/dev/ata/ata-sata.c index d4c52fd475b..d3df7ce4e4d 100644 --- a/sys/dev/ata/ata-sata.c +++ b/sys/dev/ata/ata-sata.c @@ -48,20 +48,23 @@ __FBSDID("$FreeBSD$"); #include void -ata_sata_phy_check_events(device_t dev) +ata_sata_phy_check_events(device_t dev, int port) { struct ata_channel *ch = device_get_softc(dev); - u_int32_t error = ATA_IDX_INL(ch, ATA_SERROR); + u_int32_t error, status; - /* clear error bits/interrupt */ - ATA_IDX_OUTL(ch, ATA_SERROR, error); + ata_sata_scr_read(ch, port, ATA_SERROR, &error); + /* Clear set error bits/interrupt. */ + if (error) + ata_sata_scr_write(ch, port, ATA_SERROR, error); /* if we have a connection event deal with it */ if ((error & ATA_SE_PHY_CHANGED) && (ch->pm_level == 0)) { if (bootverbose) { - u_int32_t status = ATA_IDX_INL(ch, ATA_SSTATUS); - if (((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1) || - ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)) { + ata_sata_scr_read(ch, port, ATA_SSTATUS, &status); + if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && + ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && + ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) { device_printf(dev, "CONNECT requested\n"); } else device_printf(dev, "DISCONNECT requested\n"); @@ -73,69 +76,51 @@ ata_sata_phy_check_events(device_t dev) int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val) { - int r; - if (port < 0) { + if (ch->hw.pm_read != NULL) + return (ch->hw.pm_read(ch->dev, port, reg, val)); + if (ch->r_io[reg].res) { *val = ATA_IDX_INL(ch, reg); return (0); - } else { - switch (reg) { - case ATA_SSTATUS: - r = 0; - break; - case ATA_SERROR: - r = 1; - break; - case ATA_SCONTROL: - r = 2; - break; - default: - return (EINVAL); - } - return (ch->hw.pm_read(ch->dev, port, r, val)); } + return (-1); } int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val) { - int r; - if (port < 0) { + if (ch->hw.pm_write != NULL) + return (ch->hw.pm_write(ch->dev, port, reg, val)); + if (ch->r_io[reg].res) { ATA_IDX_OUTL(ch, reg, val); return (0); - } else { - switch (reg) { - case ATA_SERROR: - r = 1; - break; - case ATA_SCONTROL: - r = 2; - break; - default: - return (EINVAL); - } - return (ch->hw.pm_write(ch->dev, port, r, val)); } + return (-1); } static int -ata_sata_connect(struct ata_channel *ch, int port) +ata_sata_connect(struct ata_channel *ch, int port, int quick) { u_int32_t status; - int timeout; + int timeout, t; /* wait up to 1 second for "connect well" */ - for (timeout = 0; timeout < 100 ; timeout++) { + timeout = (quick == 2) ? 0 : 100; + t = 0; + while (1) { if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status)) return (0); - if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 || - (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2) + if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) && + ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) && + ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE)) + break; + if (++t > timeout) break; ata_udelay(10000); } - if (timeout >= 100) { - if (bootverbose) { + if (bootverbose) { + if (t > timeout) { if (port < 0) { device_printf(ch->dev, "SATA connect timeout status=%08x\n", status); @@ -143,23 +128,19 @@ ata_sata_connect(struct ata_channel *ch, int port) device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n", port, status); } - } - return 0; - } - if (bootverbose) { - if (port < 0) { + } else if (port < 0) { device_printf(ch->dev, "SATA connect time=%dms status=%08x\n", - timeout * 10, status); + t * 10, status); } else { device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n", - port, timeout * 10, status); + port, t * 10, status); } } /* clear SATA error register */ ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff); - return 1; + return ((t > timeout) ? 0 : 1); } int @@ -173,7 +154,7 @@ ata_sata_phy_reset(device_t dev, int port, int quick) if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) - return ata_sata_connect(ch, port); + return ata_sata_connect(ch, port, quick); } if (bootverbose) { @@ -203,7 +184,7 @@ ata_sata_phy_reset(device_t dev, int port, int quick) if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val)) return (0); if ((val & ATA_SC_DET_MASK) == 0) - return ata_sata_connect(ch, port); + return ata_sata_connect(ch, port, 0); } } return 0; diff --git a/sys/dev/ata/chipsets/ata-ahci.c b/sys/dev/ata/chipsets/ata-ahci.c index 6811c795c85..4a240d7e15a 100644 --- a/sys/dev/ata/chipsets/ata-ahci.c +++ b/sys/dev/ata/chipsets/ata-ahci.c @@ -403,7 +403,7 @@ ata_ahci_status(device_t dev) /* do we have any PHY events ? */ if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); /* do we have a potentially hanging engine to take care of? */ /* XXX SOS what todo on NCQ */ @@ -563,7 +563,7 @@ ata_ahci_end_transaction(struct ata_request *request) /* record how much data we actually moved */ clp = (struct ata_ahci_cmd_list *) (ch->dma.work + ATA_AHCI_CL_OFFSET); - request->donecount = clp->bytecount; + request->donecount = le32toh(clp->bytecount); /* release SG list etc */ ch->dma.unload(request); @@ -623,6 +623,25 @@ ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result) (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; + if (port < 0) { + *result = ATA_IDX_INL(ch, reg); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ @@ -649,6 +668,25 @@ ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value) (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); int offset = ch->unit << 7; + if (port < 0) { + ATA_IDX_OUTL(ch, reg, value); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ @@ -815,7 +853,7 @@ ata_ahci_hardreset(device_t dev, int port, uint32_t *signature) if (!ata_sata_phy_reset(dev, port, 0)) return (ENOENT); /* Wait for clearing busy status. */ - if (ata_ahci_wait_ready(dev, 10000)) { + if (ata_ahci_wait_ready(dev, 15000)) { device_printf(dev, "hardware reset timeout\n"); return (EBUSY); } diff --git a/sys/dev/ata/chipsets/ata-intel.c b/sys/dev/ata/chipsets/ata-intel.c index 0638b39c907..ba602aaa5ea 100644 --- a/sys/dev/ata/chipsets/ata-intel.c +++ b/sys/dev/ata/chipsets/ata-intel.c @@ -59,6 +59,15 @@ static int ata_intel_old_setmode(device_t dev, int target, int mode); static int ata_intel_new_setmode(device_t dev, int target, int mode); static int ata_intel_sch_setmode(device_t dev, int target, int mode); static int ata_intel_sata_getrev(device_t dev, int target); +static int ata_intel_sata_status(device_t dev); +static int ata_intel_sata_cscr_read(device_t dev, int port, + int reg, u_int32_t *result); +static int ata_intel_sata_sidpr_read(device_t dev, int port, + int reg, u_int32_t *result); +static int ata_intel_sata_cscr_write(device_t dev, int port, + int reg, u_int32_t result); +static int ata_intel_sata_sidpr_write(device_t dev, int port, + int reg, u_int32_t result); static int ata_intel_31244_ch_attach(device_t dev); static int ata_intel_31244_ch_detach(device_t dev); static int ata_intel_31244_status(device_t dev); @@ -67,7 +76,9 @@ static void ata_intel_31244_reset(device_t dev); /* misc defines */ #define INTEL_AHCI 1 - +#define INTEL_ICH5 2 +#define INTEL_6CH 4 +#define INTEL_6CH2 8 /* * Intel chipset support functions @@ -92,70 +103,74 @@ ata_intel_probe(device_t dev) { ATA_I82801DB, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801DB_1, 0, 0, 2, ATA_UDMA5, "ICH4" }, { ATA_I82801EB, 0, 0, 2, ATA_UDMA5, "ICH5" }, - { ATA_I82801EB_S1, 0, 0, 2, ATA_SA150, "ICH5" }, - { ATA_I82801EB_R1, 0, 0, 2, ATA_SA150, "ICH5" }, + { ATA_I82801EB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "ICH5" }, + { ATA_I82801EB_R1, 0, INTEL_ICH5, 2, ATA_SA150, "ICH5" }, { ATA_I6300ESB, 0, 0, 2, ATA_UDMA5, "6300ESB" }, - { ATA_I6300ESB_S1, 0, 0, 2, ATA_SA150, "6300ESB" }, - { ATA_I6300ESB_R1, 0, 0, 2, ATA_SA150, "6300ESB" }, + { ATA_I6300ESB_S1, 0, INTEL_ICH5, 2, ATA_SA150, "6300ESB" }, + { ATA_I6300ESB_R1, 0, INTEL_ICH5, 2, ATA_SA150, "6300ESB" }, { ATA_I82801FB, 0, 0, 2, ATA_UDMA5, "ICH6" }, { ATA_I82801FB_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FB_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6" }, { ATA_I82801FBM, 0, INTEL_AHCI, 0, ATA_SA150, "ICH6M" }, { ATA_I82801GB, 0, 0, 1, ATA_UDMA5, "ICH7" }, - { ATA_I82801GB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, - { ATA_I82801GB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, + { ATA_I82801GB_S1, 0, 0, 0, ATA_SA300, "ICH7" }, + { ATA_I82801GB_R1, 0, 0, 0, ATA_SA300, "ICH7" }, { ATA_I82801GB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH7" }, - { ATA_I82801GBM_S1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, - { ATA_I82801GBM_R1, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, + { ATA_I82801GBM_S1, 0, 0, 0, ATA_SA150, "ICH7M" }, + { ATA_I82801GBM_R1, 0, 0, 0, ATA_SA150, "ICH7M" }, { ATA_I82801GBM_AH, 0, INTEL_AHCI, 0, ATA_SA150, "ICH7M" }, { ATA_I63XXESB2, 0, 0, 1, ATA_UDMA5, "63XXESB2" }, - { ATA_I63XXESB2_S1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, + { ATA_I63XXESB2_S1, 0, 0, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_S2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R1, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, { ATA_I63XXESB2_R2, 0, INTEL_AHCI, 0, ATA_SA300, "63XXESB2" }, - { ATA_I82801HB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, - { ATA_I82801HB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, + { ATA_I82801HB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH8" }, + { ATA_I82801HB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8" }, { ATA_I82801HBM, 0, 0, 1, ATA_UDMA5, "ICH8M" }, - { ATA_I82801HBM_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, + { ATA_I82801HBM_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, { ATA_I82801HBM_S3, 0, INTEL_AHCI, 0, ATA_SA300, "ICH8M" }, - { ATA_I82801IB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, - { ATA_I82801IB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, + { ATA_I82801IB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH9" }, + { ATA_I82801IB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_AH6, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, { ATA_I82801IB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH9" }, - { ATA_I82801JIB_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, + { ATA_I82801JIB_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JIB_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { ATA_I82801JIB_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { ATA_I82801JD_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, + { ATA_I82801JIB_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, + { ATA_I82801JD_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JD_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { ATA_I82801JD_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { ATA_I82801JI_S1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, + { ATA_I82801JD_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, + { ATA_I82801JI_S1, 0, INTEL_6CH, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_AH, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, { ATA_I82801JI_R1, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { ATA_I82801JI_S2, 0, INTEL_AHCI, 0, ATA_SA300, "ICH10" }, - { 0x3b208086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b218086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b228086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b238086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b248086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b258086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b268086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b278086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b288086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b298086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2a8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2b8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2c8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2d8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2e8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, - { 0x3b2f8086, 0, INTEL_AHCI, 0, ATA_SA300, "PCH" }, + { ATA_I82801JI_S2, 0, INTEL_6CH2, 0, ATA_SA300, "ICH10" }, + { ATA_5Series_S1, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_S2, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_R1, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_S3, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_S4, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_AH3, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_R2, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_S5, 0, INTEL_6CH2, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_S6, 0, INTEL_6CH, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_5Series_AH4, 0, INTEL_AHCI, 0, ATA_SA300, "5 Series/3400 Series PCH" }, + { ATA_CPT_S1, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_S2, 0, INTEL_6CH, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_AH1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_AH2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_R1, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_R2, 0, INTEL_AHCI, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_S3, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" }, + { ATA_CPT_S4, 0, INTEL_6CH2, 0, ATA_SA300, "Cougar Point" }, { ATA_I31244, 0, 0, 2, ATA_SA150, "31244" }, { ATA_ISCH, 0, 0, 1, ATA_UDMA5, "SCH" }, { 0, 0, 0, 0, 0, 0}}; @@ -179,6 +194,8 @@ ata_intel_chipinit(device_t dev) if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; + ctlr->chipset_data = NULL; + /* good old PIIX needs special treatment (not implemented) */ if (ctlr->chip->chipid == ATA_I82371FB) { ctlr->setmode = ata_intel_old_setmode; @@ -229,7 +246,7 @@ ata_intel_chipinit(device_t dev) * if we have AHCI capability and AHCI or RAID mode enabled * in BIOS we try for AHCI mode */ - if ((ctlr->chip->cfg1 == INTEL_AHCI) && + if ((ctlr->chip->cfg1 & INTEL_AHCI) && (pci_read_config(dev, 0x90, 1) & 0xc0) && (ata_ahci_chipinit(dev) != ENXIO)) return 0; @@ -238,7 +255,8 @@ ata_intel_chipinit(device_t dev) ctlr->r_type2 = SYS_RES_IOPORT; ctlr->r_rid2 = PCIR_BAR(5); if ((ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, - &ctlr->r_rid2, RF_ACTIVE))) + &ctlr->r_rid2, RF_ACTIVE)) + || (ctlr->chip->cfg1 & INTEL_ICH5)) ctlr->getrev = ata_intel_sata_getrev; ctlr->setmode = ata_sata_setmode; } @@ -248,63 +266,142 @@ ata_intel_chipinit(device_t dev) static int ata_intel_ch_attach(device_t dev) { - struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); - struct ata_channel *ch = device_get_softc(dev); + struct ata_pci_controller *ctlr; + struct ata_channel *ch; + u_char *smap; + u_int map; - /* setup the usual register normal pci style */ - if (ata_pci_ch_attach(dev)) - return ENXIO; + /* setup the usual register normal pci style */ + if (ata_pci_ch_attach(dev)) + return (ENXIO); - /* if r_res2 is valid it points to SATA interface registers */ - if (ctlr->r_res2) { - ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; - ch->r_io[ATA_IDX_ADDR].offset = 0x00; - ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2; - ch->r_io[ATA_IDX_DATA].offset = 0x04; - } + ctlr = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); - ch->flags |= ATA_ALWAYS_DMASTAT; - if (ctlr->chip->max_dma >= ATA_SA150) { - if (ctlr->chip->cfg1 == 0 && - (pci_read_config(device_get_parent(dev), 0x90, 1) & 0x04) == 0) - ch->flags |= ATA_NO_SLAVE; - ch->flags |= ATA_SATA; - } else if (ctlr->chip->chipid != ATA_ISCH) - ch->flags |= ATA_CHECKS_CABLE; - return 0; + /* if r_res2 is valid it points to SATA interface registers */ + if (ctlr->r_res2) { + ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; + ch->r_io[ATA_IDX_ADDR].offset = 0x00; + ch->r_io[ATA_IDX_DATA].res = ctlr->r_res2; + ch->r_io[ATA_IDX_DATA].offset = 0x04; + } + + ch->flags |= ATA_ALWAYS_DMASTAT; + if (ctlr->chip->max_dma >= ATA_SA150) { + smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + map = pci_read_config(device_get_parent(dev), 0x90, 1); + if (ctlr->chip->cfg1 & INTEL_ICH5) { + map &= 0x07; + if ((map & 0x04) == 0) { + ch->flags |= ATA_SATA; + ch->flags |= ATA_NO_SLAVE; + smap[0] = (map & 0x01) ^ ch->unit; + smap[1] = 0; + } else if ((map & 0x02) == 0 && ch->unit == 0) { + ch->flags |= ATA_SATA; + smap[0] = (map & 0x01) ? 1 : 0; + smap[1] = (map & 0x01) ? 0 : 1; + } else if ((map & 0x02) != 0 && ch->unit == 1) { + ch->flags |= ATA_SATA; + smap[0] = (map & 0x01) ? 1 : 0; + smap[1] = (map & 0x01) ? 0 : 1; + } + } else if (ctlr->chip->cfg1 & INTEL_6CH2) { + ch->flags |= ATA_SATA; + ch->flags |= ATA_NO_SLAVE; + smap[0] = (ch->unit == 0) ? 4 : 5; + smap[1] = 0; + } else { + map &= 0x03; + if (map == 0x00) { + ch->flags |= ATA_SATA; + smap[ch->unit] = (ch->unit == 0) ? 0x20 : 0x31; + smap[0] = (ch->unit == 0) ? 0 : 1; + smap[1] = (ch->unit == 0) ? 2 : 3; + } else if (map == 0x02 && ch->unit == 0) { + ch->flags |= ATA_SATA; + smap[0] = 0; + smap[1] = 2; + } else if (map == 0x01 && ch->unit == 1) { + ch->flags |= ATA_SATA; + smap[0] = 1; + smap[1] = 3; + } + } + if (ch->flags & ATA_SATA) { + if ((ctlr->chip->cfg1 & INTEL_ICH5)) { + ch->flags |= ATA_PERIODIC_POLL; + ch->hw.status = ata_intel_sata_status; + ch->hw.pm_read = ata_intel_sata_cscr_read; + ch->hw.pm_write = ata_intel_sata_cscr_write; + } else if (ctlr->r_res2) { + ch->flags |= ATA_PERIODIC_POLL; + ch->hw.status = ata_intel_sata_status; + ch->hw.pm_read = ata_intel_sata_sidpr_read; + ch->hw.pm_write = ata_intel_sata_sidpr_write; + } + if (ch->hw.pm_write != NULL) { + ata_sata_scr_write(ch, 0, + ATA_SERROR, 0xffffffff); + if ((ch->flags & ATA_NO_SLAVE) == 0) { + ata_sata_scr_write(ch, 1, + ATA_SERROR, 0xffffffff); + } + } + } else + ctlr->setmode = ata_intel_new_setmode; + } else if (ctlr->chip->chipid != ATA_ISCH) + ch->flags |= ATA_CHECKS_CABLE; + return (0); } static void ata_intel_reset(device_t dev) { - device_t parent = device_get_parent(dev); - struct ata_pci_controller *ctlr = device_get_softc(parent); - struct ata_channel *ch = device_get_softc(dev); - int mask, timeout; + device_t parent = device_get_parent(dev); + struct ata_pci_controller *ctlr = device_get_softc(parent); + struct ata_channel *ch = device_get_softc(dev); + int mask, pmask, timeout, devs; + u_char *smap; - /* ICH6 & ICH7 in compat mode has 4 SATA ports as master/slave on 2 ch's */ - if (ctlr->chip->cfg1) { - mask = (0x0005 << ch->unit); - } - else { - /* ICH5 in compat mode has SATA ports as master/slave on 1 channel */ - if (pci_read_config(parent, 0x90, 1) & 0x04) - mask = 0x0003; + /* In combined mode, skip SATA stuff for PATA channel. */ + if ((ch->flags & ATA_SATA) == 0) + return (ata_generic_reset(dev)); + + /* Do hard-reset on respective SATA ports. */ + smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + mask = 1 << smap[0]; + if ((ch->flags & ATA_NO_SLAVE) == 0) + mask |= (1 << smap[1]); + pci_write_config(parent, 0x92, + pci_read_config(parent, 0x92, 2) & ~mask, 2); + DELAY(10); + pci_write_config(parent, 0x92, + pci_read_config(parent, 0x92, 2) | mask, 2); + + /* Wait up to 1 sec for "connect well". */ + if (ctlr->chip->cfg1 & (INTEL_6CH | INTEL_6CH2)) + pmask = mask << 8; else - mask = (0x0001 << ch->unit); - } - pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) & ~mask, 2); - DELAY(10); - pci_write_config(parent, 0x92, pci_read_config(parent, 0x92, 2) | mask, 2); + pmask = mask << 4; + for (timeout = 0; timeout < 100 ; timeout++) { + if (((pci_read_config(parent, 0x92, 2) & pmask) == pmask) && + (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) + break; + ata_udelay(10000); + } - /* wait up to 1 sec for "connect well" */ - for (timeout = 0; timeout < 100 ; timeout++) { - if (((pci_read_config(parent, 0x92, 2) & (mask << 4)) == (mask << 4)) && - (ATA_IDX_INB(ch, ATA_STATUS) != 0xff)) - break; - ata_udelay(10000); - } - ata_generic_reset(dev); + /* If any device found, do soft-reset. */ + if (ch->hw.pm_read != NULL) { + devs = ata_sata_phy_reset(dev, 0, 2); + if ((ch->flags & ATA_NO_SLAVE) == 0) + devs += ata_sata_phy_reset(dev, 1, 2); + } else + devs = 1; + if (devs) + ata_generic_reset(dev); + else + ch->devices = 0; } static int @@ -335,6 +432,10 @@ ata_intel_new_setmode(device_t dev, int target, int mode) u_int8_t timings[] = { 0x00, 0x00, 0x10, 0x21, 0x23, 0x00, 0x21, 0x23 }; u_int8_t utimings[] = { 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02 }; + /* In combined mode, skip PATA stuff for SATA channel. */ + if (ch->flags & ATA_SATA) + return (ata_sata_setmode(dev, target, mode)); + mode = min(mode, ctlr->chip->max_dma); if (ata_dma_check_80pin && mode > ATA_UDMA2 && !(reg54 & (0x10 << devno))) { @@ -417,12 +518,145 @@ static int ata_intel_sata_getrev(device_t dev, int target) { struct ata_channel *ch = device_get_softc(dev); - int devno = (ch->unit << 1) + target; + uint32_t status; - /* set ATA_SSTATUS register offset */ - ATA_IDX_OUTL(ch, ATA_IDX_ADDR, devno * 0x100); - /* query SATA STATUS for the speed */ - return ((ATA_IDX_INL(ch, ATA_IDX_DATA) & 0x0f0) >> 4); + if (ata_sata_scr_read(ch, target, ATA_SSTATUS, &status) == 0) + return ((status & 0x0f0) >> 4); + return (0xff); +} + +static int +ata_intel_sata_status(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ata_sata_phy_check_events(dev, 0); + if ((ch->flags & ATA_NO_SLAVE) == 0) + ata_sata_phy_check_events(dev, 1); + + return ata_pci_status(dev); +} + +static int +ata_intel_sata_cscr_read(device_t dev, int port, int reg, u_int32_t *result) +{ + struct ata_pci_controller *ctlr; + struct ata_channel *ch; + device_t parent; + u_char *smap; + + parent = device_get_parent(dev); + ctlr = device_get_softc(parent); + ch = device_get_softc(dev); + smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + port = (port == 1) ? 1 : 0; + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + pci_write_config(parent, 0xa0, + 0x50 + smap[port] * 0x10 + reg * 4, 4); + *result = pci_read_config(parent, 0xa4, 4); + return (0); +} + +static int +ata_intel_sata_sidpr_read(device_t dev, int port, int reg, u_int32_t *result) +{ + struct ata_pci_controller *ctlr; + struct ata_channel *ch; + device_t parent; + + parent = device_get_parent(dev); + ctlr = device_get_softc(parent); + ch = device_get_softc(dev); + port = (port == 1) ? 1 : 0; + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SCONTROL: + reg = 1; + break; + case ATA_SERROR: + reg = 2; + break; + default: + return (EINVAL); + } + ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); + *result = ATA_IDX_INL(ch, ATA_IDX_DATA); + return (0); +} + +static int +ata_intel_sata_cscr_write(device_t dev, int port, int reg, u_int32_t value) +{ + struct ata_pci_controller *ctlr; + struct ata_channel *ch; + device_t parent; + u_char *smap; + + parent = device_get_parent(dev); + ctlr = device_get_softc(parent); + ch = device_get_softc(dev); + smap = (u_char *)&ctlr->chipset_data + ch->unit * 2; + port = (port == 1) ? 1 : 0; + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + pci_write_config(parent, 0xa0, + 0x50 + smap[port] * 0x10 + reg * 4, 4); + pci_write_config(parent, 0xa4, value, 4); + return (0); +} + +static int +ata_intel_sata_sidpr_write(device_t dev, int port, int reg, u_int32_t value) +{ + struct ata_pci_controller *ctlr; + struct ata_channel *ch; + device_t parent; + + parent = device_get_parent(dev); + ctlr = device_get_softc(parent); + ch = device_get_softc(dev); + port = (port == 1) ? 1 : 0; + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SCONTROL: + reg = 1; + break; + case ATA_SERROR: + reg = 2; + break; + default: + return (EINVAL); + } + ATA_IDX_OUTL(ch, ATA_IDX_ADDR, ((ch->unit * 2 + port) << 8) + reg); + ATA_IDX_OUTL(ch, ATA_IDX_DATA, value); + return (0); } static int @@ -488,7 +722,7 @@ static int ata_intel_31244_status(device_t dev) { /* do we have any PHY events ? */ - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); /* any drive action to take care of ? */ return ata_pci_status(dev); diff --git a/sys/dev/ata/chipsets/ata-marvell.c b/sys/dev/ata/chipsets/ata-marvell.c index 371d951fc85..eb6414e8cf8 100644 --- a/sys/dev/ata/chipsets/ata-marvell.c +++ b/sys/dev/ata/chipsets/ata-marvell.c @@ -374,7 +374,7 @@ ata_marvell_edma_status(device_t dev) ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0); /* do we have any PHY events ? */ - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); } /* do we have any device action ? */ diff --git a/sys/dev/ata/chipsets/ata-nvidia.c b/sys/dev/ata/chipsets/ata-nvidia.c index 344e5a44655..b1da6f0eccc 100644 --- a/sys/dev/ata/chipsets/ata-nvidia.c +++ b/sys/dev/ata/chipsets/ata-nvidia.c @@ -281,7 +281,7 @@ ata_nvidia_status(device_t dev) /* do we have any PHY events ? */ if (istatus & (0x0c << shift)) - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); /* clear interrupt(s) */ if (ctlr->chip->cfg1 & NVQ) diff --git a/sys/dev/ata/chipsets/ata-promise.c b/sys/dev/ata/chipsets/ata-promise.c index 8a7bceb0761..622352bf445 100644 --- a/sys/dev/ata/chipsets/ata-promise.c +++ b/sys/dev/ata/chipsets/ata-promise.c @@ -830,6 +830,25 @@ ata_promise_mio_pm_read(device_t dev, int port, int reg, u_int32_t *result) struct ata_channel *ch = device_get_softc(dev); int timeout = 0; + if (port < 0) { + *result = ATA_IDX_INL(ch, reg); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } /* set portmultiplier port */ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); @@ -862,6 +881,25 @@ ata_promise_mio_pm_write(device_t dev, int port, int reg, u_int32_t value) struct ata_channel *ch = device_get_softc(dev); int timeout = 0; + if (port < 0) { + ATA_IDX_OUTL(ch, reg, value); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } /* set portmultiplier port */ ATA_OUTB(ctlr->r_res2, 0x4e8 + (ch->unit << 8), 0x0f); diff --git a/sys/dev/ata/chipsets/ata-serverworks.c b/sys/dev/ata/chipsets/ata-serverworks.c index cd6db3d28d7..1771dc42b35 100644 --- a/sys/dev/ata/chipsets/ata-serverworks.c +++ b/sys/dev/ata/chipsets/ata-serverworks.c @@ -58,9 +58,8 @@ static int ata_serverworks_ch_detach(device_t dev); static void ata_serverworks_tf_read(struct ata_request *request); static void ata_serverworks_tf_write(struct ata_request *request); static int ata_serverworks_setmode(device_t dev, int target, int mode); -#ifdef __powerpc__ +static void ata_serverworks_sata_reset(device_t dev); static int ata_serverworks_status(device_t dev); -#endif /* misc defines */ #define SWKS_33 0 @@ -101,7 +100,6 @@ ata_serverworks_probe(device_t dev) return (BUS_PROBE_DEFAULT); } -#ifdef __powerpc__ static int ata_serverworks_status(device_t dev) { @@ -123,7 +121,6 @@ ata_serverworks_status(device_t dev) return ata_pci_status(dev); } -#endif static int ata_serverworks_chipinit(device_t dev) @@ -145,6 +142,7 @@ ata_serverworks_chipinit(device_t dev) ctlr->ch_detach = ata_serverworks_ch_detach; ctlr->setmode = ata_sata_setmode; ctlr->getrev = ata_sata_getrev; + ctlr->reset = ata_serverworks_sata_reset; return 0; } else if (ctlr->chip->cfg1 == SWKS_33) { @@ -210,30 +208,20 @@ ata_serverworks_ch_attach(device_t dev) ch->r_io[ATA_SERROR].offset = ch_offset + 0x44; ch->r_io[ATA_SCONTROL].offset = ch_offset + 0x48; - ch->flags |= ATA_NO_SLAVE; - ch->flags |= ATA_SATA; + ch->flags |= ATA_NO_SLAVE | ATA_SATA | ATA_KNOWN_PRESENCE; ata_pci_hw(dev); ch->hw.tf_read = ata_serverworks_tf_read; ch->hw.tf_write = ata_serverworks_tf_write; -#ifdef __powerpc__ - ch->hw.status = ata_serverworks_status; -#endif if (ctlr->chip->chipid == ATA_K2) { /* - * The revision 1 K2 SATA controller has interesting bugs. Patch them. - * These magic numbers regulate interrupt delivery in the first few - * cases and are pure magic in the last case. - * - * Values obtained from the Darwin driver. + * Set SICR registers to turn off waiting for a status message + * before sending FIS. Values obtained from the Darwin driver. */ - ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, 0x04); - ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff); - ATA_IDX_OUTL(ch, ATA_SCONTROL, 0x00000300); - ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0); ATA_OUTL(ctlr->r_res2, ch_offset + 0x80, ATA_INL(ctlr->r_res2, ch_offset + 0x80) & ~0x00040000); + ATA_OUTL(ctlr->r_res2, ch_offset + 0x88, 0); /* * Some controllers have a bug where they will send the command @@ -244,6 +232,14 @@ ata_serverworks_ch_attach(device_t dev) */ ch->flags |= ATA_DMA_BEFORE_CMD; + + /* + * The status register must be read as a long to fill the other + * registers. + */ + + ch->hw.status = ata_serverworks_status; + ch->flags |= ATA_STATUS_IS_LONG; } /* chip does not reliably do 64K DMA transfers */ @@ -404,4 +400,15 @@ ata_serverworks_setmode(device_t dev, int target, int mode) return (mode); } +static void +ata_serverworks_sata_reset(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + if (ata_sata_phy_reset(dev, -1, 1)) + ata_generic_reset(dev); + else + ch->devices = 0; +} + ATA_DECLARE_DRIVER(ata_serverworks); diff --git a/sys/dev/ata/chipsets/ata-siliconimage.c b/sys/dev/ata/chipsets/ata-siliconimage.c index 31d1878a110..fa7619c75b3 100644 --- a/sys/dev/ata/chipsets/ata-siliconimage.c +++ b/sys/dev/ata/chipsets/ata-siliconimage.c @@ -316,6 +316,7 @@ ata_sii_ch_attach(device_t dev) ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8); ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_SATA; + ch->flags |= ATA_KNOWN_PRESENCE; /* enable PHY state change interrupt */ ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); @@ -353,7 +354,7 @@ ata_sii_status(device_t dev) /* do we have any PHY events ? */ if (ctlr->chip->max_dma >= ATA_SA150 && (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010)) - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800) return ata_pci_status(dev); @@ -364,7 +365,15 @@ ata_sii_status(device_t dev) static void ata_sii_reset(device_t dev) { + struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); + int offset = ((ch->unit & 1) << 7) + ((ch->unit & 2) << 8); + uint32_t val; + + /* Apply R_ERR on DMA activate FIS errata workaround. */ + val = ATA_INL(ctlr->r_res2, 0x14c + offset); + if ((val & 0x3) == 0x1) + ATA_OUTL(ctlr->r_res2, 0x14c + offset, val & ~0x3); if (ata_sata_phy_reset(dev, -1, 1)) ata_generic_reset(dev); @@ -501,7 +510,7 @@ ata_siiprb_status(device_t dev) u_int32_t istatus = ATA_INL(ctlr->r_res2, 0x1008 + offset); /* do we have any PHY events ? */ - ata_sata_phy_check_events(dev); + ata_sata_phy_check_events(dev, -1); /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res2, 0x1008 + offset, istatus); @@ -640,7 +649,7 @@ ata_siiprb_end_transaction(struct ata_request *request) /* update progress */ if (!(request->status & ATA_S_ERROR) && !(request->flags & ATA_R_TIMEOUT)) { if (request->flags & ATA_R_READ) - request->donecount = prb->transfer_count; + request->donecount = le32toh(prb->transfer_count); else request->donecount = request->bytecount; } @@ -691,6 +700,25 @@ ata_siiprb_pm_read(device_t dev, int port, int reg, u_int32_t *result) struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; int offset = ch->unit * 0x2000; + if (port < 0) { + *result = ATA_IDX_INL(ch, reg); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } bzero(prb, sizeof(struct ata_siiprb_command)); prb->fis[0] = 0x27; /* host to device */ prb->fis[1] = 0x8f; /* command FIS to PM port */ @@ -715,6 +743,25 @@ ata_siiprb_pm_write(device_t dev, int port, int reg, u_int32_t value) struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work; int offset = ch->unit * 0x2000; + if (port < 0) { + ATA_IDX_OUTL(ch, reg, value); + return (0); + } + if (port < ATA_PM) { + switch (reg) { + case ATA_SSTATUS: + reg = 0; + break; + case ATA_SERROR: + reg = 1; + break; + case ATA_SCONTROL: + reg = 2; + break; + default: + return (EINVAL); + } + } bzero(prb, sizeof(struct ata_siiprb_command)); prb->fis[0] = 0x27; /* host to device */ prb->fis[1] = 0x8f; /* command FIS to PM port */ diff --git a/sys/dev/ata/chipsets/ata-via.c b/sys/dev/ata/chipsets/ata-via.c index 8a65b6a699e..284a89280d0 100644 --- a/sys/dev/ata/chipsets/ata-via.c +++ b/sys/dev/ata/chipsets/ata-via.c @@ -56,6 +56,7 @@ static int ata_via_chipinit(device_t dev); static int ata_via_ch_attach(device_t dev); static int ata_via_ch_detach(device_t dev); static void ata_via_reset(device_t dev); +static int ata_via_status(device_t dev); static int ata_via_old_setmode(device_t dev, int target, int mode); static void ata_via_southbridge_fixup(device_t dev); static int ata_via_new_setmode(device_t dev, int target, int mode); @@ -249,11 +250,13 @@ ata_via_ch_attach(device_t dev) ch->r_io[ATA_SERROR].offset = 0x04 + (ch->unit << ctlr->chip->cfg1); ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = 0x08 + (ch->unit << ctlr->chip->cfg1); + ch->hw.status = ata_via_status; ch->flags |= ATA_NO_SLAVE; ch->flags |= ATA_SATA; + ch->flags |= ATA_PERIODIC_POLL; + + ata_sata_scr_write(ch, -1, ATA_SERROR, 0xffffffff); - /* XXX SOS PHY hotplug handling missing in VIA chip ?? */ - /* XXX SOS unknown how to enable PHY state change interrupt */ return 0; } @@ -298,6 +301,14 @@ ata_via_reset(device_t dev) } } +static int +ata_via_status(device_t dev) +{ + + ata_sata_phy_check_events(dev, -1); + return (ata_pci_status(dev)); +} + static int ata_via_new_setmode(device_t dev, int target, int mode) { @@ -352,8 +363,7 @@ ata_via_old_setmode(device_t dev, int target, int mode) piomode = mode; } /* Set WDMA/PIO timings */ - if (ctlr->chip->cfg1 != VIA133) - pci_write_config(parent, reg - 0x08,timings[ata_mode2idx(piomode)], 1); + pci_write_config(parent, reg - 0x08,timings[ata_mode2idx(piomode)], 1); return (mode); } diff --git a/sys/dev/atkbdc/atkbdc_isa.c b/sys/dev/atkbdc/atkbdc_isa.c index 10e172f4552..42bb67bd9c8 100644 --- a/sys/dev/atkbdc/atkbdc_isa.c +++ b/sys/dev/atkbdc/atkbdc_isa.c @@ -47,7 +47,7 @@ __FBSDID("$FreeBSD$"); static int atkbdc_isa_probe(device_t dev); static int atkbdc_isa_attach(device_t dev); -static device_t atkbdc_isa_add_child(device_t bus, int order, const char *name, +static device_t atkbdc_isa_add_child(device_t bus, u_int order, const char *name, int unit); static device_method_t atkbdc_isa_methods[] = { @@ -230,7 +230,7 @@ atkbdc_isa_attach(device_t dev) } static device_t -atkbdc_isa_add_child(device_t bus, int order, const char *name, int unit) +atkbdc_isa_add_child(device_t bus, u_int order, const char *name, int unit) { atkbdc_device_t *ivar; device_t child; diff --git a/sys/dev/atkbdc/psm.c b/sys/dev/atkbdc/psm.c index 30113bdad11..81d63f35bfc 100644 --- a/sys/dev/atkbdc/psm.c +++ b/sys/dev/atkbdc/psm.c @@ -143,11 +143,6 @@ __FBSDID("$FreeBSD$"); #define MOUSE_PS2PLUS_PACKET_TYPE(b) \ (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) -/* some macros */ -#define PSM_UNIT(dev) (dev2unit(dev) >> 1) -#define PSM_NBLOCKIO(dev) (dev2unit(dev) & 1) -#define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1)) - /* ring buffer */ typedef struct ringbuf { int count; /* # of valid elements in the buffer */ @@ -305,8 +300,6 @@ struct psm_softc { /* Driver status information */ struct sigio *async; /* Processes waiting for SIGIO */ }; static devclass_t psm_devclass; -#define PSM_SOFTC(unit) \ - ((struct psm_softc*)devclass_get_softc(psm_devclass, unit)) /* driver state flags (state) */ #define PSM_VALID 0x80 @@ -1457,10 +1450,10 @@ psmattach(device_t dev) } /* Done */ - sc->dev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, - "psm%d", unit); - sc->bdev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, - "bpsm%d", unit); + sc->dev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "psm%d", unit); + sc->dev->si_drv1 = sc; + sc->bdev = make_dev(&psm_cdevsw, 0, 0, 0, 0666, "bpsm%d", unit); + sc->bdev->si_drv1 = sc; if (!verbose) printf("psm%d: model %s, device ID %d\n", @@ -1504,14 +1497,13 @@ psmdetach(device_t dev) static int psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) { - int unit = PSM_UNIT(dev); struct psm_softc *sc; int command_byte; int err; int s; /* Get device data */ - sc = PSM_SOFTC(unit); + sc = dev->si_drv1; if ((sc == NULL) || (sc->state & PSM_VALID) == 0) { /* the device is no longer valid/functioning */ return (ENXIO); @@ -1521,7 +1513,7 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) if (sc->state & PSM_OPEN) return (EBUSY); - device_busy(devclass_get_device(psm_devclass, unit)); + device_busy(devclass_get_device(psm_devclass, sc->unit)); /* Initialize state */ sc->mode.level = sc->dflt_mode.level; @@ -1565,7 +1557,8 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) kbdc_lock(sc->kbdc, FALSE); splx(s); log(LOG_ERR, - "psm%d: unable to set the command byte (psmopen).\n", unit); + "psm%d: unable to set the command byte (psmopen).\n", + sc->unit); return (EIO); } /* @@ -1590,8 +1583,7 @@ psmopen(struct cdev *dev, int flag, int fmt, struct thread *td) static int psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) { - int unit = PSM_UNIT(dev); - struct psm_softc *sc = PSM_SOFTC(unit); + struct psm_softc *sc = dev->si_drv1; int stat[3]; int command_byte; int s; @@ -1615,7 +1607,8 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { log(LOG_ERR, - "psm%d: failed to disable the aux int (psmclose).\n", unit); + "psm%d: failed to disable the aux int (psmclose).\n", + sc->unit); /* CONTROLLER ERROR; * NOTE: we shall force our way through. Because the only * ill effect we shall see is that we may not be able @@ -1643,12 +1636,13 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) */ log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n", - unit); + sc->unit); } if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) log(LOG_DEBUG, - "psm%d: failed to get status (psmclose).\n", unit); + "psm%d: failed to get status (psmclose).\n", + sc->unit); } if (!set_controller_command_byte(sc->kbdc, @@ -1661,7 +1655,7 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) */ log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n", - unit); + sc->unit); } /* remove anything left in the output buffer */ @@ -1676,7 +1670,7 @@ psmclose(struct cdev *dev, int flag, int fmt, struct thread *td) /* close is almost always successful */ sc->state &= ~PSM_OPEN; kbdc_lock(sc->kbdc, FALSE); - device_unbusy(devclass_get_device(psm_devclass, unit)); + device_unbusy(devclass_get_device(psm_devclass, sc->unit)); return (0); } @@ -1745,7 +1739,7 @@ tame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status, static int psmread(struct cdev *dev, struct uio *uio, int flag) { - register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + struct psm_softc *sc = dev->si_drv1; u_char buf[PSM_SMALLBUFSIZE]; int error = 0; int s; @@ -1757,7 +1751,7 @@ psmread(struct cdev *dev, struct uio *uio, int flag) /* block until mouse activity occured */ s = spltty(); while (sc->queue.count <= 0) { - if (PSM_NBLOCKIO(dev)) { + if (dev != sc->bdev) { splx(s); return (EWOULDBLOCK); } @@ -1892,7 +1886,7 @@ unblock_mouse_data(struct psm_softc *sc, int c) static int psmwrite(struct cdev *dev, struct uio *uio, int flag) { - register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + struct psm_softc *sc = dev->si_drv1; u_char buf[PSM_SMALLBUFSIZE]; int error = 0, i, l; @@ -1925,7 +1919,7 @@ static int psmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { - struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + struct psm_softc *sc = dev->si_drv1; mousemode_t mode; mousestatus_t status; #if (defined(MOUSE_GETVARS)) @@ -3270,7 +3264,7 @@ psmsoftintr(void *arg) MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN }; - register struct psm_softc *sc = arg; + struct psm_softc *sc = arg; mousestatus_t ms; packetbuf_t *pb; int x, y, z, c, l, s; @@ -3519,7 +3513,7 @@ next: static int psmpoll(struct cdev *dev, int events, struct thread *td) { - struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); + struct psm_softc *sc = dev->si_drv1; int s; int revents = 0; diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index 8671142b03c..2d38b8ee4aa 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -343,6 +343,12 @@ static int bce_miibus_read_reg (device_t, int, int); static int bce_miibus_write_reg (device_t, int, int, int); static void bce_miibus_statchg (device_t); +#ifdef BCE_DEBUG +static int sysctl_nvram_dump(SYSCTL_HANDLER_ARGS); +#ifdef BCE_NVRAM_WRITE_SUPPORT +static int sysctl_nvram_write(SYSCTL_HANDLER_ARGS); +#endif +#endif /****************************************************************************/ /* BCE NVRAM Access Routines */ @@ -1134,12 +1140,13 @@ bce_attach(device_t dev) /* Handle any special PHY initialization for SerDes PHYs. */ bce_init_media(sc); - /* MII child bus by probing the PHY. */ - if (mii_phy_probe(dev, &sc->bce_miibus, bce_ifmedia_upd, - bce_ifmedia_sts)) { - BCE_PRINTF("%s(%d): No PHY found on child MII bus!\n", - __FILE__, __LINE__); - rc = ENXIO; + /* MII child bus by attaching the PHY. */ + rc = mii_attach(dev, &sc->bce_miibus, ifp, bce_ifmedia_upd, + bce_ifmedia_sts, BMSR_DEFCAPMASK, sc->bce_phy_addr, + MII_OFFSET_ANY, 0); + if (rc != 0) { + BCE_PRINTF("%s(%d): attaching PHYs failed\n", __FILE__, + __LINE__); goto bce_attach_fail; } @@ -6730,6 +6737,7 @@ bce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags) } /* Get the TCP header length in bytes (min 20) */ + ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); th = (struct tcphdr *)((caddr_t)ip + ip_hlen); tcp_hlen = (th->th_off << 2); @@ -6742,6 +6750,7 @@ bce_tso_setup(struct bce_softc *sc, struct mbuf **m_head, u16 *flags) } /* IP header length and checksum will be calc'd by hardware */ + ip = (struct ip *)(m->m_data + sizeof(struct ether_header)); ip_len = ip->ip_len; ip->ip_len = 0; ip->ip_sum = 0; @@ -8342,6 +8351,57 @@ bce_sysctl_phy_read(SYSCTL_HANDLER_ARGS) } +static int +sysctl_nvram_dump(SYSCTL_HANDLER_ARGS) +{ + struct bce_softc *sc = (struct bce_softc *)arg1; + int error, i; + + if (sc->nvram_buf == NULL) { + sc->nvram_buf = malloc(sc->bce_flash_size, + M_TEMP, M_ZERO | M_WAITOK); + } + if (sc->nvram_buf == NULL) { + return(ENOMEM); + } + if (req->oldlen == sc->bce_flash_size) { + for (i = 0; i < sc->bce_flash_size; i++) { + bce_nvram_read(sc, i, &sc->nvram_buf[i], 1); + } + } + + error = SYSCTL_OUT(req, sc->nvram_buf, sc->bce_flash_size); + + return error; +} + +#ifdef BCE_NVRAM_WRITE_SUPPORT +static int +sysctl_nvram_write(SYSCTL_HANDLER_ARGS) +{ + struct bce_softc *sc = (struct bce_softc *)arg1; + int error; + + if (sc->nvram_buf == NULL) { + sc->nvram_buf = malloc(sc->bce_flash_size, + M_TEMP, M_ZERO | M_WAITOK); + } + if (sc->nvram_buf == NULL) { + return(ENOMEM); + } + bzero(sc->nvram_buf, sc->bce_flash_size); + error = SYSCTL_IN(req, sc->nvram_buf, sc->bce_flash_size); + + if (req->newlen == sc->bce_flash_size) { + bce_nvram_write(sc, 0, sc->nvram_buf , sc->bce_flash_size); + } + + + return error; +} +#endif + + /****************************************************************************/ /* Provides a sysctl interface to allow reading a CID. */ /* */ @@ -8566,6 +8626,16 @@ bce_add_sysctls(struct bce_softc *sc) "interrupts_tx", CTLFLAG_RD, &sc->interrupts_tx, 0, "Number of TX interrupts"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "nvram_dump", CTLTYPE_OPAQUE | CTLFLAG_RD, + (void *)sc, 0, + sysctl_nvram_dump, "S", ""); +#ifdef BCE_NVRAM_WRITE_SUPPORT + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "nvram_write", CTLTYPE_OPAQUE | CTLFLAG_WR, + (void *)sc, 0, + sysctl_nvram_write, "S", ""); +#endif #endif SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, diff --git a/sys/dev/bce/if_bcereg.h b/sys/dev/bce/if_bcereg.h index 2bb589fcc7a..cedb6b179fa 100644 --- a/sys/dev/bce/if_bcereg.h +++ b/sys/dev/bce/if_bcereg.h @@ -6790,6 +6790,7 @@ struct bce_softc /* Number of VLAN tagged frames stripped. */ u32 vlan_tagged_frames_stripped; #endif + uint8_t *nvram_buf; }; #endif /* __BCEREG_H_DEFINED */ diff --git a/sys/dev/bfe/if_bfe.c b/sys/dev/bfe/if_bfe.c index 00a2e97e5be..f384f6de9ee 100644 --- a/sys/dev/bfe/if_bfe.c +++ b/sys/dev/bfe/if_bfe.c @@ -505,10 +505,11 @@ bfe_attach(device_t dev) bfe_chip_reset(sc); BFE_UNLOCK(sc); - if (mii_phy_probe(dev, &sc->bfe_miibus, - bfe_ifmedia_upd, bfe_ifmedia_sts)) { - device_printf(dev, "MII without any PHY!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->bfe_miibus, ifp, bfe_ifmedia_upd, + bfe_ifmedia_sts, BMSR_DEFCAPMASK, sc->bfe_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -631,8 +632,6 @@ bfe_miibus_readreg(device_t dev, int phy, int reg) u_int32_t ret; sc = device_get_softc(dev); - if (phy != sc->bfe_phyaddr) - return (0); bfe_readphy(sc, reg, &ret); return (ret); @@ -644,8 +643,6 @@ bfe_miibus_writereg(device_t dev, int phy, int reg, int val) struct bfe_softc *sc; sc = device_get_softc(dev); - if (phy != sc->bfe_phyaddr) - return (0); bfe_writephy(sc, reg, val); return (0); diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index a473919189c..63c4c5dc5ae 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -120,7 +120,7 @@ __FBSDID("$FreeBSD$"); #include -#define BGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) +#define BGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP) #define ETHER_MIN_NOPAD (ETHER_MIN_LEN - ETHER_CRC_LEN) /* i.e., 60 */ MODULE_DEPEND(bge, pci, 1, 1, 1); @@ -355,8 +355,10 @@ static int bge_suspend(device_t); static int bge_resume(device_t); static void bge_release_resources(struct bge_softc *); static void bge_dma_map_addr(void *, bus_dma_segment_t *, int, int); -static int bge_dma_alloc(device_t); +static int bge_dma_alloc(struct bge_softc *); static void bge_dma_free(struct bge_softc *); +static int bge_dma_ring_alloc(struct bge_softc *, bus_size_t, bus_size_t, + bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *); static int bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[]); static int bge_get_eaddr_mem(struct bge_softc *, uint8_t[]); @@ -369,8 +371,10 @@ static int bge_rxeof(struct bge_softc *, uint16_t, int); static void bge_asf_driver_up (struct bge_softc *); static void bge_tick(void *); +static void bge_stats_clear_regs(struct bge_softc *); static void bge_stats_update(struct bge_softc *); static void bge_stats_update_regs(struct bge_softc *); +static struct mbuf *bge_check_short_dma(struct mbuf *); static struct mbuf *bge_setup_tso(struct bge_softc *, struct mbuf *, uint16_t *); static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *); @@ -451,6 +455,10 @@ static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS); static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS); #endif static void bge_add_sysctls(struct bge_softc *); +static void bge_add_sysctl_stats_regs(struct bge_softc *, + struct sysctl_ctx_list *, struct sysctl_oid_list *); +static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *, + struct sysctl_oid_list *); static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS); static device_method_t bge_methods[] = { @@ -543,6 +551,10 @@ bge_readmem_ind(struct bge_softc *sc, int off) device_t dev; uint32_t val; + if (sc->bge_asicrev == BGE_ASICREV_BCM5906 && + off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4) + return (0); + dev = sc->bge_dev; pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); @@ -556,6 +568,10 @@ bge_writemem_ind(struct bge_softc *sc, int off, int val) { device_t dev; + if (sc->bge_asicrev == BGE_ASICREV_BCM5906 && + off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4) + return; + dev = sc->bge_dev; pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); @@ -614,13 +630,9 @@ bge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) if (error) return; + KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg)); + ctx = arg; - - if (nseg > ctx->bge_maxsegs) { - ctx->bge_maxsegs = 0; - return; - } - ctx->bge_busaddr = segs->ds_addr; } @@ -765,38 +777,30 @@ static int bge_miibus_readreg(device_t dev, int phy, int reg) { struct bge_softc *sc; - uint32_t val, autopoll; + uint32_t val; int i; sc = device_get_softc(dev); - /* - * Broadcom's own driver always assumes the internal - * PHY is at GMII address 1. On some chips, the PHY responds - * to accesses at all addresses, which could cause us to - * bogusly attach the PHY 32 times at probe type. Always - * restricting the lookup to address 1 is simpler than - * trying to figure out which chips revisions should be - * special-cased. - */ - if (phy != 1) - return (0); - - /* Reading with autopolling on may trigger PCI errors */ - autopoll = CSR_READ_4(sc, BGE_MI_MODE); - if (autopoll & BGE_MIMODE_AUTOPOLL) { - BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); - DELAY(40); + /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ + if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { + CSR_WRITE_4(sc, BGE_MI_MODE, + sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL); + DELAY(80); } CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY | BGE_MIPHY(phy) | BGE_MIREG(reg)); + /* Poll for the PHY register access to complete. */ for (i = 0; i < BGE_TIMEOUT; i++) { DELAY(10); val = CSR_READ_4(sc, BGE_MI_COMM); - if (!(val & BGE_MICOMM_BUSY)) + if ((val & BGE_MICOMM_BUSY) == 0) { + DELAY(5); + val = CSR_READ_4(sc, BGE_MI_COMM); break; + } } if (i == BGE_TIMEOUT) { @@ -804,16 +808,12 @@ bge_miibus_readreg(device_t dev, int phy, int reg) "PHY read timed out (phy %d, reg %d, val 0x%08x)\n", phy, reg, val); val = 0; - goto done; } - DELAY(5); - val = CSR_READ_4(sc, BGE_MI_COMM); - -done: - if (autopoll & BGE_MIMODE_AUTOPOLL) { - BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); - DELAY(40); + /* Restore the autopoll bit if necessary. */ + if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { + CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode); + DELAY(80); } if (val & BGE_MICOMM_READFAIL) @@ -826,7 +826,6 @@ static int bge_miibus_writereg(device_t dev, int phy, int reg, int val) { struct bge_softc *sc; - uint32_t autopoll; int i; sc = device_get_softc(dev); @@ -835,11 +834,11 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val) (reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL)) return (0); - /* Reading with autopolling on may trigger PCI errors */ - autopoll = CSR_READ_4(sc, BGE_MI_MODE); - if (autopoll & BGE_MIMODE_AUTOPOLL) { - BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); - DELAY(40); + /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ + if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { + CSR_WRITE_4(sc, BGE_MI_MODE, + sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL); + DELAY(80); } CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY | @@ -854,17 +853,16 @@ bge_miibus_writereg(device_t dev, int phy, int reg, int val) } } - if (i == BGE_TIMEOUT) { + /* Restore the autopoll bit if necessary. */ + if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { + CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode); + DELAY(80); + } + + if (i == BGE_TIMEOUT) device_printf(sc->bge_dev, "PHY write timed out (phy %d, reg %d, val %d)\n", phy, reg, val); - return (0); - } - - if (autopoll & BGE_MIMODE_AUTOPOLL) { - BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); - DELAY(40); - } return (0); } @@ -877,6 +875,29 @@ bge_miibus_statchg(device_t dev) sc = device_get_softc(dev); mii = device_get_softc(sc->bge_miibus); + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: + sc->bge_link = 1; + break; + case IFM_1000_T: + case IFM_1000_SX: + case IFM_2500_SX: + if (sc->bge_asicrev != BGE_ASICREV_BCM5906) + sc->bge_link = 1; + else + sc->bge_link = 0; + break; + default: + sc->bge_link = 0; + break; + } + } else + sc->bge_link = 0; + if (sc->bge_link == 0) + return; BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_PORTMODE); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) @@ -884,10 +905,21 @@ bge_miibus_statchg(device_t dev) else BGE_SETBIT(sc, BGE_MAC_MODE, BGE_PORTMODE_MII); - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) + if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0) { BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); - else + if (IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG1) + BGE_SETBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE); + else + BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE); + if (IFM_OPTIONS(mii->mii_media_active) & IFM_FLAG0) + BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE); + else + BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE); + } else { BGE_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); + BGE_CLRBIT(sc, BGE_TX_MODE, BGE_TXMODE_FLOWCTL_ENABLE); + BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_FLOWCTL_ENABLE); + } } /* @@ -1038,7 +1070,7 @@ bge_init_rx_ring_std(struct bge_softc *sc) if ((error = bge_newbuf_std(sc, i)) != 0) return (error); BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT); - }; + } bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag, sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE); @@ -1081,16 +1113,17 @@ bge_init_rx_ring_jumbo(struct bge_softc *sc) if ((error = bge_newbuf_jumbo(sc, i)) != 0) return (error); BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT); - }; + } bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag, sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE); sc->bge_jumbo = 0; + /* Enable the jumbo receive producer ring. */ rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb; - rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0, - BGE_RCB_FLAG_USE_EXT_RX_BD); + rcb->bge_maxlen_flags = + BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_USE_EXT_RX_BD); CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, BGE_JUMBO_RX_RING_CNT - 1); @@ -1469,7 +1502,7 @@ bge_blockinit(struct bge_softc *sc) bus_size_t vrcb; bge_hostaddr taddr; uint32_t val; - int i; + int i, limit; /* * Initialize the memory window pointer register so that @@ -1549,7 +1582,38 @@ bge_blockinit(struct bge_softc *sc) return (ENXIO); } - /* Initialize the standard RX ring control block */ + /* + * Summary of rings supported by the controller: + * + * Standard Receive Producer Ring + * - This ring is used to feed receive buffers for "standard" + * sized frames (typically 1536 bytes) to the controller. + * + * Jumbo Receive Producer Ring + * - This ring is used to feed receive buffers for jumbo sized + * frames (i.e. anything bigger than the "standard" frames) + * to the controller. + * + * Mini Receive Producer Ring + * - This ring is used to feed receive buffers for "mini" + * sized frames to the controller. + * - This feature required external memory for the controller + * but was never used in a production system. Should always + * be disabled. + * + * Receive Return Ring + * - After the controller has placed an incoming frame into a + * receive buffer that buffer is moved into a receive return + * ring. The driver is then responsible to passing the + * buffer up to the stack. Many versions of the controller + * support multiple RR rings. + * + * Send Ring + * - This ring is used for outgoing frames. Many versions of + * the controller support multiple send rings. + */ + + /* Initialize the standard receive producer ring control block. */ rcb = &sc->bge_ldata.bge_info.bge_std_rx_rcb; rcb->bge_hostaddr.bge_addr_lo = BGE_ADDR_LO(sc->bge_ldata.bge_rx_std_ring_paddr); @@ -1557,28 +1621,45 @@ bge_blockinit(struct bge_softc *sc) BGE_ADDR_HI(sc->bge_ldata.bge_rx_std_ring_paddr); bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag, sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREREAD); - if (BGE_IS_5705_PLUS(sc)) + if (BGE_IS_5705_PLUS(sc)) { + /* + * Bits 31-16: Programmable ring size (512, 256, 128, 64, 32) + * Bits 15-2 : Reserved (should be 0) + * Bit 1 : 1 = Ring Disabled, 0 = Ring Enabled + * Bit 0 : Reserved + */ rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(512, 0); - else + } else { + /* + * Ring size is always XXX entries + * Bits 31-16: Maximum RX frame size + * Bits 15-2 : Reserved (should be 0) + * Bit 1 : 1 = Ring Disabled, 0 = Ring Enabled + * Bit 0 : Reserved + */ rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(BGE_MAX_FRAMELEN, 0); + } rcb->bge_nicaddr = BGE_STD_RX_RINGS; + /* Write the standard receive producer ring control block. */ CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_HI, rcb->bge_hostaddr.bge_addr_hi); CSR_WRITE_4(sc, BGE_RX_STD_RCB_HADDR_LO, rcb->bge_hostaddr.bge_addr_lo); - CSR_WRITE_4(sc, BGE_RX_STD_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); CSR_WRITE_4(sc, BGE_RX_STD_RCB_NICADDR, rcb->bge_nicaddr); + /* Reset the standard receive producer ring producer index. */ + bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0); + /* - * Initialize the jumbo RX ring control block - * We set the 'ring disabled' bit in the flags - * field until we're actually ready to start + * Initialize the jumbo RX producer ring control + * block. We set the 'ring disabled' bit in the + * flags field until we're actually ready to start * using this ring (i.e. once we set the MTU * high enough to require it). */ if (BGE_IS_JUMBO_CAPABLE(sc)) { rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb; - + /* Get the jumbo receive producer ring RCB parameters. */ rcb->bge_hostaddr.bge_addr_lo = BGE_ADDR_LO(sc->bge_ldata.bge_rx_jumbo_ring_paddr); rcb->bge_hostaddr.bge_addr_hi = @@ -1593,20 +1674,39 @@ bge_blockinit(struct bge_softc *sc) rcb->bge_hostaddr.bge_addr_hi); CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_HADDR_LO, rcb->bge_hostaddr.bge_addr_lo); - + /* Program the jumbo receive producer ring RCB parameters. */ CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_NICADDR, rcb->bge_nicaddr); + /* Reset the jumbo receive producer ring producer index. */ + bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0); + } - /* Set up dummy disabled mini ring RCB */ + /* Disable the mini receive producer ring RCB. */ + if (BGE_IS_5700_FAMILY(sc)) { rcb = &sc->bge_ldata.bge_info.bge_mini_rx_rcb; rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED); CSR_WRITE_4(sc, BGE_RX_MINI_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); + /* Reset the mini receive producer ring producer index. */ + bge_writembx(sc, BGE_MBX_RX_MINI_PROD_LO, 0); } + /* Choose de-pipeline mode for BCM5906 A0, A1 and A2. */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5906) { + if (sc->bge_chipid == BGE_CHIPID_BCM5906_A0 || + sc->bge_chipid == BGE_CHIPID_BCM5906_A1 || + sc->bge_chipid == BGE_CHIPID_BCM5906_A2) + CSR_WRITE_4(sc, BGE_ISO_PKT_TX, + (CSR_READ_4(sc, BGE_ISO_PKT_TX) & ~3) | 2); + } /* + * The BD ring replenish thresholds control how often the + * hardware fetches new BD's from the producer rings in host + * memory. Setting the value too low on a busy system can + * starve the hardware and recue the throughpout. + * * Set the BD ring replentish thresholds. The recommended * values are 1/8th the number of descriptors allocated to * each ring. @@ -1628,61 +1728,67 @@ bge_blockinit(struct bge_softc *sc) BGE_JUMBO_RX_RING_CNT/8); /* - * Disable all unused send rings by setting the 'ring disabled' - * bit in the flags field of all the TX send ring control blocks. - * These are located in NIC memory. + * Disable all send rings by setting the 'ring disabled' bit + * in the flags field of all the TX send ring control blocks, + * located in NIC memory. */ + if (!BGE_IS_5705_PLUS(sc)) + /* 5700 to 5704 had 16 send rings. */ + limit = BGE_TX_RINGS_EXTSSRAM_MAX; + else + limit = 1; vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; - for (i = 0; i < BGE_TX_RINGS_EXTSSRAM_MAX; i++) { + for (i = 0; i < limit; i++) { RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_RING_DISABLED)); RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0); vrcb += sizeof(struct bge_rcb); } - /* Configure TX RCB 0 (we use only the first ring) */ + /* Configure send ring RCB 0 (we use only the first ring) */ vrcb = BGE_MEMWIN_START + BGE_SEND_RING_RCB; BGE_HOSTADDR(taddr, sc->bge_ldata.bge_tx_ring_paddr); RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, taddr.bge_addr_hi); RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, taddr.bge_addr_lo); RCB_WRITE_4(sc, vrcb, bge_nicaddr, BGE_NIC_TXRING_ADDR(0, BGE_TX_RING_CNT)); - if (!(BGE_IS_5705_PLUS(sc))) - RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, - BGE_RCB_MAXLEN_FLAGS(BGE_TX_RING_CNT, 0)); + RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, + BGE_RCB_MAXLEN_FLAGS(BGE_TX_RING_CNT, 0)); - /* Disable all unused RX return rings */ + /* + * Disable all receive return rings by setting the + * 'ring diabled' bit in the flags field of all the receive + * return ring control blocks, located in NIC memory. + */ + if (!BGE_IS_5705_PLUS(sc)) + limit = BGE_RX_RINGS_MAX; + else if (sc->bge_asicrev == BGE_ASICREV_BCM5755) + limit = 4; + else + limit = 1; + /* Disable all receive return rings. */ vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; - for (i = 0; i < BGE_RX_RINGS_MAX; i++) { + for (i = 0; i < limit; i++) { RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, 0); RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, 0); RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, - BGE_RCB_MAXLEN_FLAGS(sc->bge_return_ring_cnt, - BGE_RCB_FLAG_RING_DISABLED)); + BGE_RCB_FLAG_RING_DISABLED); RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0); bge_writembx(sc, BGE_MBX_RX_CONS0_LO + (i * (sizeof(uint64_t))), 0); vrcb += sizeof(struct bge_rcb); } - /* Initialize RX ring indexes */ - bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, 0); - if (BGE_IS_JUMBO_CAPABLE(sc)) - bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, 0); - if (sc->bge_asicrev == BGE_ASICREV_BCM5700) - bge_writembx(sc, BGE_MBX_RX_MINI_PROD_LO, 0); - /* - * Set up RX return ring 0 - * Note that the NIC address for RX return rings is 0x00000000. - * The return rings live entirely within the host, so the - * nicaddr field in the RCB isn't used. + * Set up receive return ring 0. Note that the NIC address + * for RX return rings is 0x0. The return rings live entirely + * within the host, so the nicaddr field in the RCB isn't used. */ vrcb = BGE_MEMWIN_START + BGE_RX_RETURN_RING_RCB; BGE_HOSTADDR(taddr, sc->bge_ldata.bge_rx_return_ring_paddr); RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_hi, taddr.bge_addr_hi); RCB_WRITE_4(sc, vrcb, bge_hostaddr.bge_addr_lo, taddr.bge_addr_lo); - RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0x00000000); + RCB_WRITE_4(sc, vrcb, bge_nicaddr, 0); RCB_WRITE_4(sc, vrcb, bge_maxlen_flags, BGE_RCB_MAXLEN_FLAGS(sc->bge_return_ring_cnt, 0)); @@ -1820,6 +1926,10 @@ bge_blockinit(struct bge_softc *sc) if (BGE_IS_5755_PLUS(sc)) val |= BGE_WDMAMODE_STATUS_TAG_FIX; + /* Request larger DMA burst size to get better performance. */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5785) + val |= BGE_WDMAMODE_BURST_ALL_DATA; + /* Turn on write DMA state machine */ CSR_WRITE_4(sc, BGE_WDMA_MODE, val); DELAY(40); @@ -1840,6 +1950,19 @@ bge_blockinit(struct bge_softc *sc) sc->bge_asicrev == BGE_ASICREV_BCM57780) val |= BGE_RDMAMODE_TSO6_ENABLE; } + if (sc->bge_asicrev == BGE_ASICREV_BCM5761 || + sc->bge_asicrev == BGE_ASICREV_BCM5784 || + sc->bge_asicrev == BGE_ASICREV_BCM5785 || + sc->bge_asicrev == BGE_ASICREV_BCM57780) { + /* + * Enable fix for read DMA FIFO overruns. + * The fix is to limit the number of RX BDs + * the hardware would fetch at a fime. + */ + CSR_WRITE_4(sc, BGE_RDMA_RSRVCTRL, + CSR_READ_4(sc, BGE_RDMA_RSRVCTRL) | + BGE_RDMA_RSRVCTRL_FIFO_OFLW_FIX); + } CSR_WRITE_4(sc, BGE_RDMA_MODE, val); DELAY(40); @@ -1887,11 +2010,17 @@ bge_blockinit(struct bge_softc *sc) BGE_MACSTAT_LINK_CHANGED); CSR_WRITE_4(sc, BGE_MI_STS, 0); - /* Enable PHY auto polling (for MII/GMII only) */ + /* + * Enable attention when the link has changed state for + * devices that use auto polling. + */ if (sc->bge_flags & BGE_FLAG_TBI) { CSR_WRITE_4(sc, BGE_MI_STS, BGE_MISTS_LINK); } else { - BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL | (10 << 16)); + if (sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) { + CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode); + DELAY(80); + } if (sc->bge_asicrev == BGE_ASICREV_BCM5700 && sc->bge_chipid != BGE_CHIPID_BCM5700_B2) CSR_WRITE_4(sc, BGE_MAC_EVT_ENB, @@ -2122,27 +2251,84 @@ bge_dma_free(struct bge_softc *sc) if (sc->bge_cdata.bge_stats_tag) bus_dma_tag_destroy(sc->bge_cdata.bge_stats_tag); + if (sc->bge_cdata.bge_buffer_tag) + bus_dma_tag_destroy(sc->bge_cdata.bge_buffer_tag); + /* Destroy the parent tag. */ if (sc->bge_cdata.bge_parent_tag) bus_dma_tag_destroy(sc->bge_cdata.bge_parent_tag); } static int -bge_dma_alloc(device_t dev) +bge_dma_ring_alloc(struct bge_softc *sc, bus_size_t alignment, + bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, + bus_addr_t *paddr, const char *msg) { struct bge_dmamap_arg ctx; - struct bge_softc *sc; bus_addr_t lowaddr; - bus_size_t sbsz, txsegsz, txmaxsegsz; - int i, error; + bus_size_t ring_end; + int error; - sc = device_get_softc(dev); + lowaddr = BUS_SPACE_MAXADDR; +again: + error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, + alignment, 0, lowaddr, BUS_SPACE_MAXADDR, NULL, + NULL, maxsize, 1, maxsize, 0, NULL, NULL, tag); + if (error != 0) { + device_printf(sc->bge_dev, + "could not create %s dma tag\n", msg); + return (ENOMEM); + } + /* Allocate DMA'able memory for ring. */ + error = bus_dmamem_alloc(*tag, (void **)ring, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); + if (error != 0) { + device_printf(sc->bge_dev, + "could not allocate DMA'able memory for %s\n", msg); + return (ENOMEM); + } + /* Load the address of the ring. */ + ctx.bge_busaddr = 0; + error = bus_dmamap_load(*tag, *map, *ring, maxsize, bge_dma_map_addr, + &ctx, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->bge_dev, + "could not load DMA'able memory for %s\n", msg); + return (ENOMEM); + } + *paddr = ctx.bge_busaddr; + ring_end = *paddr + maxsize; + if ((sc->bge_flags & BGE_FLAG_4G_BNDRY_BUG) != 0 && + BGE_ADDR_HI(*paddr) != BGE_ADDR_HI(ring_end)) { + /* + * 4GB boundary crossed. Limit maximum allowable DMA + * address space to 32bit and try again. + */ + bus_dmamap_unload(*tag, *map); + bus_dmamem_free(*tag, *ring, *map); + bus_dma_tag_destroy(*tag); + if (bootverbose) + device_printf(sc->bge_dev, "4GB boundary crossed, " + "limit DMA address space to 32bit for %s\n", msg); + *ring = NULL; + *tag = NULL; + *map = NULL; + lowaddr = BUS_SPACE_MAXADDR_32BIT; + goto again; + } + return (0); +} + +static int +bge_dma_alloc(struct bge_softc *sc) +{ + bus_addr_t lowaddr; + bus_size_t boundary, sbsz, txsegsz, txmaxsegsz; + int i, error; lowaddr = BUS_SPACE_MAXADDR; if ((sc->bge_flags & BGE_FLAG_40BIT_BUG) != 0) lowaddr = BGE_DMA_MAXADDR; - if ((sc->bge_flags & BGE_FLAG_4G_BNDRY_BUG) != 0) - lowaddr = BUS_SPACE_MAXADDR_32BIT; /* * Allocate the parent bus DMA tag appropriate for PCI. */ @@ -2150,16 +2336,93 @@ bge_dma_alloc(device_t dev) 1, 0, lowaddr, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL, &sc->bge_cdata.bge_parent_tag); - if (error != 0) { device_printf(sc->bge_dev, "could not allocate parent dma tag\n"); return (ENOMEM); } + /* Create tag for standard RX ring. */ + error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_STD_RX_RING_SZ, + &sc->bge_cdata.bge_rx_std_ring_tag, + (uint8_t **)&sc->bge_ldata.bge_rx_std_ring, + &sc->bge_cdata.bge_rx_std_ring_map, + &sc->bge_ldata.bge_rx_std_ring_paddr, "RX ring"); + if (error) + return (error); + + /* Create tag for RX return ring. */ + error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_RX_RTN_RING_SZ(sc), + &sc->bge_cdata.bge_rx_return_ring_tag, + (uint8_t **)&sc->bge_ldata.bge_rx_return_ring, + &sc->bge_cdata.bge_rx_return_ring_map, + &sc->bge_ldata.bge_rx_return_ring_paddr, "RX return ring"); + if (error) + return (error); + + /* Create tag for TX ring. */ + error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_TX_RING_SZ, + &sc->bge_cdata.bge_tx_ring_tag, + (uint8_t **)&sc->bge_ldata.bge_tx_ring, + &sc->bge_cdata.bge_tx_ring_map, + &sc->bge_ldata.bge_tx_ring_paddr, "TX ring"); + if (error) + return (error); + /* - * Create tag for Tx mbufs. + * Create tag for status block. + * Because we only use single Tx/Rx/Rx return ring, use + * minimum status block size except BCM5700 AX/BX which + * seems to want to see full status block size regardless + * of configured number of ring. */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5700 && + sc->bge_chipid != BGE_CHIPID_BCM5700_C0) + sbsz = BGE_STATUS_BLK_SZ; + else + sbsz = 32; + error = bge_dma_ring_alloc(sc, PAGE_SIZE, sbsz, + &sc->bge_cdata.bge_status_tag, + (uint8_t **)&sc->bge_ldata.bge_status_block, + &sc->bge_cdata.bge_status_map, + &sc->bge_ldata.bge_status_block_paddr, "status block"); + if (error) + return (error); + + /* Create tag for statistics block. */ + error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_STATS_SZ, + &sc->bge_cdata.bge_stats_tag, + (uint8_t **)&sc->bge_ldata.bge_stats, + &sc->bge_cdata.bge_stats_map, + &sc->bge_ldata.bge_stats_paddr, "statistics block"); + if (error) + return (error); + + /* Create tag for jumbo RX ring. */ + if (BGE_IS_JUMBO_CAPABLE(sc)) { + error = bge_dma_ring_alloc(sc, PAGE_SIZE, BGE_JUMBO_RX_RING_SZ, + &sc->bge_cdata.bge_rx_jumbo_ring_tag, + (uint8_t **)&sc->bge_ldata.bge_rx_jumbo_ring, + &sc->bge_cdata.bge_rx_jumbo_ring_map, + &sc->bge_ldata.bge_rx_jumbo_ring_paddr, "jumbo RX ring"); + if (error) + return (error); + } + + /* Create parent tag for buffers. */ + boundary = 0; + if ((sc->bge_flags & BGE_FLAG_4G_BNDRY_BUG) != 0) + boundary = BGE_DMA_BNDRY; + error = bus_dma_tag_create(bus_get_dma_tag(sc->bge_dev), + 1, boundary, lowaddr, BUS_SPACE_MAXADDR, NULL, + NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, + 0, NULL, NULL, &sc->bge_cdata.bge_buffer_tag); + if (error != 0) { + device_printf(sc->bge_dev, + "could not allocate buffer dma tag\n"); + return (ENOMEM); + } + /* Create tag for Tx mbufs. */ if (sc->bge_flags & BGE_FLAG_TSO) { txsegsz = BGE_TSOSEG_SZ; txmaxsegsz = 65535 + sizeof(struct ether_vlan_header); @@ -2167,7 +2430,7 @@ bge_dma_alloc(device_t dev) txsegsz = MCLBYTES; txmaxsegsz = MCLBYTES * BGE_NSEG_NEW; } - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, 1, + error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, txmaxsegsz, BGE_NSEG_NEW, txsegsz, 0, NULL, NULL, &sc->bge_cdata.bge_tx_mtag); @@ -2177,10 +2440,8 @@ bge_dma_alloc(device_t dev) return (ENOMEM); } - /* - * Create tag for Rx mbufs. - */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, 1, 0, + /* Create tag for Rx mbufs. */ + error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->bge_cdata.bge_rx_mtag); @@ -2218,42 +2479,9 @@ bge_dma_alloc(device_t dev) } } - /* Create tag for standard RX ring. */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, BGE_STD_RX_RING_SZ, 1, BGE_STD_RX_RING_SZ, 0, - NULL, NULL, &sc->bge_cdata.bge_rx_std_ring_tag); - - if (error) { - device_printf(sc->bge_dev, "could not allocate dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for standard RX ring. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_rx_std_ring_tag, - (void **)&sc->bge_ldata.bge_rx_std_ring, BUS_DMA_NOWAIT, - &sc->bge_cdata.bge_rx_std_ring_map); - if (error) - return (ENOMEM); - - bzero((char *)sc->bge_ldata.bge_rx_std_ring, BGE_STD_RX_RING_SZ); - - /* Load the address of the standard RX ring. */ - ctx.bge_maxsegs = 1; - ctx.sc = sc; - - error = bus_dmamap_load(sc->bge_cdata.bge_rx_std_ring_tag, - sc->bge_cdata.bge_rx_std_ring_map, sc->bge_ldata.bge_rx_std_ring, - BGE_STD_RX_RING_SZ, bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_rx_std_ring_paddr = ctx.bge_busaddr; - - /* Create tags for jumbo mbufs. */ + /* Create tags for jumbo RX buffers. */ if (BGE_IS_JUMBO_CAPABLE(sc)) { - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, + error = bus_dma_tag_create(sc->bge_cdata.bge_buffer_tag, 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MJUM9BYTES, BGE_NSEG_JUMBO, PAGE_SIZE, 0, NULL, NULL, &sc->bge_cdata.bge_mtag_jumbo); @@ -2262,41 +2490,6 @@ bge_dma_alloc(device_t dev) "could not allocate jumbo dma tag\n"); return (ENOMEM); } - - /* Create tag for jumbo RX ring. */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, BGE_JUMBO_RX_RING_SZ, 1, BGE_JUMBO_RX_RING_SZ, 0, - NULL, NULL, &sc->bge_cdata.bge_rx_jumbo_ring_tag); - - if (error) { - device_printf(sc->bge_dev, - "could not allocate jumbo ring dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for jumbo RX ring. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_rx_jumbo_ring_tag, - (void **)&sc->bge_ldata.bge_rx_jumbo_ring, - BUS_DMA_NOWAIT | BUS_DMA_ZERO, - &sc->bge_cdata.bge_rx_jumbo_ring_map); - if (error) - return (ENOMEM); - - /* Load the address of the jumbo RX ring. */ - ctx.bge_maxsegs = 1; - ctx.sc = sc; - - error = bus_dmamap_load(sc->bge_cdata.bge_rx_jumbo_ring_tag, - sc->bge_cdata.bge_rx_jumbo_ring_map, - sc->bge_ldata.bge_rx_jumbo_ring, BGE_JUMBO_RX_RING_SZ, - bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_rx_jumbo_ring_paddr = ctx.bge_busaddr; - /* Create DMA maps for jumbo RX buffers. */ error = bus_dmamap_create(sc->bge_cdata.bge_mtag_jumbo, 0, &sc->bge_cdata.bge_rx_jumbo_sparemap); @@ -2314,154 +2507,8 @@ bge_dma_alloc(device_t dev) return (ENOMEM); } } - } - /* Create tag for RX return ring. */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, BGE_RX_RTN_RING_SZ(sc), 1, BGE_RX_RTN_RING_SZ(sc), 0, - NULL, NULL, &sc->bge_cdata.bge_rx_return_ring_tag); - - if (error) { - device_printf(sc->bge_dev, "could not allocate dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for RX return ring. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_rx_return_ring_tag, - (void **)&sc->bge_ldata.bge_rx_return_ring, BUS_DMA_NOWAIT, - &sc->bge_cdata.bge_rx_return_ring_map); - if (error) - return (ENOMEM); - - bzero((char *)sc->bge_ldata.bge_rx_return_ring, - BGE_RX_RTN_RING_SZ(sc)); - - /* Load the address of the RX return ring. */ - ctx.bge_maxsegs = 1; - ctx.sc = sc; - - error = bus_dmamap_load(sc->bge_cdata.bge_rx_return_ring_tag, - sc->bge_cdata.bge_rx_return_ring_map, - sc->bge_ldata.bge_rx_return_ring, BGE_RX_RTN_RING_SZ(sc), - bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_rx_return_ring_paddr = ctx.bge_busaddr; - - /* Create tag for TX ring. */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, BGE_TX_RING_SZ, 1, BGE_TX_RING_SZ, 0, NULL, NULL, - &sc->bge_cdata.bge_tx_ring_tag); - - if (error) { - device_printf(sc->bge_dev, "could not allocate dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for TX ring. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_tx_ring_tag, - (void **)&sc->bge_ldata.bge_tx_ring, BUS_DMA_NOWAIT, - &sc->bge_cdata.bge_tx_ring_map); - if (error) - return (ENOMEM); - - bzero((char *)sc->bge_ldata.bge_tx_ring, BGE_TX_RING_SZ); - - /* Load the address of the TX ring. */ - ctx.bge_maxsegs = 1; - ctx.sc = sc; - - error = bus_dmamap_load(sc->bge_cdata.bge_tx_ring_tag, - sc->bge_cdata.bge_tx_ring_map, sc->bge_ldata.bge_tx_ring, - BGE_TX_RING_SZ, bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_tx_ring_paddr = ctx.bge_busaddr; - - /* - * Create tag for status block. - * Because we only use single Tx/Rx/Rx return ring, use - * minimum status block size except BCM5700 AX/BX which - * seems to want to see full status block size regardless - * of configured number of ring. - */ - if (sc->bge_asicrev == BGE_ASICREV_BCM5700 && - sc->bge_chipid != BGE_CHIPID_BCM5700_C0) - sbsz = BGE_STATUS_BLK_SZ; - else - sbsz = 32; - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, sbsz, 1, sbsz, 0, NULL, NULL, &sc->bge_cdata.bge_status_tag); - - if (error) { - device_printf(sc->bge_dev, - "could not allocate status dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for status block. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_status_tag, - (void **)&sc->bge_ldata.bge_status_block, BUS_DMA_NOWAIT, - &sc->bge_cdata.bge_status_map); - if (error) - return (ENOMEM); - - bzero((char *)sc->bge_ldata.bge_status_block, sbsz); - - /* Load the address of the status block. */ - ctx.sc = sc; - ctx.bge_maxsegs = 1; - - error = bus_dmamap_load(sc->bge_cdata.bge_status_tag, - sc->bge_cdata.bge_status_map, sc->bge_ldata.bge_status_block, - sbsz, bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_status_block_paddr = ctx.bge_busaddr; - - /* Create tag for statistics block. */ - error = bus_dma_tag_create(sc->bge_cdata.bge_parent_tag, - PAGE_SIZE, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, - NULL, BGE_STATS_SZ, 1, BGE_STATS_SZ, 0, NULL, NULL, - &sc->bge_cdata.bge_stats_tag); - - if (error) { - device_printf(sc->bge_dev, "could not allocate dma tag\n"); - return (ENOMEM); - } - - /* Allocate DMA'able memory for statistics block. */ - error = bus_dmamem_alloc(sc->bge_cdata.bge_stats_tag, - (void **)&sc->bge_ldata.bge_stats, BUS_DMA_NOWAIT, - &sc->bge_cdata.bge_stats_map); - if (error) - return (ENOMEM); - - bzero((char *)sc->bge_ldata.bge_stats, BGE_STATS_SZ); - - /* Load the address of the statstics block. */ - ctx.sc = sc; - ctx.bge_maxsegs = 1; - - error = bus_dmamap_load(sc->bge_cdata.bge_stats_tag, - sc->bge_cdata.bge_stats_map, sc->bge_ldata.bge_stats, - BGE_STATS_SZ, bge_dma_map_addr, &ctx, BUS_DMA_NOWAIT); - - if (error) - return (ENOMEM); - - sc->bge_ldata.bge_stats_paddr = ctx.bge_busaddr; - return (0); } @@ -2521,7 +2568,7 @@ bge_attach(device_t dev) struct bge_softc *sc; uint32_t hwcfg = 0, misccfg; u_char eaddr[ETHER_ADDR_LEN]; - int error, msicount, reg, rid, trys; + int error, msicount, phy_addr, reg, rid, trys; sc = device_get_softc(dev); sc->bge_dev = dev; @@ -2553,6 +2600,9 @@ bge_attach(device_t dev) sc->bge_asicrev = BGE_ASICREV(sc->bge_chipid); sc->bge_chiprev = BGE_CHIPREV(sc->bge_chipid); + /* Set default PHY address. */ + phy_addr = 1; + /* * Don't enable Ethernet@WireSpeed for the 5700, 5906, or the * 5705 A0 and A1 chips. @@ -2561,7 +2611,7 @@ bge_attach(device_t dev) sc->bge_asicrev != BGE_ASICREV_BCM5906 && sc->bge_chipid != BGE_CHIPID_BCM5705_A0 && sc->bge_chipid != BGE_CHIPID_BCM5705_A1) - sc->bge_flags |= BGE_FLAG_WIRESPEED; + sc->bge_phy_flags |= BGE_PHY_WIRESPEED; if (bge_has_eaddr(sc)) sc->bge_flags |= BGE_FLAG_EADDR; @@ -2592,38 +2642,56 @@ bge_attach(device_t dev) case BGE_ASICREV_BCM5752: case BGE_ASICREV_BCM5906: sc->bge_flags |= BGE_FLAG_575X_PLUS; + if (sc->bge_asicrev == BGE_ASICREV_BCM5906) + sc->bge_flags |= BGE_FLAG_SHORT_DMA_BUG; /* FALLTHROUGH */ case BGE_ASICREV_BCM5705: sc->bge_flags |= BGE_FLAG_5705_PLUS; break; } - /* Set various bug flags. */ + /* Set various PHY bug flags. */ if (sc->bge_chipid == BGE_CHIPID_BCM5701_A0 || sc->bge_chipid == BGE_CHIPID_BCM5701_B0) - sc->bge_flags |= BGE_FLAG_CRC_BUG; + sc->bge_phy_flags |= BGE_PHY_CRC_BUG; if (sc->bge_chiprev == BGE_CHIPREV_5703_AX || sc->bge_chiprev == BGE_CHIPREV_5704_AX) - sc->bge_flags |= BGE_FLAG_ADC_BUG; + sc->bge_phy_flags |= BGE_PHY_ADC_BUG; if (sc->bge_chipid == BGE_CHIPID_BCM5704_A0) - sc->bge_flags |= BGE_FLAG_5704_A0_BUG; + sc->bge_phy_flags |= BGE_PHY_5704_A0_BUG; if (pci_get_subvendor(dev) == DELL_VENDORID) - sc->bge_flags |= BGE_FLAG_NO_3LED; - if (pci_get_device(dev) == BCOM_DEVICEID_BCM5755M) - sc->bge_flags |= BGE_FLAG_ADJUST_TRIM; - if (BGE_IS_5705_PLUS(sc) && - !(sc->bge_flags & BGE_FLAG_ADJUST_TRIM)) { + sc->bge_phy_flags |= BGE_PHY_NO_3LED; + if ((BGE_IS_5705_PLUS(sc)) && + sc->bge_asicrev != BGE_ASICREV_BCM5906 && + sc->bge_asicrev != BGE_ASICREV_BCM5785 && + sc->bge_asicrev != BGE_ASICREV_BCM57780) { if (sc->bge_asicrev == BGE_ASICREV_BCM5755 || sc->bge_asicrev == BGE_ASICREV_BCM5761 || sc->bge_asicrev == BGE_ASICREV_BCM5784 || sc->bge_asicrev == BGE_ASICREV_BCM5787) { if (pci_get_device(dev) != BCOM_DEVICEID_BCM5722 && pci_get_device(dev) != BCOM_DEVICEID_BCM5756) - sc->bge_flags |= BGE_FLAG_JITTER_BUG; - } else if (sc->bge_asicrev != BGE_ASICREV_BCM5906) - sc->bge_flags |= BGE_FLAG_BER_BUG; + sc->bge_phy_flags |= BGE_PHY_JITTER_BUG; + if (pci_get_device(dev) == BCOM_DEVICEID_BCM5755M) + sc->bge_phy_flags |= BGE_PHY_ADJUST_TRIM; + } else + sc->bge_phy_flags |= BGE_PHY_BER_BUG; } + /* Identify the chips that use an CPMU. */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5784 || + sc->bge_asicrev == BGE_ASICREV_BCM5761 || + sc->bge_asicrev == BGE_ASICREV_BCM5785 || + sc->bge_asicrev == BGE_ASICREV_BCM57780) + sc->bge_flags |= BGE_FLAG_CPMU_PRESENT; + if ((sc->bge_flags & BGE_FLAG_CPMU_PRESENT) != 0) + sc->bge_mi_mode = BGE_MIMODE_500KHZ_CONST; + else + sc->bge_mi_mode = BGE_MIMODE_BASE; + /* Enable auto polling for BCM570[0-5]. */ + if (BGE_IS_5700_FAMILY(sc) || sc->bge_asicrev == BGE_ASICREV_BCM5705) + sc->bge_mi_mode |= BGE_MIMODE_AUTOPOLL; + /* * All controllers that are not 5755 or higher have 4GB * boundary DMA bug. @@ -2635,14 +2703,12 @@ bge_attach(device_t dev) if (BGE_IS_5755_PLUS(sc) == 0) sc->bge_flags |= BGE_FLAG_4G_BNDRY_BUG; - /* - * We could possibly check for BCOM_DEVICEID_BCM5788 in bge_probe() - * but I do not know the DEVICEID for the 5788M. - */ - misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID; - if (misccfg == BGE_MISCCFG_BOARD_ID_5788 || - misccfg == BGE_MISCCFG_BOARD_ID_5788M) - sc->bge_flags |= BGE_FLAG_5788; + if (sc->bge_asicrev == BGE_ASICREV_BCM5705) { + misccfg = CSR_READ_4(sc, BGE_MISC_CFG) & BGE_MISCCFG_BOARD_ID; + if (misccfg == BGE_MISCCFG_BOARD_ID_5788 || + misccfg == BGE_MISCCFG_BOARD_ID_5788M) + sc->bge_flags |= BGE_FLAG_5788; + } /* * Some controllers seem to require a special firmware to use @@ -2728,12 +2794,11 @@ bge_attach(device_t dev) goto fail; } - if (bootverbose) - device_printf(dev, - "CHIP ID 0x%08x; ASIC REV 0x%02x; CHIP REV 0x%02x; %s\n", - sc->bge_chipid, sc->bge_asicrev, sc->bge_chiprev, - (sc->bge_flags & BGE_FLAG_PCIX) ? "PCI-X" : - ((sc->bge_flags & BGE_FLAG_PCIE) ? "PCI-E" : "PCI")); + device_printf(dev, + "CHIP ID 0x%08x; ASIC REV 0x%02x; CHIP REV 0x%02x; %s\n", + sc->bge_chipid, sc->bge_asicrev, sc->bge_chiprev, + (sc->bge_flags & BGE_FLAG_PCIX) ? "PCI-X" : + ((sc->bge_flags & BGE_FLAG_PCIE) ? "PCI-E" : "PCI")); BGE_LOCK_INIT(sc, device_get_nameunit(dev)); @@ -2788,13 +2853,15 @@ bge_attach(device_t dev) else sc->bge_return_ring_cnt = BGE_RETURN_RING_CNT; - if (bge_dma_alloc(dev)) { + if (bge_dma_alloc(sc)) { device_printf(sc->bge_dev, "failed to allocate DMA resources\n"); error = ENXIO; goto fail; } + bge_add_sysctls(sc); + /* Set default tuneable values. */ sc->bge_stat_ticks = BGE_TICKS_PER_SEC; sc->bge_rx_coal_ticks = 150; @@ -2802,6 +2869,11 @@ bge_attach(device_t dev) sc->bge_rx_max_coal_bds = 10; sc->bge_tx_max_coal_bds = 10; + /* Initialize checksum features to use. */ + sc->bge_csum_features = BGE_CSUM_FEATURES; + if (sc->bge_forced_udpcsum != 0) + sc->bge_csum_features |= CSUM_UDP; + /* Set up ifnet structure */ ifp = sc->bge_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { @@ -2818,7 +2890,7 @@ bge_attach(device_t dev) ifp->if_snd.ifq_drv_maxlen = BGE_TX_RING_CNT - 1; IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); - ifp->if_hwassist = BGE_CSUM_FEATURES; + ifp->if_hwassist = sc->bge_csum_features; ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; if ((sc->bge_flags & BGE_FLAG_TSO) != 0) { @@ -2896,17 +2968,17 @@ bge_attach(device_t dev) again: bge_asf_driver_up(sc); - if (mii_phy_probe(dev, &sc->bge_miibus, - bge_ifmedia_upd, bge_ifmedia_sts)) { + error = (mii_attach(dev, &sc->bge_miibus, ifp, + bge_ifmedia_upd, bge_ifmedia_sts, BMSR_DEFCAPMASK, + phy_addr, MII_OFFSET_ANY, 0)); + if (error != 0) { if (trys++ < 4) { device_printf(sc->bge_dev, "Try again\n"); bge_miibus_writereg(sc->bge_dev, 1, MII_BMCR, BMCR_RESET); goto again; } - - device_printf(sc->bge_dev, "MII without any PHY!\n"); - error = ENXIO; + device_printf(sc->bge_dev, "attaching PHYs failed\n"); goto fail; } @@ -2975,8 +3047,6 @@ again: device_printf(sc->bge_dev, "couldn't set up irq\n"); } - bge_add_sysctls(sc); - return (0); fail: @@ -3465,9 +3535,11 @@ bge_rxeof(struct bge_softc *sc, uint16_t rx_prod, int holdlck) sc->bge_rx_saved_considx = rx_cons; bge_writembx(sc, BGE_MBX_RX_CONS0_LO, sc->bge_rx_saved_considx); if (stdcnt) - bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std); + bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, (sc->bge_std + + BGE_STD_RX_RING_CNT - 1) % BGE_STD_RX_RING_CNT); if (jumbocnt) - bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo); + bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, (sc->bge_jumbo + + BGE_JUMBO_RX_RING_CNT - 1) % BGE_JUMBO_RX_RING_CNT); #ifdef notyet /* * This register wraps very quickly under heavy packet drops. @@ -3482,7 +3554,7 @@ bge_rxeof(struct bge_softc *sc, uint16_t rx_prod, int holdlck) static void bge_txeof(struct bge_softc *sc, uint16_t tx_cons) { - struct bge_tx_bd *cur_tx = NULL; + struct bge_tx_bd *cur_tx; struct ifnet *ifp; BGE_LOCK_ASSERT(sc); @@ -3500,7 +3572,7 @@ bge_txeof(struct bge_softc *sc, uint16_t tx_cons) * frames that have been sent. */ while (sc->bge_tx_saved_considx != tx_cons) { - uint32_t idx = 0; + uint32_t idx; idx = sc->bge_tx_saved_considx; cur_tx = &sc->bge_ldata.bge_tx_ring[idx]; @@ -3519,8 +3591,7 @@ bge_txeof(struct bge_softc *sc, uint16_t tx_cons) BGE_INC(sc->bge_tx_saved_considx, BGE_TX_RING_CNT); } - if (cur_tx != NULL) - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (sc->bge_txcnt == 0) sc->bge_timer = 0; } @@ -3546,8 +3617,8 @@ bge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) rx_prod = sc->bge_ldata.bge_status_block->bge_idx[0].bge_rx_prod_idx; tx_cons = sc->bge_ldata.bge_status_block->bge_idx[0].bge_tx_cons_idx; - statusword = atomic_readandclear_32( - &sc->bge_ldata.bge_status_block->bge_status); + statusword = sc->bge_ldata.bge_status_block->bge_status; + sc->bge_ldata.bge_status_block->bge_status = 0; bus_dmamap_sync(sc->bge_cdata.bge_status_tag, sc->bge_cdata.bge_status_map, @@ -3603,8 +3674,11 @@ bge_intr_task(void *arg, int pending) sc = (struct bge_softc *)arg; ifp = sc->bge_ifp; - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + BGE_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + BGE_UNLOCK(sc); return; + } /* Get updated status block. */ bus_dmamap_sync(sc->bge_cdata.bge_status_tag, @@ -3619,26 +3693,27 @@ bge_intr_task(void *arg, int pending) bus_dmamap_sync(sc->bge_cdata.bge_status_tag, sc->bge_cdata.bge_status_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) + bge_link_upd(sc); + /* Let controller work. */ bge_writembx(sc, BGE_MBX_IRQ0_LO, 0); - if ((status & BGE_STATFLAG_LINKSTATE_CHANGED) != 0) { - BGE_LOCK(sc); - bge_link_upd(sc); - BGE_UNLOCK(sc); - } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + sc->bge_rx_saved_considx != rx_prod) { /* Check RX return ring producer/consumer. */ + BGE_UNLOCK(sc); bge_rxeof(sc, rx_prod, 0); + BGE_LOCK(sc); } if (ifp->if_drv_flags & IFF_DRV_RUNNING) { - BGE_LOCK(sc); /* Check TX ring producer/consumer. */ bge_txeof(sc, tx_cons); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) bge_start_locked(ifp); - BGE_UNLOCK(sc); } + BGE_UNLOCK(sc); } static void @@ -3798,15 +3873,127 @@ static void bge_stats_update_regs(struct bge_softc *sc) { struct ifnet *ifp; + struct bge_mac_stats *stats; ifp = sc->bge_ifp; + stats = &sc->bge_mac_stats; - ifp->if_collisions += CSR_READ_4(sc, BGE_MAC_STATS + - offsetof(struct bge_mac_stats_regs, etherStatsCollisions)); + stats->ifHCOutOctets += + CSR_READ_4(sc, BGE_TX_MAC_STATS_OCTETS); + stats->etherStatsCollisions += + CSR_READ_4(sc, BGE_TX_MAC_STATS_COLLS); + stats->outXonSent += + CSR_READ_4(sc, BGE_TX_MAC_STATS_XON_SENT); + stats->outXoffSent += + CSR_READ_4(sc, BGE_TX_MAC_STATS_XOFF_SENT); + stats->dot3StatsInternalMacTransmitErrors += + CSR_READ_4(sc, BGE_TX_MAC_STATS_ERRORS); + stats->dot3StatsSingleCollisionFrames += + CSR_READ_4(sc, BGE_TX_MAC_STATS_SINGLE_COLL); + stats->dot3StatsMultipleCollisionFrames += + CSR_READ_4(sc, BGE_TX_MAC_STATS_MULTI_COLL); + stats->dot3StatsDeferredTransmissions += + CSR_READ_4(sc, BGE_TX_MAC_STATS_DEFERRED); + stats->dot3StatsExcessiveCollisions += + CSR_READ_4(sc, BGE_TX_MAC_STATS_EXCESS_COLL); + stats->dot3StatsLateCollisions += + CSR_READ_4(sc, BGE_TX_MAC_STATS_LATE_COLL); + stats->ifHCOutUcastPkts += + CSR_READ_4(sc, BGE_TX_MAC_STATS_UCAST); + stats->ifHCOutMulticastPkts += + CSR_READ_4(sc, BGE_TX_MAC_STATS_MCAST); + stats->ifHCOutBroadcastPkts += + CSR_READ_4(sc, BGE_TX_MAC_STATS_BCAST); - ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS); - ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); - ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_ERRORS); + stats->ifHCInOctets += + CSR_READ_4(sc, BGE_RX_MAC_STATS_OCTESTS); + stats->etherStatsFragments += + CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAGMENTS); + stats->ifHCInUcastPkts += + CSR_READ_4(sc, BGE_RX_MAC_STATS_UCAST); + stats->ifHCInMulticastPkts += + CSR_READ_4(sc, BGE_RX_MAC_STATS_MCAST); + stats->ifHCInBroadcastPkts += + CSR_READ_4(sc, BGE_RX_MAC_STATS_BCAST); + stats->dot3StatsFCSErrors += + CSR_READ_4(sc, BGE_RX_MAC_STATS_FCS_ERRORS); + stats->dot3StatsAlignmentErrors += + CSR_READ_4(sc, BGE_RX_MAC_STATS_ALGIN_ERRORS); + stats->xonPauseFramesReceived += + CSR_READ_4(sc, BGE_RX_MAC_STATS_XON_RCVD); + stats->xoffPauseFramesReceived += + CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_RCVD); + stats->macControlFramesReceived += + CSR_READ_4(sc, BGE_RX_MAC_STATS_CTRL_RCVD); + stats->xoffStateEntered += + CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_ENTERED); + stats->dot3StatsFramesTooLong += + CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAME_TOO_LONG); + stats->etherStatsJabbers += + CSR_READ_4(sc, BGE_RX_MAC_STATS_JABBERS); + stats->etherStatsUndersizePkts += + CSR_READ_4(sc, BGE_RX_MAC_STATS_UNDERSIZE); + + stats->FramesDroppedDueToFilters += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_FILTDROP); + stats->DmaWriteQueueFull += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_WRQ_FULL); + stats->DmaWriteHighPriQueueFull += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_HPWRQ_FULL); + stats->NoMoreRxBDs += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS); + stats->InputDiscards += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + stats->InputErrors += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_ERRORS); + stats->RecvThresholdHit += + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_RXTHRESH_HIT); + + ifp->if_collisions = (u_long)stats->etherStatsCollisions; + ifp->if_ierrors = (u_long)(stats->NoMoreRxBDs + stats->InputDiscards + + stats->InputErrors); +} + +static void +bge_stats_clear_regs(struct bge_softc *sc) +{ + + CSR_READ_4(sc, BGE_TX_MAC_STATS_OCTETS); + CSR_READ_4(sc, BGE_TX_MAC_STATS_COLLS); + CSR_READ_4(sc, BGE_TX_MAC_STATS_XON_SENT); + CSR_READ_4(sc, BGE_TX_MAC_STATS_XOFF_SENT); + CSR_READ_4(sc, BGE_TX_MAC_STATS_ERRORS); + CSR_READ_4(sc, BGE_TX_MAC_STATS_SINGLE_COLL); + CSR_READ_4(sc, BGE_TX_MAC_STATS_MULTI_COLL); + CSR_READ_4(sc, BGE_TX_MAC_STATS_DEFERRED); + CSR_READ_4(sc, BGE_TX_MAC_STATS_EXCESS_COLL); + CSR_READ_4(sc, BGE_TX_MAC_STATS_LATE_COLL); + CSR_READ_4(sc, BGE_TX_MAC_STATS_UCAST); + CSR_READ_4(sc, BGE_TX_MAC_STATS_MCAST); + CSR_READ_4(sc, BGE_TX_MAC_STATS_BCAST); + + CSR_READ_4(sc, BGE_RX_MAC_STATS_OCTESTS); + CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAGMENTS); + CSR_READ_4(sc, BGE_RX_MAC_STATS_UCAST); + CSR_READ_4(sc, BGE_RX_MAC_STATS_MCAST); + CSR_READ_4(sc, BGE_RX_MAC_STATS_BCAST); + CSR_READ_4(sc, BGE_RX_MAC_STATS_FCS_ERRORS); + CSR_READ_4(sc, BGE_RX_MAC_STATS_ALGIN_ERRORS); + CSR_READ_4(sc, BGE_RX_MAC_STATS_XON_RCVD); + CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_RCVD); + CSR_READ_4(sc, BGE_RX_MAC_STATS_CTRL_RCVD); + CSR_READ_4(sc, BGE_RX_MAC_STATS_XOFF_ENTERED); + CSR_READ_4(sc, BGE_RX_MAC_STATS_FRAME_TOO_LONG); + CSR_READ_4(sc, BGE_RX_MAC_STATS_JABBERS); + CSR_READ_4(sc, BGE_RX_MAC_STATS_UNDERSIZE); + + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_FILTDROP); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_WRQ_FULL); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_DMA_HPWRQ_FULL); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_OUT_OF_BDS); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_ERRORS); + CSR_READ_4(sc, BGE_RXLP_LOCSTAT_RXTHRESH_HIT); } static void @@ -3883,6 +4070,39 @@ bge_cksum_pad(struct mbuf *m) return (0); } +static struct mbuf * +bge_check_short_dma(struct mbuf *m) +{ + struct mbuf *n; + int found; + + /* + * If device receive two back-to-back send BDs with less than + * or equal to 8 total bytes then the device may hang. The two + * back-to-back send BDs must in the same frame for this failure + * to occur. Scan mbuf chains and see whether two back-to-back + * send BDs are there. If this is the case, allocate new mbuf + * and copy the frame to workaround the silicon bug. + */ + for (n = m, found = 0; n != NULL; n = n->m_next) { + if (n->m_len < 8) { + found++; + if (found > 1) + break; + continue; + } + found = 0; + } + + if (found > 1) { + n = m_defrag(m, M_DONTWAIT); + if (n == NULL) + m_freem(m); + } else + n = m; + return (n); +} + static struct mbuf * bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss) { @@ -3917,9 +4137,11 @@ bge_setup_tso(struct bge_softc *sc, struct mbuf *m, uint16_t *mss) * checksum. These checksum computed by upper stack should be 0. */ *mss = m->m_pkthdr.tso_segsz; + ip = (struct ip *)(mtod(m, char *) + sizeof(struct ether_header)); ip->ip_sum = 0; ip->ip_len = htons(*mss + (ip->ip_hl << 2) + (tcp->th_off << 2)); /* Clear pseudo checksum computed by TCP stack. */ + tcp = (struct tcphdr *)(mtod(m, char *) + poff); tcp->th_sum = 0; /* * Broadcom controllers uses different descriptor format for @@ -3954,13 +4176,20 @@ bge_encap(struct bge_softc *sc, struct mbuf **m_head, uint32_t *txidx) csum_flags = 0; mss = 0; vlan_tag = 0; + if ((sc->bge_flags & BGE_FLAG_SHORT_DMA_BUG) != 0 && + m->m_next != NULL) { + *m_head = bge_check_short_dma(m); + if (*m_head == NULL) + return (ENOBUFS); + m = *m_head; + } if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) { *m_head = m = bge_setup_tso(sc, m, &mss); if (*m_head == NULL) return (ENOBUFS); csum_flags |= BGE_TXBDFLAG_CPU_PRE_DMA | BGE_TXBDFLAG_CPU_POST_DMA; - } else if ((m->m_pkthdr.csum_flags & BGE_CSUM_FEATURES) != 0) { + } else if ((m->m_pkthdr.csum_flags & sc->bge_csum_features) != 0) { if (m->m_pkthdr.csum_flags & CSUM_IP) csum_flags |= BGE_TXBDFLAG_IP_CSUM; if (m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) { @@ -4188,6 +4417,7 @@ bge_init_locked(struct bge_softc *sc) { struct ifnet *ifp; uint16_t *m; + uint32_t mode; BGE_LOCK_ASSERT(sc); @@ -4237,6 +4467,17 @@ bge_init_locked(struct bge_softc *sc) /* Program VLAN tag stripping. */ bge_setvlan(sc); + /* Override UDP checksum offloading. */ + if (sc->bge_forced_udpcsum == 0) + sc->bge_csum_features &= ~CSUM_UDP; + else + sc->bge_csum_features |= CSUM_UDP; + if (ifp->if_capabilities & IFCAP_TXCSUM && + ifp->if_capenable & IFCAP_TXCSUM) { + ifp->if_hwassist &= ~(BGE_CSUM_FEATURES | CSUM_UDP); + ifp->if_hwassist |= sc->bge_csum_features; + } + /* Init RX ring. */ if (bge_init_rx_ring_std(sc) != 0) { device_printf(sc->bge_dev, "no memory for std Rx buffers.\n"); @@ -4282,12 +4523,28 @@ bge_init_locked(struct bge_softc *sc) /* Init TX ring. */ bge_init_tx_ring(sc); + /* Enable TX MAC state machine lockup fix. */ + mode = CSR_READ_4(sc, BGE_TX_MODE); + if (BGE_IS_5755_PLUS(sc) || sc->bge_asicrev == BGE_ASICREV_BCM5906) + mode |= BGE_TXMODE_MBUF_LOCKUP_FIX; /* Turn on transmitter. */ - BGE_SETBIT(sc, BGE_TX_MODE, BGE_TXMODE_ENABLE); + CSR_WRITE_4(sc, BGE_TX_MODE, mode | BGE_TXMODE_ENABLE); /* Turn on receiver. */ BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_ENABLE); + /* + * Set the number of good frames to receive after RX MBUF + * Low Watermark has been reached. After the RX MAC receives + * this number of frames, it will drop subsequent incoming + * frames until the MBUF High Watermark is reached. + */ + CSR_WRITE_4(sc, BGE_MAX_RX_FRAME_LOWAT, 2); + + /* Clear MAC statistics. */ + if (BGE_IS_5705_PLUS(sc)) + bge_stats_clear_regs(sc); + /* Tell firmware we're alive. */ BGE_SETBIT(sc, BGE_MODE_CTL, BGE_MODECTL_STACKUP); @@ -4472,6 +4729,7 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) switch (command) { case SIOCSIFMTU: + BGE_LOCK(sc); if (ifr->ifr_mtu < ETHERMIN || ((BGE_IS_JUMBO_CAPABLE(sc)) && ifr->ifr_mtu > BGE_JUMBO_MTU) || @@ -4480,9 +4738,12 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = EINVAL; else if (ifp->if_mtu != ifr->ifr_mtu) { ifp->if_mtu = ifr->ifr_mtu; - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - bge_init(sc); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + bge_init_locked(sc); + } } + BGE_UNLOCK(sc); break; case SIOCSIFFLAGS: BGE_LOCK(sc); @@ -4558,15 +4819,19 @@ bge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) } } #endif - if (mask & IFCAP_HWCSUM) { - ifp->if_capenable ^= IFCAP_HWCSUM; - if (IFCAP_HWCSUM & ifp->if_capenable && - IFCAP_HWCSUM & ifp->if_capabilities) - ifp->if_hwassist |= BGE_CSUM_FEATURES; + if ((mask & IFCAP_TXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { + ifp->if_capenable ^= IFCAP_TXCSUM; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist |= sc->bge_csum_features; else - ifp->if_hwassist &= ~BGE_CSUM_FEATURES; + ifp->if_hwassist &= ~sc->bge_csum_features; } + if ((mask & IFCAP_RXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_RXCSUM) != 0) + ifp->if_capenable ^= IFCAP_RXCSUM; + if ((mask & IFCAP_TSO4) != 0 && (ifp->if_capabilities & IFCAP_TSO4) != 0) { ifp->if_capenable ^= IFCAP_TSO4; @@ -4689,6 +4954,9 @@ bge_stop(struct bge_softc *sc) BGE_CLRBIT(sc, BGE_BMAN_MODE, BGE_BMANMODE_ENABLE); BGE_CLRBIT(sc, BGE_MARB_MODE, BGE_MARBMODE_ENABLE); } + /* Update MAC statistics. */ + if (BGE_IS_5705_PLUS(sc)) + bge_stats_update_regs(sc); bge_reset(sc); bge_sig_legacy(sc, BGE_RESET_STOP); @@ -4848,7 +5116,7 @@ bge_link_upd(struct bge_softc *sc) if_printf(sc->bge_ifp, "link DOWN\n"); if_link_state_change(sc->bge_ifp, LINK_STATE_DOWN); } - } else if (CSR_READ_4(sc, BGE_MI_MODE) & BGE_MIMODE_AUTOPOLL) { + } else if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { /* * Some broken BCM chips have BGE_STATFLAG_LINKSTATE_CHANGED bit * in status word always set. Workaround this bug by reading @@ -4876,9 +5144,12 @@ bge_link_upd(struct bge_softc *sc) } } else { /* - * Discard link events for MII/GMII controllers - * if MI auto-polling is disabled. + * For controllers that call mii_tick, we have to poll + * link status. */ + mii = device_get_softc(sc->bge_miibus); + mii_pollstat(mii); + bge_miibus_statchg(sc->bge_dev); } /* Clear the attention. */ @@ -4887,17 +5158,13 @@ bge_link_upd(struct bge_softc *sc) BGE_MACSTAT_LINK_CHANGED); } -#define BGE_SYSCTL_STAT(sc, ctx, desc, parent, node, oid) \ - SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, oid, CTLTYPE_UINT|CTLFLAG_RD, \ - sc, offsetof(struct bge_stats, node), bge_sysctl_stats, "IU", \ - desc) - static void bge_add_sysctls(struct bge_softc *sc) { struct sysctl_ctx_list *ctx; - struct sysctl_oid_list *children, *schildren; - struct sysctl_oid *tree; + struct sysctl_oid_list *children; + char tn[32]; + int unit; ctx = device_get_sysctl_ctx(sc->bge_dev); children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->bge_dev)); @@ -4917,6 +5184,7 @@ bge_add_sysctls(struct bge_softc *sc) #endif + unit = device_get_unit(sc->bge_dev); /* * A common design characteristic for many Broadcom client controllers * is that they only support a single outstanding DMA read operation @@ -4929,18 +5197,51 @@ bge_add_sysctls(struct bge_softc *sc) * performance is about 850Mbps. However forcing coalescing mbufs * consumes a lot of CPU cycles, so leave it off by default. */ + sc->bge_forced_collapse = 0; + snprintf(tn, sizeof(tn), "dev.bge.%d.forced_collapse", unit); + TUNABLE_INT_FETCH(tn, &sc->bge_forced_collapse); SYSCTL_ADD_INT(ctx, children, OID_AUTO, "forced_collapse", CTLFLAG_RW, &sc->bge_forced_collapse, 0, "Number of fragmented TX buffers of a frame allowed before " "forced collapsing"); - resource_int_value(device_get_name(sc->bge_dev), - device_get_unit(sc->bge_dev), "forced_collapse", - &sc->bge_forced_collapse); + + /* + * It seems all Broadcom controllers have a bug that can generate UDP + * datagrams with checksum value 0 when TX UDP checksum offloading is + * enabled. Generating UDP checksum value 0 is RFC 768 violation. + * Even though the probability of generating such UDP datagrams is + * low, I don't want to see FreeBSD boxes to inject such datagrams + * into network so disable UDP checksum offloading by default. Users + * still override this behavior by setting a sysctl variable, + * dev.bge.0.forced_udpcsum. + */ + sc->bge_forced_udpcsum = 0; + snprintf(tn, sizeof(tn), "dev.bge.%d.bge_forced_udpcsum", unit); + TUNABLE_INT_FETCH(tn, &sc->bge_forced_udpcsum); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "forced_udpcsum", + CTLFLAG_RW, &sc->bge_forced_udpcsum, 0, + "Enable UDP checksum offloading even if controller can " + "generate UDP checksum value 0"); if (BGE_IS_5705_PLUS(sc)) - return; + bge_add_sysctl_stats_regs(sc, ctx, children); + else + bge_add_sysctl_stats(sc, ctx, children); +} - tree = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, +#define BGE_SYSCTL_STAT(sc, ctx, desc, parent, node, oid) \ + SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, oid, CTLTYPE_UINT|CTLFLAG_RD, \ + sc, offsetof(struct bge_stats, node), bge_sysctl_stats, "IU", \ + desc) + +static void +bge_add_sysctl_stats(struct bge_softc *sc, struct sysctl_ctx_list *ctx, + struct sysctl_oid_list *parent) +{ + struct sysctl_oid *tree; + struct sysctl_oid_list *children, *schildren; + + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", CTLFLAG_RD, NULL, "BGE Statistics"); schildren = children = SYSCTL_CHILDREN(tree); BGE_SYSCTL_STAT(sc, ctx, "Frames Dropped Due To Filters", @@ -4979,11 +5280,11 @@ bge_add_sysctls(struct bge_softc *sc) NULL, "BGE RX Statistics"); children = SYSCTL_CHILDREN(tree); BGE_SYSCTL_STAT(sc, ctx, "Inbound Octets", - children, rxstats.ifHCInOctets, "Octets"); + children, rxstats.ifHCInOctets, "ifHCInOctets"); BGE_SYSCTL_STAT(sc, ctx, "Fragments", children, rxstats.etherStatsFragments, "Fragments"); BGE_SYSCTL_STAT(sc, ctx, "Inbound Unicast Packets", - children, rxstats.ifHCInUcastPkts, "UcastPkts"); + children, rxstats.ifHCInUcastPkts, "UnicastPkts"); BGE_SYSCTL_STAT(sc, ctx, "Inbound Multicast Packets", children, rxstats.ifHCInMulticastPkts, "MulticastPkts"); BGE_SYSCTL_STAT(sc, ctx, "FCS Errors", @@ -5015,7 +5316,7 @@ bge_add_sysctls(struct bge_softc *sc) NULL, "BGE TX Statistics"); children = SYSCTL_CHILDREN(tree); BGE_SYSCTL_STAT(sc, ctx, "Outbound Octets", - children, txstats.ifHCOutOctets, "Octets"); + children, txstats.ifHCOutOctets, "ifHCOutOctets"); BGE_SYSCTL_STAT(sc, ctx, "TX Collisions", children, txstats.etherStatsCollisions, "Collisions"); BGE_SYSCTL_STAT(sc, ctx, "XON Sent", @@ -5043,7 +5344,7 @@ bge_add_sysctls(struct bge_softc *sc) children, txstats.dot3StatsLateCollisions, "LateCollisions"); BGE_SYSCTL_STAT(sc, ctx, "Outbound Unicast Packets", - children, txstats.ifHCOutUcastPkts, "UcastPkts"); + children, txstats.ifHCOutUcastPkts, "UnicastPkts"); BGE_SYSCTL_STAT(sc, ctx, "Outbound Multicast Packets", children, txstats.ifHCOutMulticastPkts, "MulticastPkts"); BGE_SYSCTL_STAT(sc, ctx, "Outbound Broadcast Packets", @@ -5057,6 +5358,106 @@ bge_add_sysctls(struct bge_softc *sc) children, txstats.ifOutErrors, "Errors"); } +#undef BGE_SYSCTL_STAT + +#define BGE_SYSCTL_STAT_ADD64(c, h, n, p, d) \ + SYSCTL_ADD_QUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d) + +static void +bge_add_sysctl_stats_regs(struct bge_softc *sc, struct sysctl_ctx_list *ctx, + struct sysctl_oid_list *parent) +{ + struct sysctl_oid *tree; + struct sysctl_oid_list *child, *schild; + struct bge_mac_stats *stats; + + stats = &sc->bge_mac_stats; + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "BGE Statistics"); + schild = child = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT_ADD64(ctx, child, "FramesDroppedDueToFilters", + &stats->FramesDroppedDueToFilters, "Frames Dropped Due to Filters"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "DmaWriteQueueFull", + &stats->DmaWriteQueueFull, "NIC DMA Write Queue Full"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "DmaWriteHighPriQueueFull", + &stats->DmaWriteHighPriQueueFull, + "NIC DMA Write High Priority Queue Full"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "NoMoreRxBDs", + &stats->NoMoreRxBDs, "NIC No More RX Buffer Descriptors"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "InputDiscards", + &stats->InputDiscards, "Discarded Input Frames"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "InputErrors", + &stats->InputErrors, "Input Errors"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "RecvThresholdHit", + &stats->RecvThresholdHit, "NIC Recv Threshold Hit"); + + tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "rx", CTLFLAG_RD, + NULL, "BGE RX Statistics"); + child = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT_ADD64(ctx, child, "ifHCInOctets", + &stats->ifHCInOctets, "Inbound Octets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "Fragments", + &stats->etherStatsFragments, "Fragments"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "UnicastPkts", + &stats->ifHCInUcastPkts, "Inbound Unicast Packets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "MulticastPkts", + &stats->ifHCInMulticastPkts, "Inbound Multicast Packets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "BroadcastPkts", + &stats->ifHCInBroadcastPkts, "Inbound Broadcast Packets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "FCSErrors", + &stats->dot3StatsFCSErrors, "FCS Errors"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "AlignmentErrors", + &stats->dot3StatsAlignmentErrors, "Alignment Errors"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "xonPauseFramesReceived", + &stats->xonPauseFramesReceived, "XON Pause Frames Received"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "xoffPauseFramesReceived", + &stats->xoffPauseFramesReceived, "XOFF Pause Frames Received"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "ControlFramesReceived", + &stats->macControlFramesReceived, "MAC Control Frames Received"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "xoffStateEntered", + &stats->xoffStateEntered, "XOFF State Entered"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "FramesTooLong", + &stats->dot3StatsFramesTooLong, "Frames Too Long"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "Jabbers", + &stats->etherStatsJabbers, "Jabbers"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "UndersizePkts", + &stats->etherStatsUndersizePkts, "Undersized Packets"); + + tree = SYSCTL_ADD_NODE(ctx, schild, OID_AUTO, "tx", CTLFLAG_RD, + NULL, "BGE TX Statistics"); + child = SYSCTL_CHILDREN(tree); + BGE_SYSCTL_STAT_ADD64(ctx, child, "ifHCOutOctets", + &stats->ifHCOutOctets, "Outbound Octets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "Collisions", + &stats->etherStatsCollisions, "TX Collisions"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "XonSent", + &stats->outXonSent, "XON Sent"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "XoffSent", + &stats->outXoffSent, "XOFF Sent"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "InternalMacTransmitErrors", + &stats->dot3StatsInternalMacTransmitErrors, + "Internal MAC TX Errors"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "SingleCollisionFrames", + &stats->dot3StatsSingleCollisionFrames, "Single Collision Frames"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "MultipleCollisionFrames", + &stats->dot3StatsMultipleCollisionFrames, + "Multiple Collision Frames"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "DeferredTransmissions", + &stats->dot3StatsDeferredTransmissions, "Deferred Transmissions"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "ExcessiveCollisions", + &stats->dot3StatsExcessiveCollisions, "Excessive Collisions"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "LateCollisions", + &stats->dot3StatsLateCollisions, "Late Collisions"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "UnicastPkts", + &stats->ifHCOutUcastPkts, "Outbound Unicast Packets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "MulticastPkts", + &stats->ifHCOutMulticastPkts, "Outbound Multicast Packets"); + BGE_SYSCTL_STAT_ADD64(ctx, child, "BroadcastPkts", + &stats->ifHCOutBroadcastPkts, "Outbound Broadcast Packets"); +} + +#undef BGE_SYSCTL_STAT_ADD64 + static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS) { @@ -5127,7 +5528,7 @@ bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS) printf(" - PCI-X Bus\n"); if (sc->bge_flags & BGE_FLAG_PCIE) printf(" - PCI Express Bus\n"); - if (sc->bge_flags & BGE_FLAG_NO_3LED) + if (sc->bge_phy_flags & BGE_PHY_NO_3LED) printf(" - No 3 LEDs\n"); if (sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) printf(" - RX Alignment Bug\n"); diff --git a/sys/dev/bge/if_bgereg.h b/sys/dev/bge/if_bgereg.h index 6664d5b7e56..a50bf59280a 100644 --- a/sys/dev/bge/if_bgereg.h +++ b/sys/dev/bge/if_bgereg.h @@ -306,6 +306,7 @@ #define BGE_CHIPID_BCM5787_A0 0xb000 #define BGE_CHIPID_BCM5787_A1 0xb001 #define BGE_CHIPID_BCM5787_A2 0xb002 +#define BGE_CHIPID_BCM5906_A0 0xc000 #define BGE_CHIPID_BCM5906_A1 0xc001 #define BGE_CHIPID_BCM5906_A2 0xc002 #define BGE_CHIPID_BCM57780_A0 0x57780000 @@ -632,11 +633,58 @@ #define BGE_RX_BD_RULES_CTL15 0x04F8 #define BGE_RX_BD_RULES_MASKVAL15 0x04FC #define BGE_RX_RULES_CFG 0x0500 +#define BGE_MAX_RX_FRAME_LOWAT 0x0504 #define BGE_SERDES_CFG 0x0590 #define BGE_SERDES_STS 0x0594 #define BGE_SGDIG_CFG 0x05B0 #define BGE_SGDIG_STS 0x05B4 -#define BGE_MAC_STATS 0x0800 +#define BGE_TX_MAC_STATS_OCTETS 0x0800 +#define BGE_TX_MAC_STATS_RESERVE_0 0x0804 +#define BGE_TX_MAC_STATS_COLLS 0x0808 +#define BGE_TX_MAC_STATS_XON_SENT 0x080C +#define BGE_TX_MAC_STATS_XOFF_SENT 0x0810 +#define BGE_TX_MAC_STATS_RESERVE_1 0x0814 +#define BGE_TX_MAC_STATS_ERRORS 0x0818 +#define BGE_TX_MAC_STATS_SINGLE_COLL 0x081C +#define BGE_TX_MAC_STATS_MULTI_COLL 0x0820 +#define BGE_TX_MAC_STATS_DEFERRED 0x0824 +#define BGE_TX_MAC_STATS_RESERVE_2 0x0828 +#define BGE_TX_MAC_STATS_EXCESS_COLL 0x082C +#define BGE_TX_MAC_STATS_LATE_COLL 0x0830 +#define BGE_TX_MAC_STATS_RESERVE_3 0x0834 +#define BGE_TX_MAC_STATS_RESERVE_4 0x0838 +#define BGE_TX_MAC_STATS_RESERVE_5 0x083C +#define BGE_TX_MAC_STATS_RESERVE_6 0x0840 +#define BGE_TX_MAC_STATS_RESERVE_7 0x0844 +#define BGE_TX_MAC_STATS_RESERVE_8 0x0848 +#define BGE_TX_MAC_STATS_RESERVE_9 0x084C +#define BGE_TX_MAC_STATS_RESERVE_10 0x0850 +#define BGE_TX_MAC_STATS_RESERVE_11 0x0854 +#define BGE_TX_MAC_STATS_RESERVE_12 0x0858 +#define BGE_TX_MAC_STATS_RESERVE_13 0x085C +#define BGE_TX_MAC_STATS_RESERVE_14 0x0860 +#define BGE_TX_MAC_STATS_RESERVE_15 0x0864 +#define BGE_TX_MAC_STATS_RESERVE_16 0x0868 +#define BGE_TX_MAC_STATS_UCAST 0x086C +#define BGE_TX_MAC_STATS_MCAST 0x0870 +#define BGE_TX_MAC_STATS_BCAST 0x0874 +#define BGE_TX_MAC_STATS_RESERVE_17 0x0878 +#define BGE_TX_MAC_STATS_RESERVE_18 0x087C +#define BGE_RX_MAC_STATS_OCTESTS 0x0880 +#define BGE_RX_MAC_STATS_RESERVE_0 0x0884 +#define BGE_RX_MAC_STATS_FRAGMENTS 0x0888 +#define BGE_RX_MAC_STATS_UCAST 0x088C +#define BGE_RX_MAC_STATS_MCAST 0x0890 +#define BGE_RX_MAC_STATS_BCAST 0x0894 +#define BGE_RX_MAC_STATS_FCS_ERRORS 0x0898 +#define BGE_RX_MAC_STATS_ALGIN_ERRORS 0x089C +#define BGE_RX_MAC_STATS_XON_RCVD 0x08A0 +#define BGE_RX_MAC_STATS_XOFF_RCVD 0x08A4 +#define BGE_RX_MAC_STATS_CTRL_RCVD 0x08A8 +#define BGE_RX_MAC_STATS_XOFF_ENTERED 0x08AC +#define BGE_RX_MAC_STATS_FRAME_TOO_LONG 0x08B0 +#define BGE_RX_MAC_STATS_JABBERS 0x08B4 +#define BGE_RX_MAC_STATS_UNDERSIZE 0x08B8 /* Ethernet MAC Mode register */ #define BGE_MACMODE_RESET 0x00000001 @@ -718,6 +766,7 @@ #define BGE_TXMODE_FLOWCTL_ENABLE 0x00000010 #define BGE_TXMODE_BIGBACKOFF_ENABLE 0x00000020 #define BGE_TXMODE_LONGPAUSE_ENABLE 0x00000040 +#define BGE_TXMODE_MBUF_LOCKUP_FIX 0x00000100 /* Transmit MAC status register */ #define BGE_TXSTAT_RX_XOFFED 0x00000001 @@ -816,9 +865,12 @@ #define BGE_MISTS_LINK 0x00000001 #define BGE_MISTS_10MBPS 0x00000002 +#define BGE_MIMODE_CLK_10MHZ 0x00000001 #define BGE_MIMODE_SHORTPREAMBLE 0x00000002 #define BGE_MIMODE_AUTOPOLL 0x00000010 #define BGE_MIMODE_CLKCNT 0x001F0000 +#define BGE_MIMODE_500KHZ_CONST 0x00008000 +#define BGE_MIMODE_BASE 0x000C0000 /* @@ -829,6 +881,7 @@ #define BGE_SDI_STATS_CTL 0x0C08 #define BGE_SDI_STATS_ENABLE_MASK 0x0C0C #define BGE_SDI_STATS_INCREMENT_MASK 0x0C10 +#define BGE_ISO_PKT_TX 0x0C20 #define BGE_LOCSTATS_COS0 0x0C80 #define BGE_LOCSTATS_COS1 0x0C84 #define BGE_LOCSTATS_COS2 0x0C88 @@ -1174,6 +1227,51 @@ /* Receive List Selector Status register */ #define BGE_RXLSSTAT_ERROR 0x00000004 +#define BGE_CPMU_CTRL 0x3600 +#define BGE_CPMU_LSPD_10MB_CLK 0x3604 +#define BGE_CPMU_LSPD_1000MB_CLK 0x360C +#define BGE_CPMU_LNK_AWARE_PWRMD 0x3610 +#define BGE_CPMU_HST_ACC 0x361C +#define BGE_CPMU_CLCK_STAT 0x3630 +#define BGE_CPMU_MUTEX_REQ 0x365C +#define BGE_CPMU_MUTEX_GNT 0x3660 +#define BGE_CPMU_PHY_STRAP 0x3664 + +/* Central Power Management Unit (CPMU) register */ +#define BGE_CPMU_CTRL_LINK_IDLE_MODE 0x00000200 +#define BGE_CPMU_CTRL_LINK_AWARE_MODE 0x00000400 +#define BGE_CPMU_CTRL_LINK_SPEED_MODE 0x00004000 +#define BGE_CPMU_CTRL_GPHY_10MB_RXONLY 0x00010000 + +/* Link Speed 10MB/No Link Power Mode Clock Policy register */ +#define BGE_CPMU_LSPD_10MB_MACCLK_MASK 0x001F0000 +#define BGE_CPMU_LSPD_10MB_MACCLK_6_25 0x00130000 + +/* Link Speed 1000MB Power Mode Clock Policy register */ +#define BGE_CPMU_LSPD_1000MB_MACCLK_62_5 0x00000000 +#define BGE_CPMU_LSPD_1000MB_MACCLK_12_5 0x00110000 +#define BGE_CPMU_LSPD_1000MB_MACCLK_MASK 0x001F0000 + +/* Link Aware Power Mode Clock Policy register */ +#define BGE_CPMU_LNK_AWARE_MACCLK_MASK 0x001F0000 +#define BGE_CPMU_LNK_AWARE_MACCLK_6_25 0x00130000 + +#define BGE_CPMU_HST_ACC_MACCLK_MASK 0x001F0000 +#define BGE_CPMU_HST_ACC_MACCLK_6_25 0x00130000 + +/* CPMU Clock Status register */ +#define BGE_CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001F0000 +#define BGE_CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 +#define BGE_CPMU_CLCK_STAT_MAC_CLCK_12_5 0x00110000 +#define BGE_CPMU_CLCK_STAT_MAC_CLCK_6_25 0x00130000 + +/* CPMU Mutex Request register */ +#define BGE_CPMU_MUTEX_REQ_DRIVER 0x00001000 +#define BGE_CPMU_MUTEX_GNT_DRIVER 0x00001000 + +/* CPMU GPHY Strap register */ +#define BGE_CPMU_PHY_STRAP_IS_SERDES 0x00000020 + /* * Mbuf Cluster Free registers (has nothing to do with BSD mbufs) */ @@ -1384,6 +1482,7 @@ */ #define BGE_RDMA_MODE 0x4800 #define BGE_RDMA_STATUS 0x4804 +#define BGE_RDMA_RSRVCTRL 0x4900 /* Read DMA mode register */ #define BGE_RDMAMODE_RESET 0x00000001 @@ -1415,6 +1514,9 @@ #define BGE_RDMASTAT_PCI_FIFOOREAD_ATTN 0x00000100 #define BGE_RDMASTAT_LOCWRITE_TOOBIG 0x00000200 +/* Read DMA Reserved Control register */ +#define BGE_RDMA_RSRVCTRL_FIFO_OFLW_FIX 0x00000004 + /* * Write DMA control registers */ @@ -1434,6 +1536,7 @@ #define BGE_WDMAMODE_LOCREAD_TOOBIG 0x00000200 #define BGE_WDMAMODE_ALL_ATTNS 0x000003FC #define BGE_WDMAMODE_STATUS_TAG_FIX 0x20000000 +#define BGE_WDMAMODE_BURST_ALL_DATA 0xC0000000 /* Write DMA status register */ #define BGE_WDMASTAT_PCI_TGT_ABRT_ATTN 0x00000004 @@ -2348,40 +2451,50 @@ struct bge_tx_mac_stats { }; /* Stats counters access through registers */ -struct bge_mac_stats_regs { - uint32_t ifHCOutOctets; - uint32_t Reserved0; - uint32_t etherStatsCollisions; - uint32_t outXonSent; - uint32_t outXoffSent; - uint32_t Reserved1; - uint32_t dot3StatsInternalMacTransmitErrors; - uint32_t dot3StatsSingleCollisionFrames; - uint32_t dot3StatsMultipleCollisionFrames; - uint32_t dot3StatsDeferredTransmissions; - uint32_t Reserved2; - uint32_t dot3StatsExcessiveCollisions; - uint32_t dot3StatsLateCollisions; - uint32_t Reserved3[14]; - uint32_t ifHCOutUcastPkts; - uint32_t ifHCOutMulticastPkts; - uint32_t ifHCOutBroadcastPkts; - uint32_t Reserved4[2]; - uint32_t ifHCInOctets; - uint32_t Reserved5; - uint32_t etherStatsFragments; - uint32_t ifHCInUcastPkts; - uint32_t ifHCInMulticastPkts; - uint32_t ifHCInBroadcastPkts; - uint32_t dot3StatsFCSErrors; - uint32_t dot3StatsAlignmentErrors; - uint32_t xonPauseFramesReceived; - uint32_t xoffPauseFramesReceived; - uint32_t macControlFramesReceived; - uint32_t xoffStateEntered; - uint32_t dot3StatsFramesTooLong; - uint32_t etherStatsJabbers; - uint32_t etherStatsUndersizePkts; +struct bge_mac_stats { + /* TX MAC statistics */ + uint64_t ifHCOutOctets; + uint64_t Reserved0; + uint64_t etherStatsCollisions; + uint64_t outXonSent; + uint64_t outXoffSent; + uint64_t Reserved1; + uint64_t dot3StatsInternalMacTransmitErrors; + uint64_t dot3StatsSingleCollisionFrames; + uint64_t dot3StatsMultipleCollisionFrames; + uint64_t dot3StatsDeferredTransmissions; + uint64_t Reserved2; + uint64_t dot3StatsExcessiveCollisions; + uint64_t dot3StatsLateCollisions; + uint64_t Reserved3[14]; + uint64_t ifHCOutUcastPkts; + uint64_t ifHCOutMulticastPkts; + uint64_t ifHCOutBroadcastPkts; + uint64_t Reserved4[2]; + /* RX MAC statistics */ + uint64_t ifHCInOctets; + uint64_t Reserved5; + uint64_t etherStatsFragments; + uint64_t ifHCInUcastPkts; + uint64_t ifHCInMulticastPkts; + uint64_t ifHCInBroadcastPkts; + uint64_t dot3StatsFCSErrors; + uint64_t dot3StatsAlignmentErrors; + uint64_t xonPauseFramesReceived; + uint64_t xoffPauseFramesReceived; + uint64_t macControlFramesReceived; + uint64_t xoffStateEntered; + uint64_t dot3StatsFramesTooLong; + uint64_t etherStatsJabbers; + uint64_t etherStatsUndersizePkts; + /* Receive List Placement control */ + uint64_t FramesDroppedDueToFilters; + uint64_t DmaWriteQueueFull; + uint64_t DmaWriteHighPriQueueFull; + uint64_t NoMoreRxBDs; + uint64_t InputDiscards; + uint64_t InputErrors; + uint64_t RecvThresholdHit; }; struct bge_stats { @@ -2487,6 +2600,16 @@ struct bge_gib { #define BGE_DMA_MAXADDR 0xFFFFFFFFFF #endif +#ifdef PAE +#define BGE_DMA_BNDRY 0x80000000 +#else +#if (BUS_SPACE_MAXADDR > 0xFFFFFFFF) +#define BGE_DMA_BNDRY 0x100000000 +#else +#define BGE_DMA_BNDRY 0 +#endif +#endif + /* * Ring structures. Most of these reside in host memory and we tell * the NIC where they are via the ring control blocks. The exceptions @@ -2530,6 +2653,7 @@ struct bge_ring_data { */ struct bge_chain_data { bus_dma_tag_t bge_parent_tag; + bus_dma_tag_t bge_buffer_tag; bus_dma_tag_t bge_rx_std_ring_tag; bus_dma_tag_t bge_rx_jumbo_ring_tag; bus_dma_tag_t bge_rx_return_ring_tag; @@ -2558,12 +2682,7 @@ struct bge_chain_data { }; struct bge_dmamap_arg { - struct bge_softc *sc; bus_addr_t bge_busaddr; - uint16_t bge_flags; - int bge_idx; - int bge_maxsegs; - struct bge_tx_bd *bge_ring; }; #define BGE_HWREV_TIGON 0x01 @@ -2595,29 +2714,32 @@ struct bge_softc { uint32_t bge_flags; #define BGE_FLAG_TBI 0x00000001 #define BGE_FLAG_JUMBO 0x00000002 -#define BGE_FLAG_WIRESPEED 0x00000004 #define BGE_FLAG_EADDR 0x00000008 #define BGE_FLAG_MII_SERDES 0x00000010 +#define BGE_FLAG_CPMU_PRESENT 0x00000020 #define BGE_FLAG_MSI 0x00000100 #define BGE_FLAG_PCIX 0x00000200 #define BGE_FLAG_PCIE 0x00000400 #define BGE_FLAG_TSO 0x00000800 -#define BGE_FLAG_5700_FAMILY 0x00001000 -#define BGE_FLAG_5705_PLUS 0x00002000 -#define BGE_FLAG_5714_FAMILY 0x00004000 -#define BGE_FLAG_575X_PLUS 0x00008000 -#define BGE_FLAG_5755_PLUS 0x00010000 -#define BGE_FLAG_40BIT_BUG 0x00020000 -#define BGE_FLAG_4G_BNDRY_BUG 0x00040000 -#define BGE_FLAG_RX_ALIGNBUG 0x00100000 -#define BGE_FLAG_NO_3LED 0x00200000 -#define BGE_FLAG_ADC_BUG 0x00400000 -#define BGE_FLAG_5704_A0_BUG 0x00800000 -#define BGE_FLAG_JITTER_BUG 0x01000000 -#define BGE_FLAG_BER_BUG 0x02000000 -#define BGE_FLAG_ADJUST_TRIM 0x04000000 -#define BGE_FLAG_CRC_BUG 0x08000000 -#define BGE_FLAG_5788 0x20000000 +#define BGE_FLAG_5700_FAMILY 0x00010000 +#define BGE_FLAG_5705_PLUS 0x00020000 +#define BGE_FLAG_5714_FAMILY 0x00040000 +#define BGE_FLAG_575X_PLUS 0x00080000 +#define BGE_FLAG_5755_PLUS 0x00100000 +#define BGE_FLAG_5788 0x00200000 +#define BGE_FLAG_40BIT_BUG 0x01000000 +#define BGE_FLAG_4G_BNDRY_BUG 0x02000000 +#define BGE_FLAG_RX_ALIGNBUG 0x04000000 +#define BGE_FLAG_SHORT_DMA_BUG 0x08000000 + uint32_t bge_phy_flags; +#define BGE_PHY_WIRESPEED 0x00000001 +#define BGE_PHY_ADC_BUG 0x00000002 +#define BGE_PHY_5704_A0_BUG 0x00000004 +#define BGE_PHY_JITTER_BUG 0x00000008 +#define BGE_PHY_BER_BUG 0x00000010 +#define BGE_PHY_ADJUST_TRIM 0x00000020 +#define BGE_PHY_CRC_BUG 0x00000040 +#define BGE_PHY_NO_3LED 0x00000080 uint32_t bge_chipid; uint32_t bge_asicrev; uint32_t bge_chiprev; @@ -2637,13 +2759,15 @@ struct bge_softc { uint32_t bge_tx_prodidx; uint32_t bge_rx_max_coal_bds; uint32_t bge_tx_max_coal_bds; - uint32_t bge_tx_buf_ratio; + uint32_t bge_mi_mode; int bge_if_flags; int bge_txcnt; int bge_link; /* link state */ int bge_link_evt; /* pending link event */ int bge_timer; int bge_forced_collapse; + int bge_forced_udpcsum; + int bge_csum_features; struct callout bge_stat_ch; uint32_t bge_rx_discards; uint32_t bge_tx_discards; @@ -2651,6 +2775,7 @@ struct bge_softc { #ifdef DEVICE_POLLING int rxcycles; #endif /* DEVICE_POLLING */ + struct bge_mac_stats bge_mac_stats; struct task bge_intr_task; struct taskqueue *bge_tq; }; diff --git a/sys/dev/bm/if_bm.c b/sys/dev/bm/if_bm.c index c2a43589baf..ded2b42f6f3 100644 --- a/sys/dev/bm/if_bm.c +++ b/sys/dev/bm/if_bm.c @@ -594,11 +594,19 @@ bm_attach(device_t dev) /* reset the adapter */ bm_chip_setup(sc); - /* setup MII */ - error = mii_phy_probe(dev, &sc->sc_miibus, bm_ifmedia_upd, - bm_ifmedia_sts); - if (error != 0) - device_printf(dev,"PHY probe failed: %d\n", error); + /* + * Setup MII + * On Apple BMAC controllers, we end up in a weird state of + * partially-completed autonegotiation on boot. So we force + * autonegotation to try again. + */ + error = mii_attach(dev, &sc->sc_miibus, ifp, bm_ifmedia_upd, + bm_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_FORCEANEG); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); + return (error); + } sc->sc_mii = device_get_softc(sc->sc_miibus); diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c index e9f4c85882d..8e3c8b9d726 100644 --- a/sys/dev/bwn/if_bwn.c +++ b/sys/dev/bwn/if_bwn.c @@ -2907,7 +2907,7 @@ bwn_set_channel(struct ieee80211com *ic) bwn_rf_turnon(mac); if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)) device_printf(sc->sc_dev, - "please turns on the RF switch\n"); + "please turn on the RF switch\n"); } else bwn_rf_turnoff(mac); } diff --git a/sys/dev/cas/if_cas.c b/sys/dev/cas/if_cas.c index c3de5122c40..e454fa1592d 100644 --- a/sys/dev/cas/if_cas.c +++ b/sys/dev/cas/if_cas.c @@ -344,13 +344,9 @@ cas_attach(struct cas_softc *sc) BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } - switch (sc->sc_variant) { - default: - sc->sc_phyad = -1; - break; - } - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - cas_mediachange, cas_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, + MII_PHY_ANY, MII_OFFSET_ANY, 0); } /* * Fall back on an internal PHY if no external PHY was found. @@ -368,13 +364,9 @@ cas_attach(struct cas_softc *sc) BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } - switch (sc->sc_variant) { - default: - sc->sc_phyad = -1; - break; - } - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - cas_mediachange, cas_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, + MII_PHY_ANY, MII_OFFSET_ANY, 0); } } else { /* @@ -394,12 +386,12 @@ cas_attach(struct cas_softc *sc) CAS_WRITE_4(sc, CAS_PCS_CONF, CAS_PCS_CONF_EN); CAS_BARRIER(sc, CAS_PCS_CONF, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - sc->sc_phyad = CAS_PHYAD_EXTERNAL; - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - cas_mediachange, cas_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + cas_mediachange, cas_mediastatus, BMSR_DEFCAPMASK, + CAS_PHYAD_EXTERNAL, MII_OFFSET_ANY, 0); } if (error != 0) { - device_printf(sc->sc_dev, "PHY probe failed: %d\n", error); + device_printf(sc->sc_dev, "attaching PHYs failed\n"); goto fail_rxmap; } sc->sc_mii = device_get_softc(sc->sc_miibus); @@ -2172,9 +2164,6 @@ cas_mii_readreg(device_t dev, int phy, int reg) #endif sc = device_get_softc(dev); - if (sc->sc_phyad != -1 && phy != sc->sc_phyad) - return (0); - if ((sc->sc_flags & CAS_SERDES) != 0) { switch (reg) { case MII_BMCR: @@ -2233,9 +2222,6 @@ cas_mii_writereg(device_t dev, int phy, int reg, int val) #endif sc = device_get_softc(dev); - if (sc->sc_phyad != -1 && phy != sc->sc_phyad) - return (0); - if ((sc->sc_flags & CAS_SERDES) != 0) { switch (reg) { case MII_BMSR: @@ -2318,8 +2304,7 @@ cas_mii_statchg(device_t dev) #ifdef CAS_DEBUG if ((ifp->if_flags & IFF_DEBUG) != 0) - device_printf(sc->sc_dev, "%s: status change: PHY = %d\n", - __func__, sc->sc_phyad); + device_printf(sc->sc_dev, "%s: status changen", __func__); #endif if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) != 0 && diff --git a/sys/dev/cas/if_casvar.h b/sys/dev/cas/if_casvar.h index e800f4e9f7b..fa2e6af9fde 100644 --- a/sys/dev/cas/if_casvar.h +++ b/sys/dev/cas/if_casvar.h @@ -154,8 +154,6 @@ struct cas_softc { bus_dma_tag_t sc_cdmatag; /* control data bus DMA tag */ bus_dmamap_t sc_dmamap; /* bus DMA handle */ - u_int sc_phyad; /* PHY to use or -1 for any */ - u_int sc_variant; #define CAS_UNKNOWN 0 /* don't know */ #define CAS_CAS 1 /* Sun Cassini */ diff --git a/sys/dev/ciss/ciss.c b/sys/dev/ciss/ciss.c index 2a4fb27ae55..e892e5061a9 100644 --- a/sys/dev/ciss/ciss.c +++ b/sys/dev/ciss/ciss.c @@ -4394,7 +4394,7 @@ ciss_name_ldrive_org(int org) case CISS_LDRIVE_RAID0: return("RAID 0"); case CISS_LDRIVE_RAID1: - return("RAID 1"); + return("RAID 1(1+0)"); case CISS_LDRIVE_RAID4: return("RAID 4"); case CISS_LDRIVE_RAID5: diff --git a/sys/dev/cxgb/common/cxgb_common.h b/sys/dev/cxgb/common/cxgb_common.h index 1501e16751e..3760bd6084b 100644 --- a/sys/dev/cxgb/common/cxgb_common.h +++ b/sys/dev/cxgb/common/cxgb_common.h @@ -745,6 +745,7 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n, int t3_mac_init(struct cmac *mac); void t3b_pcs_reset(struct cmac *mac); +void t3c_pcs_force_los(struct cmac *mac); void t3_mac_disable_exact_filters(struct cmac *mac); void t3_mac_enable_exact_filters(struct cmac *mac); int t3_mac_enable(struct cmac *mac, int which); diff --git a/sys/dev/cxgb/common/cxgb_t3_hw.c b/sys/dev/cxgb/common/cxgb_t3_hw.c index ce274075d0c..6083ad3c777 100644 --- a/sys/dev/cxgb/common/cxgb_t3_hw.c +++ b/sys/dev/cxgb/common/cxgb_t3_hw.c @@ -1441,16 +1441,18 @@ static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg, t3_mac_disable_exact_filters(mac); /* stop broadcast, multicast, promiscuous mode traffic */ - *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG); - t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, + *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG + mac->offset); + t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset, F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, F_DISBCAST); - *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0); + *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH + + mac->offset); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset, 0); - *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0); + *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW + + mac->offset); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset, 0); /* Leave time to drain max RX fifo */ msleep(1); @@ -1460,11 +1462,13 @@ static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg, u32 rx_hash_high, u32 rx_hash_low) { t3_mac_enable_exact_filters(mac); - t3_set_reg_field(mac->adapter, A_XGM_RX_CFG, + t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset, F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES, rx_cfg); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high); - t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset, + rx_hash_high); + t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset, + rx_hash_low); } static int t3_detect_link_fault(adapter_t *adapter, int port_id) @@ -1558,6 +1562,13 @@ void t3_link_changed(adapter_t *adapter, int port_id) pi->link_fault = LF_YES; } + if (uses_xaui(adapter)) { + if (adapter->params.rev >= T3_REV_C) + t3c_pcs_force_los(mac); + else + t3b_pcs_reset(mac); + } + /* Don't report link up */ link_ok = 0; } else { @@ -1584,12 +1595,20 @@ void t3_link_changed(adapter_t *adapter, int port_id) /* down -> up, or up -> up with changed settings */ if (adapter->params.rev > 0 && uses_xaui(adapter)) { + + if (adapter->params.rev >= T3_REV_C) + t3c_pcs_force_los(mac); + else + t3b_pcs_reset(mac); + t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, F_TXACTENABLE | F_RXEN); } + /* disable TX FIFO drain */ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, F_ENDROPPKT, 0); + t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset, F_CLRSTATS, 1); @@ -1609,20 +1628,21 @@ void t3_link_changed(adapter_t *adapter, int port_id) t3_set_reg_field(adapter, A_XGM_INT_ENABLE + mac->offset, F_XGM_INT, 0); - } - if (!link_fault) t3_mac_disable(mac, MAC_DIRECTION_RX); - /* - * Make sure Tx FIFO continues to drain, even as rxen is left - * high to help detect and indicate remote faults. - */ - t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset, 0, - F_ENDROPPKT); - t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); - t3_write_reg(adapter, A_XGM_TX_CTRL + mac->offset, F_TXEN); - t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN); + /* + * Make sure Tx FIFO continues to drain, even as rxen is + * left high to help detect and indicate remote faults. + */ + t3_set_reg_field(adapter, + A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT); + t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0); + t3_write_reg(adapter, + A_XGM_TX_CTRL + mac->offset, F_TXEN); + t3_write_reg(adapter, + A_XGM_RX_CTRL + mac->offset, F_RXEN); + } } t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc, diff --git a/sys/dev/cxgb/common/cxgb_xgmac.c b/sys/dev/cxgb/common/cxgb_xgmac.c index 853da35ddfe..ea4230e62d3 100644 --- a/sys/dev/cxgb/common/cxgb_xgmac.c +++ b/sys/dev/cxgb/common/cxgb_xgmac.c @@ -97,11 +97,40 @@ void t3b_pcs_reset(struct cmac *mac) { t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, F_PCS_RESET_, 0); - udelay(20); + + /* No delay required */ + t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, F_PCS_RESET_); } +void t3c_pcs_force_los(struct cmac *mac) +{ + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset, + F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0, + F_LOWSIGFORCEEN0 | F_LOWSIGFORCEVALUE0); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset, + F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1, + F_LOWSIGFORCEEN1 | F_LOWSIGFORCEVALUE1); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset, + F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2, + F_LOWSIGFORCEEN2 | F_LOWSIGFORCEVALUE2); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset, + F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3, + F_LOWSIGFORCEEN3 | F_LOWSIGFORCEVALUE3); + + /* No delay required */ + + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT0 + mac->offset, + F_LOWSIGFORCEEN0, 0); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT1 + mac->offset, + F_LOWSIGFORCEEN1, 0); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT2 + mac->offset, + F_LOWSIGFORCEEN2, 0); + t3_set_reg_field(mac->adapter, A_XGM_SERDES_STAT3 + mac->offset, + F_LOWSIGFORCEEN3, 0); +} + /** * t3_mac_init - initialize a MAC * @mac: the MAC to initialize @@ -433,7 +462,7 @@ static int rx_fifo_hwm(int mtu) */ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) { - int hwm, lwm, divisor; + int hwm, lwm; int ipg; unsigned int thres, v, reg; adapter_t *adap = mac->adapter; @@ -512,16 +541,6 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset, V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG), V_TXFIFOTHRESH(thres) | V_TXIPG(ipg)); - - /* Assuming a minimum drain rate of 2.5Gbps... - */ - if (adap->params.rev > 0) { - divisor = (adap->params.rev == T3_REV_C) ? 64 : 8; - t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, - (hwm - lwm) * 4 / divisor); - } - t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, - MAC_RXFIFO_SIZE * 4 * 8 / 512); return 0; } @@ -541,9 +560,17 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) u32 val; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; + unsigned int pause_bits; if (duplex >= 0 && duplex != DUPLEX_FULL) return -EINVAL; + + pause_bits = MAC_RXFIFO_SIZE * 4 * 8; + t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset, + pause_bits / 512); + t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset, + (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7))); + if (mac->multiport) { u32 rx_max_pkt_size = G_RXMAXPKTSIZE(t3_read_reg(adap, @@ -552,9 +579,9 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc) val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM); val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8); t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val); - t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, F_TXPAUSEEN); + return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port); } if (speed >= 0) { diff --git a/sys/dev/cxgb/cxgb_main.c b/sys/dev/cxgb/cxgb_main.c index fc66d605dd4..2dd29ac65a7 100644 --- a/sys/dev/cxgb/cxgb_main.c +++ b/sys/dev/cxgb/cxgb_main.c @@ -1778,11 +1778,12 @@ cxgb_init_locked(struct port_info *p) struct adapter *sc = p->adapter; struct ifnet *ifp = p->ifp; struct cmac *mac = &p->mac; - int i, rc = 0, may_sleep = 0; + int i, rc = 0, may_sleep = 0, gave_up_lock = 0; ADAPTER_LOCK_ASSERT_OWNED(sc); while (!IS_DOOMED(p) && IS_BUSY(sc)) { + gave_up_lock = 1; if (mtx_sleep(&sc->flags, &sc->lock, PCATCH, "cxgbinit", 0)) { rc = EINTR; goto done; @@ -1802,6 +1803,7 @@ cxgb_init_locked(struct port_info *p) if (may_sleep) { SET_BUSY(sc); + gave_up_lock = 1; ADAPTER_UNLOCK(sc); } @@ -1849,8 +1851,9 @@ done: ADAPTER_LOCK(sc); KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); CLR_BUSY(sc); - wakeup_one(&sc->flags); } + if (gave_up_lock) + wakeup_one(&sc->flags); ADAPTER_UNLOCK(sc); return (rc); } diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c index 4032b4f1f9c..5fb206b8ba3 100644 --- a/sys/dev/cxgb/cxgb_sge.c +++ b/sys/dev/cxgb/cxgb_sge.c @@ -3227,7 +3227,6 @@ t3_dump_rspq(SYSCTL_HANDLER_ARGS) struct sge_rspq *rspq; struct sge_qset *qs; int i, err, dump_end, idx; - static int multiplier = 1; struct sbuf *sb; struct rsp_desc *rspd; uint32_t data[4]; @@ -3252,8 +3251,8 @@ t3_dump_rspq(SYSCTL_HANDLER_ARGS) err = t3_sge_read_rspq(qs->port->adapter, rspq->cntxt_id, data); if (err) return (err); -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " \n index=%u size=%u MSI-X/RspQ=%u intr enable=%u intr armed=%u\n", (data[0] & 0xffff), data[0] >> 16, ((data[2] >> 20) & 0x3f), @@ -3276,13 +3275,11 @@ retry_sbufops: rspd->rss_hdr.rss_hash_val, be32toh(rspd->flags), be32toh(rspd->len_cq), rspd->intr_gen); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } @@ -3293,7 +3290,6 @@ t3_dump_txq_eth(SYSCTL_HANDLER_ARGS) struct sge_txq *txq; struct sge_qset *qs; int i, j, err, dump_end; - static int multiplier = 1; struct sbuf *sb; struct tx_desc *txd; uint32_t *WR, wr_hi, wr_lo, gen; @@ -3321,9 +3317,7 @@ t3_dump_txq_eth(SYSCTL_HANDLER_ARGS) if (err) return (err); - -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " \n credits=%u GTS=%u index=%u size=%u rspq#=%u cmdq#=%u\n", (data[0] & 0x7fff), ((data[0] >> 15) & 1), (data[0] >> 16), @@ -3350,13 +3344,10 @@ retry_sbufops: WR[j], WR[j + 1], WR[j + 2], WR[j + 3]); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } @@ -3367,7 +3358,6 @@ t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS) struct sge_txq *txq; struct sge_qset *qs; int i, j, err, dump_end; - static int multiplier = 1; struct sbuf *sb; struct tx_desc *txd; uint32_t *WR, wr_hi, wr_lo, gen; @@ -3391,8 +3381,7 @@ t3_dump_txq_ctrl(SYSCTL_HANDLER_ARGS) return (EINVAL); } -retry_sbufops: - sb = sbuf_new(NULL, NULL, QDUMP_SBUF_SIZE*multiplier, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, QDUMP_SBUF_SIZE, req); sbuf_printf(sb, " qid=%d start=%d -> end=%d\n", qs->idx, txq->txq_dump_start, (txq->txq_dump_start + txq->txq_dump_count) & 255); @@ -3412,13 +3401,10 @@ retry_sbufops: WR[j], WR[j + 1], WR[j + 2], WR[j + 3]); } - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } - sbuf_finish(sb); - err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + err = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (err == 0) + err = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (err); } diff --git a/sys/dev/dc/dcphy.c b/sys/dev/dc/dcphy.c index a4df704316e..64294df14c2 100644 --- a/sys/dev/dc/dcphy.c +++ b/sys/dev/dc/dcphy.c @@ -146,10 +146,11 @@ dcphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = dcphy_service; sc->mii_pdata = mii; @@ -159,8 +160,6 @@ dcphy_attach(device_t dev) */ sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; - mii->mii_instance++; - /*dcphy_reset(sc);*/ dc_sc = mii->mii_ifp->if_softc; CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); @@ -204,28 +203,15 @@ dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; - sc->mii_flags = 0; mii->mii_media_active = IFM_NONE; mode = CSR_READ_4(dc_sc, DC_NETCFG); mode &= ~(DC_NETCFG_FULLDUPLEX | DC_NETCFG_PORTSEL | @@ -275,12 +261,6 @@ dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ @@ -361,14 +341,14 @@ dcphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_100_TX | IFM_FDX; else if (anlpar & ANLPAR_T4 && sc->mii_capabilities & BMSR_100T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4 | IFM_HDX; else if (anlpar & ANLPAR_TX && sc->mii_capabilities & BMSR_100TXHDX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX | IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T | IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T | IFM_HDX; else mii->mii_media_active |= IFM_NONE; if (DC_IS_INTEL(dc_sc)) @@ -386,9 +366,9 @@ dcphy_status(struct mii_softc *sc) * change the media settings if we're wrong. */ if (!(reg & DC_TSTAT_LS100)) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX | IFM_HDX; else if (!(reg & DC_TSTAT_LS10)) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T | IFM_HDX; else mii->mii_media_active |= IFM_NONE; if (DC_IS_INTEL(dc_sc)) @@ -403,6 +383,8 @@ skip: mii->mii_media_active |= IFM_100_TX; if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } static int diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index a1df655849f..856908129bc 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -293,6 +293,7 @@ static void dc_decode_leaf_sia(struct dc_softc *, struct dc_eblock_sia *); static void dc_decode_leaf_mii(struct dc_softc *, struct dc_eblock_mii *); static void dc_decode_leaf_sym(struct dc_softc *, struct dc_eblock_sym *); static void dc_apply_fixup(struct dc_softc *, int); +static int dc_check_multiport(struct dc_softc *); #ifdef DC_USEIOSPACE #define DC_RES SYS_RES_IOPORT @@ -778,26 +779,6 @@ dc_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); - /* - * Note: both the AL981 and AN983 have internal PHYs, - * however the AL981 provides direct access to the PHY - * registers while the AN983 uses a serial MII interface. - * The AN983's MII interface is also buggy in that you - * can read from any MII address (0 to 31), but only address 1 - * behaves normally. To deal with both cases, we pretend - * that the PHY is at MII address 1. - */ - if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) - return (0); - - /* - * Note: the ukphy probes of the RS7112 report a PHY at - * MII address 0 (possibly HomePNA?) and 1 (ethernet) - * so we only respond to correct one. - */ - if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) - return (0); - if (sc->dc_pmode != DC_PMODE_MII) { if (phy == (MII_NPHY - 1)) { switch (reg) { @@ -900,12 +881,6 @@ dc_miibus_writereg(device_t dev, int phy, int reg, int data) sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); - if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) - return (0); - - if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) - return (0); - if (DC_IS_PNIC(sc)) { CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE | (phy << 23) | (reg << 10) | data); @@ -1814,14 +1789,12 @@ dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) static int dc_attach(device_t dev) { - int tmp = 0; uint32_t eaddr[(ETHER_ADDR_LEN+3)/4]; u_int32_t command; struct dc_softc *sc; struct ifnet *ifp; u_int32_t reg, revision; - int error = 0, rid, mac_offset; - int i; + int error, i, mac_offset, phy, rid, tmp; u_int8_t *mac; sc = device_get_softc(dev); @@ -2088,6 +2061,20 @@ dc_attach(device_t dev) break; } + bcopy(eaddr, sc->dc_eaddr, sizeof(eaddr)); + /* + * If we still have invalid station address, see whether we can + * find station address for chip 0. Some multi-port controllers + * just store station address for chip 0 if they have a shared + * SROM. + */ + if ((sc->dc_eaddr[0] == 0 && (sc->dc_eaddr[1] & ~0xffff) == 0) || + (sc->dc_eaddr[0] == 0xffffffff && + (sc->dc_eaddr[1] & 0xffff) == 0xffff)) { + if (dc_check_multiport(sc) == 0) + bcopy(sc->dc_eaddr, eaddr, sizeof(eaddr)); + } + /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, @@ -2202,6 +2189,7 @@ dc_attach(device_t dev) * old selection (SIA only or SIA/SYM) and attach the dcphy * driver instead. */ + tmp = 0; if (DC_IS_INTEL(sc)) { dc_apply_fixup(sc, IFM_AUTO); tmp = sc->dc_pmode; @@ -2210,7 +2198,7 @@ dc_attach(device_t dev) /* * Setup General Purpose port mode and data so the tulip can talk - * to the MII. This needs to be done before mii_phy_probe so that + * to the MII. This needs to be done before mii_attach so that * we can actually see them. */ if (DC_IS_XIRCOM(sc)) { @@ -2222,16 +2210,37 @@ dc_attach(device_t dev) DELAY(10); } - error = mii_phy_probe(dev, &sc->dc_miibus, - dc_ifmedia_upd, dc_ifmedia_sts); + phy = MII_PHY_ANY; + /* + * Note: both the AL981 and AN983 have internal PHYs, however the + * AL981 provides direct access to the PHY registers while the AN983 + * uses a serial MII interface. The AN983's MII interface is also + * buggy in that you can read from any MII address (0 to 31), but + * only address 1 behaves normally. To deal with both cases, we + * pretend that the PHY is at MII address 1. + */ + if (DC_IS_ADMTEK(sc)) + phy = DC_ADMTEK_PHYADDR; + + /* + * Note: the ukphy probes of the RS7112 report a PHY at MII address + * 0 (possibly HomePNA?) and 1 (ethernet) so we only respond to the + * correct one. + */ + if (DC_IS_CONEXANT(sc)) + phy = DC_CONEXANT_PHYADDR; + + error = mii_attach(dev, &sc->dc_miibus, ifp, dc_ifmedia_upd, + dc_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); if (error && DC_IS_INTEL(sc)) { sc->dc_pmode = tmp; if (sc->dc_pmode != DC_PMODE_SIA) sc->dc_pmode = DC_PMODE_SYM; sc->dc_flags |= DC_21143_NWAY; - mii_phy_probe(dev, &sc->dc_miibus, - dc_ifmedia_upd, dc_ifmedia_sts); + mii_attach(dev, &sc->dc_miibus, ifp, dc_ifmedia_upd, + dc_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, + MII_OFFSET_ANY, 0); /* * For non-MII cards, we need to have the 21143 * drive the LEDs. Except there are some systems @@ -2246,7 +2255,7 @@ dc_attach(device_t dev) } if (error) { - device_printf(dev, "MII without any PHY!\n"); + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -3808,3 +3817,34 @@ dc_shutdown(device_t dev) return (0); } + +static int +dc_check_multiport(struct dc_softc *sc) +{ + struct dc_softc *dsc; + devclass_t dc; + device_t child; + uint8_t *eaddr; + int unit; + + dc = devclass_find("dc"); + for (unit = 0; unit < devclass_get_maxunit(dc); unit++) { + child = devclass_get_device(dc, unit); + if (child == NULL) + continue; + if (child == sc->dc_dev) + continue; + if (device_get_parent(child) != device_get_parent(sc->dc_dev)) + continue; + if (unit > device_get_unit(sc->dc_dev)) + continue; + dsc = device_get_softc(child); + device_printf(sc->dc_dev, "Using station address of %s as base", + device_get_nameunit(child)); + bcopy(dsc->dc_eaddr, sc->dc_eaddr, ETHER_ADDR_LEN); + eaddr = (uint8_t *)sc->dc_eaddr; + eaddr[5]++; + return (0); + } + return (ENOENT); +} diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h index 20fd2ce1ba4..32acc4a1bdf 100644 --- a/sys/dev/dc/if_dcreg.h +++ b/sys/dev/dc/if_dcreg.h @@ -745,6 +745,7 @@ struct dc_softc { int dc_if_media; u_int32_t dc_flags; u_int32_t dc_txthresh; + u_int32_t dc_eaddr[2]; u_int8_t *dc_srom; struct dc_mediainfo *dc_mi; struct dc_list_data *dc_ldata; diff --git a/sys/dev/dc/pnphy.c b/sys/dev/dc/pnphy.c index d1282a78c6f..15704b2aebb 100644 --- a/sys/dev/dc/pnphy.c +++ b/sys/dev/dc/pnphy.c @@ -129,10 +129,11 @@ pnphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = pnphy_service; sc->mii_pdata = mii; @@ -142,8 +143,6 @@ pnphy_attach(device_t dev) */ sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; - mii->mii_instance++; - sc->mii_capabilities = BMSR_100TXFDX | BMSR_100TXHDX | BMSR_10TFDX | BMSR_10THDX; sc->mii_capabilities &= ma->mii_capmask; @@ -162,29 +161,15 @@ pnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; - sc->mii_flags = 0; - switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: /* NWAY is busted on this chip */ @@ -211,12 +196,6 @@ pnphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ @@ -257,4 +236,6 @@ pnphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_100_TX; if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } diff --git a/sys/dev/e1000/e1000_82571.c b/sys/dev/e1000/e1000_82571.c index afeb1a05e5c..3554dbe3083 100644 --- a/sys/dev/e1000/e1000_82571.c +++ b/sys/dev/e1000/e1000_82571.c @@ -78,6 +78,10 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw); static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); +static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw); +static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw); +static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw); +static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw); static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); @@ -91,6 +95,7 @@ static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw); static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; + struct e1000_dev_spec_82571 *dev_spec = &hw->dev_spec._82571; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_init_phy_params_82571"); @@ -104,9 +109,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->reset_delay_us = 100; - phy->ops.acquire = e1000_get_hw_semaphore_82571; phy->ops.check_reset_block = e1000_check_reset_block_generic; - phy->ops.release = e1000_put_hw_semaphore_82571; phy->ops.reset = e1000_phy_hw_reset_generic; phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82571; phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic; @@ -124,6 +127,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_get_cable_length_igp_2; phy->ops.read_reg = e1000_read_phy_reg_igp; phy->ops.write_reg = e1000_write_phy_reg_igp; + phy->ops.acquire = e1000_get_hw_semaphore_82571; + phy->ops.release = e1000_put_hw_semaphore_82571; /* This uses above function pointers */ ret_val = e1000_get_phy_id_82571(hw); @@ -145,6 +150,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_get_cable_length_m88; phy->ops.read_reg = e1000_read_phy_reg_m88; phy->ops.write_reg = e1000_write_phy_reg_m88; + phy->ops.acquire = e1000_get_hw_semaphore_82571; + phy->ops.release = e1000_put_hw_semaphore_82571; /* This uses above function pointers */ ret_val = e1000_get_phy_id_82571(hw); @@ -158,6 +165,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) break; case e1000_82574: case e1000_82583: + E1000_MUTEX_INIT(&dev_spec->swflag_mutex); + phy->type = e1000_phy_bm; phy->ops.get_cfg_done = e1000_get_cfg_done_generic; phy->ops.get_info = e1000_get_phy_info_m88; @@ -167,6 +176,8 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->ops.get_cable_length = e1000_get_cable_length_m88; phy->ops.read_reg = e1000_read_phy_reg_bm2; phy->ops.write_reg = e1000_write_phy_reg_bm2; + phy->ops.acquire = e1000_get_hw_semaphore_82574; + phy->ops.release = e1000_put_hw_semaphore_82574; /* This uses above function pointers */ ret_val = e1000_get_phy_id_82571(hw); @@ -250,9 +261,18 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw) } /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_nvm_82571; + switch (hw->mac.type) { + case e1000_82574: + case e1000_82583: + nvm->ops.acquire = e1000_get_hw_semaphore_82574; + nvm->ops.release = e1000_put_hw_semaphore_82574; + break; + default: + nvm->ops.acquire = e1000_acquire_nvm_82571; + nvm->ops.release = e1000_release_nvm_82571; + break; + } nvm->ops.read = e1000_read_nvm_eerd; - nvm->ops.release = e1000_release_nvm_82571; nvm->ops.update = e1000_update_nvm_checksum_82571; nvm->ops.validate = e1000_validate_nvm_checksum_82571; nvm->ops.valid_led_default = e1000_valid_led_default_82571; @@ -577,6 +597,96 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_SWSM, swsm); } +/** + * e1000_get_hw_semaphore_82573 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore during reset. + * + **/ +static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + s32 ret_val = E1000_SUCCESS; + s32 i = 0; + + DEBUGFUNC("e1000_get_hw_semaphore_82573"); + + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + do { + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + + if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) + break; + + extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + + msec_delay(2); + i++; + } while (i < MDIO_OWNERSHIP_TIMEOUT); + + if (i == MDIO_OWNERSHIP_TIMEOUT) { + /* Release semaphores */ + e1000_put_hw_semaphore_82573(hw); + DEBUGOUT("Driver can't access the PHY\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_put_hw_semaphore_82573 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used during reset. + * + **/ +static void e1000_put_hw_semaphore_82573(struct e1000_hw *hw) +{ + u32 extcnf_ctrl; + + DEBUGFUNC("e1000_put_hw_semaphore_82573"); + + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); +} + +/** + * e1000_get_hw_semaphore_82574 - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM. + * + **/ +static s32 e1000_get_hw_semaphore_82574(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_get_hw_semaphore_82574"); + + E1000_MUTEX_LOCK(&hw->dev_spec._82571.swflag_mutex); + return e1000_get_hw_semaphore_82573(hw); +} + +/** + * e1000_put_hw_semaphore_82574 - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + * + **/ +static void e1000_put_hw_semaphore_82574(struct e1000_hw *hw) +{ + DEBUGFUNC("e1000_put_hw_semaphore_82574"); + + e1000_put_hw_semaphore_82573(hw); + E1000_MUTEX_UNLOCK(&hw->dev_spec._82571.swflag_mutex); +} + /** * e1000_acquire_nvm_82571 - Request for access to the EEPROM * @hw: pointer to the HW structure @@ -598,8 +708,6 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw) switch (hw->mac.type) { case e1000_82573: - case e1000_82574: - case e1000_82583: break; default: ret_val = e1000_acquire_nvm_generic(hw); @@ -926,9 +1034,8 @@ out: **/ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) { - u32 ctrl, extcnf_ctrl, ctrl_ext, icr; + u32 ctrl, ctrl_ext, icr; s32 ret_val; - u16 i = 0; DEBUGFUNC("e1000_reset_hw_82571"); @@ -955,33 +1062,33 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) */ switch (hw->mac.type) { case e1000_82573: + ret_val = e1000_get_hw_semaphore_82573(hw); + break; case e1000_82574: case e1000_82583: - extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - - do { - E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); - extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - - if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) - break; - - extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - - msec_delay(2); - i++; - } while (i < MDIO_OWNERSHIP_TIMEOUT); + ret_val = e1000_get_hw_semaphore_82574(hw); break; default: break; } + if (ret_val) + DEBUGOUT("Cannot acquire MDIO ownership\n"); ctrl = E1000_READ_REG(hw, E1000_CTRL); DEBUGOUT("Issuing a global reset to MAC\n"); E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); + /* Must release MDIO ownership and mutex after MAC reset. */ + switch (hw->mac.type) { + case e1000_82574: + case e1000_82583: + e1000_put_hw_semaphore_82574(hw); + break; + default: + break; + } + if (hw->nvm.type == e1000_nvm_flash_hw) { usec_delay(10); ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); @@ -1015,12 +1122,14 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); icr = E1000_READ_REG(hw, E1000_ICR); - /* Install any alternate MAC address into RAR0 */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; + if (hw->mac.type == e1000_82571) { + /* Install any alternate MAC address into RAR0 */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; - e1000_set_laa_state_82571(hw, TRUE); + e1000_set_laa_state_82571(hw, TRUE); + } /* Reinitialize the 82571 serdes link state machine */ if (hw->phy.media_type == e1000_media_type_internal_serdes) @@ -1330,6 +1439,42 @@ static s32 e1000_led_on_82574(struct e1000_hw *hw) return E1000_SUCCESS; } +/** + * e1000_check_phy_82574 - check 82574 phy hung state + * @hw: pointer to the HW structure + * + * Returns whether phy is hung or not + **/ +bool e1000_check_phy_82574(struct e1000_hw *hw) +{ + u16 status_1kbt = 0; + u16 receive_errors = 0; + bool phy_hung = FALSE; + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_check_phy_82574"); + + /* + * Read PHY Receive Error counter first, if its is max - all F's then + * read the Base1000T status register If both are max then PHY is hung. + */ + ret_val = hw->phy.ops.read_reg(hw, E1000_RECEIVE_ERROR_COUNTER, + &receive_errors); + if (ret_val) + goto out; + if (receive_errors == E1000_RECEIVE_ERROR_MAX) { + ret_val = hw->phy.ops.read_reg(hw, E1000_BASE1000T_STATUS, + &status_1kbt); + if (ret_val) + goto out; + if ((status_1kbt & E1000_IDLE_ERROR_COUNT_MASK) == + E1000_IDLE_ERROR_COUNT_MASK) + phy_hung = TRUE; + } +out: + return phy_hung; +} + /** * e1000_setup_link_82571 - Setup flow control and link settings @@ -1460,6 +1605,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) u32 rxcw; u32 ctrl; u32 status; + u32 txcw; + u32 i; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_check_for_serdes_link_82571"); @@ -1482,8 +1629,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) e1000_serdes_link_autoneg_progress; mac->serdes_has_link = FALSE; DEBUGOUT("AN_UP -> AN_PROG\n"); + } else { + mac->serdes_has_link = TRUE; } - break; + break; case e1000_serdes_link_forced_up: /* @@ -1491,8 +1640,10 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) * auto-negotiation in the TXCW register and disable * forced link in the Device Control register in an * attempt to auto-negotiate with our link partner. + * If the partner code word is null, stop forcing + * and restart auto negotiation. */ - if (rxcw & E1000_RXCW_C) { + if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW)) { /* Enable autoneg, and unforce link up */ E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); E1000_WRITE_REG(hw, E1000_CTRL, @@ -1501,6 +1652,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) e1000_serdes_link_autoneg_progress; mac->serdes_has_link = FALSE; DEBUGOUT("FORCED_UP -> AN_PROG\n"); + } else { + mac->serdes_has_link = TRUE; } break; @@ -1559,6 +1712,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) (ctrl & ~E1000_CTRL_SLU)); mac->serdes_link_state = e1000_serdes_link_autoneg_progress; + mac->serdes_has_link = FALSE; DEBUGOUT("DOWN -> AN_PROG\n"); break; } @@ -1569,16 +1723,32 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) DEBUGOUT("ANYSTATE -> DOWN\n"); } else { /* - * We have sync, and can tolerate one invalid (IV) - * codeword before declaring link down, so reread - * to look again. + * Check several times, if Sync and Config + * both are consistently 1 then simply ignore + * the Invalid bit and restart Autoneg */ - usec_delay(10); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - if (rxcw & E1000_RXCW_IV) { - mac->serdes_link_state = e1000_serdes_link_down; + for (i = 0; i < AN_RETRY_COUNT; i++) { + usec_delay(10); + rxcw = E1000_READ_REG(hw, E1000_RXCW); + if ((rxcw & E1000_RXCW_IV) && + !((rxcw & E1000_RXCW_SYNCH) && + (rxcw & E1000_RXCW_C))) { + mac->serdes_has_link = FALSE; + mac->serdes_link_state = + e1000_serdes_link_down; + DEBUGOUT("ANYSTATE -> DOWN\n"); + break; + } + } + + if (i == AN_RETRY_COUNT) { + txcw = E1000_READ_REG(hw, E1000_TXCW); + txcw |= E1000_TXCW_ANE; + E1000_WRITE_REG(hw, E1000_TXCW, txcw); + mac->serdes_link_state = + e1000_serdes_link_autoneg_progress; mac->serdes_has_link = FALSE; - DEBUGOUT("ANYSTATE -> DOWN\n"); + DEBUGOUT("ANYSTATE -> AN_PROG\n"); } } } @@ -1736,14 +1906,16 @@ static s32 e1000_read_mac_addr_82571(struct e1000_hw *hw) DEBUGFUNC("e1000_read_mac_addr_82571"); - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = e1000_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; + if (hw->mac.type == e1000_82571) { + /* + * If there's an alternate MAC address place it in RAR0 + * so that it will override the Si installed default perm + * address. + */ + ret_val = e1000_check_alt_mac_addr_generic(hw); + if (ret_val) + goto out; + } ret_val = e1000_read_mac_addr_generic(hw); diff --git a/sys/dev/e1000/e1000_82571.h b/sys/dev/e1000/e1000_82571.h index 5e66793c013..c76f16fe179 100644 --- a/sys/dev/e1000/e1000_82571.h +++ b/sys/dev/e1000/e1000_82571.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2008, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -42,6 +42,7 @@ (ID_LED_DEF1_DEF2)) #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 +#define AN_RETRY_COUNT 5 /* Autoneg Retry Count value */ /* Intr Throttling - RW */ #define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n))) @@ -53,6 +54,11 @@ #define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */ +#define E1000_BASE1000T_STATUS 10 +#define E1000_IDLE_ERROR_COUNT_MASK 0xFF +#define E1000_RECEIVE_ERROR_COUNTER 21 +#define E1000_RECEIVE_ERROR_MAX 0xFFFF +bool e1000_check_phy_82574(struct e1000_hw *hw); bool e1000_get_laa_state_82571(struct e1000_hw *hw); void e1000_set_laa_state_82571(struct e1000_hw *hw, bool state); diff --git a/sys/dev/e1000/e1000_82575.c b/sys/dev/e1000/e1000_82575.c index 65b3ce47a41..bc04b452e49 100644 --- a/sys/dev/e1000/e1000_82575.c +++ b/sys/dev/e1000/e1000_82575.c @@ -85,6 +85,7 @@ static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw); static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw); static void e1000_power_up_serdes_link_82575(struct e1000_hw *hw); static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw); +static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw); static const u16 e1000_82580_rxpbs_table[] = { 36, 72, 144, 1, 2, 4, 8, 16, @@ -92,6 +93,37 @@ static const u16 e1000_82580_rxpbs_table[] = #define E1000_82580_RXPBS_TABLE_SIZE \ (sizeof(e1000_82580_rxpbs_table)/sizeof(u16)) + +/** + * e1000_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO + * @hw: pointer to the HW structure + * + * Called to determine if the I2C pins are being used for I2C or as an + * external MDIO interface since the two options are mutually exclusive. + **/ +static bool e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw) +{ + u32 reg = 0; + bool ext_mdio = FALSE; + + DEBUGFUNC("e1000_sgmii_uses_mdio_82575"); + + switch (hw->mac.type) { + case e1000_82575: + case e1000_82576: + reg = E1000_READ_REG(hw, E1000_MDIC); + ext_mdio = !!(reg & E1000_MDIC_DEST); + break; + case e1000_82580: + reg = E1000_READ_REG(hw, E1000_MDICNFG); + ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO); + break; + default: + break; + } + return ext_mdio; +} + /** * e1000_init_phy_params_82575 - Init PHY func ptrs. * @hw: pointer to the HW structure @@ -100,6 +132,7 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; s32 ret_val = E1000_SUCCESS; + u32 ctrl_ext; DEBUGFUNC("e1000_init_phy_params_82575"); @@ -120,16 +153,26 @@ static s32 e1000_init_phy_params_82575(struct e1000_hw *hw) phy->ops.get_cfg_done = e1000_get_cfg_done_82575; phy->ops.release = e1000_release_phy_82575; + ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); + if (e1000_sgmii_active_82575(hw)) { phy->ops.reset = e1000_phy_hw_reset_sgmii_82575; + ctrl_ext |= E1000_CTRL_I2C_ENA; + } else { + phy->ops.reset = e1000_phy_hw_reset_generic; + ctrl_ext &= ~E1000_CTRL_I2C_ENA; + } + + E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); + e1000_reset_mdicnfg_82580(hw); + + if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) { phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575; phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575; } else if (hw->mac.type >= e1000_82580) { - phy->ops.reset = e1000_phy_hw_reset_generic; phy->ops.read_reg = e1000_read_phy_reg_82580; phy->ops.write_reg = e1000_write_phy_reg_82580; } else { - phy->ops.reset = e1000_phy_hw_reset_generic; phy->ops.read_reg = e1000_read_phy_reg_igp; phy->ops.write_reg = e1000_write_phy_reg_igp; } @@ -256,27 +299,15 @@ static s32 e1000_init_mac_params_82575(struct e1000_hw *hw) switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) { case E1000_CTRL_EXT_LINK_MODE_SGMII: dev_spec->sgmii_active = TRUE; - ctrl_ext |= E1000_CTRL_I2C_ENA; break; case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: hw->phy.media_type = e1000_media_type_internal_serdes; - ctrl_ext |= E1000_CTRL_I2C_ENA; break; default: - ctrl_ext &= ~E1000_CTRL_I2C_ENA; break; } - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - - /* - * if using i2c make certain the MDICNFG register is cleared to prevent - * communications from being misrouted to the mdic registers - */ - if ((ctrl_ext & E1000_CTRL_I2C_ENA) && (hw->mac.type == e1000_82580)) - E1000_WRITE_REG(hw, E1000_MDICNFG, 0); - /* Set mta register count */ mac->mta_reg_count = 128; /* Set uta register count */ @@ -367,6 +398,7 @@ void e1000_init_function_pointers_82575(struct e1000_hw *hw) hw->mac.ops.init_params = e1000_init_mac_params_82575; hw->nvm.ops.init_params = e1000_init_nvm_params_82575; hw->phy.ops.init_params = e1000_init_phy_params_82575; + hw->mbx.ops.init_params = e1000_init_mbx_params_pf; } /** @@ -492,6 +524,7 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) s32 ret_val = E1000_SUCCESS; u16 phy_id; u32 ctrl_ext; + u32 mdic; DEBUGFUNC("e1000_get_phy_id_82575"); @@ -508,6 +541,28 @@ static s32 e1000_get_phy_id_82575(struct e1000_hw *hw) goto out; } + if (e1000_sgmii_uses_mdio_82575(hw)) { + switch (hw->mac.type) { + case e1000_82575: + case e1000_82576: + mdic = E1000_READ_REG(hw, E1000_MDIC); + mdic &= E1000_MDIC_PHY_MASK; + phy->addr = mdic >> E1000_MDIC_PHY_SHIFT; + break; + case e1000_82580: + mdic = E1000_READ_REG(hw, E1000_MDICNFG); + mdic &= E1000_MDICNFG_PHY_MASK; + phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT; + break; + default: + ret_val = -E1000_ERR_PHY; + goto out; + break; + } + ret_val = e1000_get_phy_id(hw); + goto out; + } + /* Power on sgmii phy if it is disabled */ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); E1000_WRITE_REG(hw, E1000_CTRL_EXT, @@ -1243,6 +1298,7 @@ static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw) case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX: /* disable PCS autoneg and support parallel detect only */ pcs_autoneg = FALSE; + /* fall through to default case */ default: /* * non-SGMII modes only supports a speed of 1000/Full for the @@ -1638,6 +1694,39 @@ out: return ret_val; } + +/** + * e1000_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing + * @hw: pointer to the hardware struct + * @enable: state to enter, either enabled or disabled + * @pf: Physical Function pool - do not set anti-spoofing for the PF + * + * enables/disables L2 switch anti-spoofing functionality. + **/ +void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf) +{ + u32 dtxswc; + + switch (hw->mac.type) { + case e1000_82576: + dtxswc = E1000_READ_REG(hw, E1000_DTXSWC); + if (enable) { + dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); + /* The PF can spoof - it has to in order to + * support emulation mode NICs */ + dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS)); + } else { + dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK | + E1000_DTXSWC_VLAN_SPOOF_MASK); + } + E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc); + break; + default: + break; + } +} + /** * e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback * @hw: pointer to the hardware struct @@ -1738,6 +1827,45 @@ out: return ret_val; } +/** + * e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits + * @hw: pointer to the HW structure + * + * This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on + * the values found in the EEPROM. This addresses an issue in which these + * bits are not restored from EEPROM after reset. + **/ +static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u32 mdicnfg; + u16 nvm_data; + + DEBUGFUNC("e1000_reset_mdicnfg_82580"); + + if (hw->mac.type != e1000_82580) + goto out; + if (!e1000_sgmii_active_82575(hw)) + goto out; + + ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A + + NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1, + &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG); + if (nvm_data & NVM_WORD24_EXT_MDIO) + mdicnfg |= E1000_MDICNFG_EXT_MDIO; + if (nvm_data & NVM_WORD24_COM_MDIO) + mdicnfg |= E1000_MDICNFG_COM_MDIO; + E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg); +out: + return ret_val; +} + /** * e1000_reset_hw_82580 - Reset hardware * @hw: pointer to the HW structure @@ -1814,6 +1942,10 @@ static s32 e1000_reset_hw_82580(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); icr = E1000_READ_REG(hw, E1000_ICR); + ret_val = e1000_reset_mdicnfg_82580(hw); + if (ret_val) + DEBUGOUT("Could not reset MDICNFG based on EEPROM\n"); + /* Install any alternate MAC address into RAR0 */ ret_val = e1000_check_alt_mac_addr_generic(hw); diff --git a/sys/dev/e1000/e1000_82575.h b/sys/dev/e1000/e1000_82575.h index d64538cc5e0..eb05262d386 100644 --- a/sys/dev/e1000/e1000_82575.h +++ b/sys/dev/e1000/e1000_82575.h @@ -458,6 +458,7 @@ struct e1000_adv_tx_context_desc { /* RX packet buffer size defines */ #define E1000_RXPBS_SIZE_MASK_82576 0x0000007F void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable); +void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf); void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable); enum e1000_promisc_type { e1000_promisc_disabled = 0, /* all promisc modes disabled */ diff --git a/sys/dev/e1000/e1000_api.c b/sys/dev/e1000/e1000_api.c index 8a49c2b4f94..3ae023cf45d 100644 --- a/sys/dev/e1000/e1000_api.c +++ b/sys/dev/e1000/e1000_api.c @@ -276,6 +276,8 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) break; case E1000_DEV_ID_ICH10_D_BM_LM: case E1000_DEV_ID_ICH10_D_BM_LF: + case E1000_DEV_ID_ICH10_D_BM_V: + case E1000_DEV_ID_ICH10_HANKSVILLE: mac->type = e1000_ich10lan; break; case E1000_DEV_ID_PCH_D_HV_DM: @@ -284,6 +286,10 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_PCH_M_HV_LC: mac->type = e1000_pchlan; break; + case E1000_DEV_ID_PCH2_LV_LM: + case E1000_DEV_ID_PCH2_LV_V: + mac->type = e1000_pch2lan; + break; case E1000_DEV_ID_82575EB_COPPER: case E1000_DEV_ID_82575EB_FIBER_SERDES: case E1000_DEV_ID_82575GB_QUAD_COPPER: @@ -294,6 +300,7 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_QUAD_COPPER_ET2: case E1000_DEV_ID_82576_NS: case E1000_DEV_ID_82576_NS_SERDES: case E1000_DEV_ID_82576_SERDES_QUAD: @@ -304,6 +311,7 @@ s32 e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82580_SERDES: case E1000_DEV_ID_82580_SGMII: case E1000_DEV_ID_82580_COPPER_DUAL: + case E1000_DEV_ID_82580_QUAD_FIBER: mac->type = e1000_82580; break; case E1000_DEV_ID_82576_VF: @@ -396,6 +404,7 @@ s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device) case e1000_ich9lan: case e1000_ich10lan: case e1000_pchlan: + case e1000_pch2lan: e1000_init_function_pointers_ich8lan(hw); break; case e1000_82575: @@ -1130,6 +1139,37 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw) return e1000_read_mac_addr_generic(hw); } +/** + * e1000_read_pba_string - Read device part number string + * @hw: pointer to the HW structure + * @pba_num: pointer to device part number + * @pba_num_size: size of part number buffer + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in pba_num. + * Currently no func pointer exists and all implementations are handled in the + * generic version of this function. + **/ +s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num, u32 pba_num_size) +{ + return e1000_read_pba_string_generic(hw, pba_num, pba_num_size); +} + +/** + * e1000_read_pba_length - Read device part number string length + * @hw: pointer to the HW structure + * @pba_num_size: size of part number buffer + * + * Reads the product board assembly (PBA) number length from the EEPROM and + * stores the value in pba_num. + * Currently no func pointer exists and all implementations are handled in the + * generic version of this function. + **/ +s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size) +{ + return e1000_read_pba_length_generic(hw, pba_num_size); +} + /** * e1000_read_pba_num - Read device part number * @hw: pointer to the HW structure diff --git a/sys/dev/e1000/e1000_api.h b/sys/dev/e1000/e1000_api.h index 9fc7469af5c..36ba712857f 100644 --- a/sys/dev/e1000/e1000_api.h +++ b/sys/dev/e1000/e1000_api.h @@ -97,6 +97,9 @@ void e1000_power_up_phy(struct e1000_hw *hw); void e1000_power_down_phy(struct e1000_hw *hw); s32 e1000_read_mac_addr(struct e1000_hw *hw); s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num); +s32 e1000_read_pba_string(struct e1000_hw *hw, u8 *pba_num, + u32 pba_num_size); +s32 e1000_read_pba_length(struct e1000_hw *hw, u32 *pba_num_size); void e1000_reload_nvm(struct e1000_hw *hw); s32 e1000_update_nvm_checksum(struct e1000_hw *hw); s32 e1000_validate_nvm_checksum(struct e1000_hw *hw); diff --git a/sys/dev/e1000/e1000_defines.h b/sys/dev/e1000/e1000_defines.h index 7ac5d8b8b1d..5d09ad92dfa 100644 --- a/sys/dev/e1000/e1000_defines.h +++ b/sys/dev/e1000/e1000_defines.h @@ -49,6 +49,8 @@ #define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ #define E1000_WUC_SPM 0x80000000 /* Enable SPM */ #define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ +#define E1000_WUC_FLX6_PHY 0x4000 /* Flexible Filter 6 Enable */ +#define E1000_WUC_FLX7_PHY 0x8000 /* Flexible Filter 7 Enable */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ @@ -73,6 +75,8 @@ #define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ #define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */ #define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ +#define E1000_WUFC_FLX6 0x00400000 /* Flexible Filter 6 Enable */ +#define E1000_WUFC_FLX7 0x00800000 /* Flexible Filter 7 Enable */ #define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/ #define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */ #define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/ @@ -80,9 +84,11 @@ #define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/ #define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ #define E1000_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask for all 6 wakeup filters*/ +#define E1000_WUFC_ALL_FILTERS_8 0x00FF00FF /* Mask for all 8 wakeup filters*/ #define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ #define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */ #define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Mask for 6 flexible filters */ +#define E1000_WUFC_FLX_FILTERS_8 0x00FF0000 /* Mask for 8 flexible filters */ /* * For 82576 to utilize Extended filter masks in addition to * existing (filter) masks @@ -109,10 +115,15 @@ #define E1000_WUS_FLX3 E1000_WUFC_FLX3 #define E1000_WUS_FLX4 E1000_WUFC_FLX4 #define E1000_WUS_FLX5 E1000_WUFC_FLX5 +#define E1000_WUS_FLX6 E1000_WUFC_FLX6 +#define E1000_WUS_FLX7 E1000_WUFC_FLX7 #define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY #define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY +#define E1000_WUS_FLX6_PHY 0x0400 +#define E1000_WUS_FLX7_PHY 0x0800 #define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS #define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6 +#define E1000_WUS_FLX_FILTERS_8 E1000_WUFC_FLX_FILTERS_8 #define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6 /* Wake Up Packet Length */ @@ -122,6 +133,8 @@ #define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 /* Six Flexible Filters are supported */ #define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6 +/* Eight Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX_8 8 /* Two Extended Flexible Filters are supported (82576) */ #define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX 2 #define E1000_FHFT_LENGTH_OFFSET 0xFC /* Length byte in FHFT */ @@ -132,6 +145,7 @@ #define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX #define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6 +#define E1000_FFLT_SIZE_8 E1000_FLEXIBLE_FILTER_COUNT_MAX_8 #define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX #define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX @@ -710,6 +724,7 @@ #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 #define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 #define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 #define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 @@ -1013,6 +1028,9 @@ #define E1000_ERR_SWFW_SYNC 13 #define E1000_NOT_IMPLEMENTED 14 #define E1000_ERR_MBX 15 +#define E1000_ERR_INVALID_ARGUMENT 16 +#define E1000_ERR_NO_SPACE 17 +#define E1000_ERR_NVM_PBA_SECTION 18 /* Loop limit on how long we wait for auto-negotiation to complete */ #define FIBER_LINK_UP_LIMIT 50 @@ -1106,6 +1124,11 @@ #define E1000_IMIR_PRIORITY_SHIFT 29 /* IMIR Priority Shift */ #define E1000_IMIREXT_CLEAR_MASK 0x7FFFF /* IMIREXT Reg Clear Mask */ +#define E1000_MDICNFG_EXT_MDIO 0x80000000 /* MDI ext/int destination */ +#define E1000_MDICNFG_COM_MDIO 0x40000000 /* MDI shared w/ lan 0 */ +#define E1000_MDICNFG_PHY_MASK 0x03E00000 +#define E1000_MDICNFG_PHY_SHIFT 21 + /* PCI Express Control */ #define E1000_GCR_RXD_NO_SNOOP 0x00000001 #define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 @@ -1301,6 +1324,10 @@ #define NVM_82580_LAN_FUNC_OFFSET(a) (a ? (0x40 + (0x40 * a)) : 0) +/* Mask bits for fields in Word 0x24 of the NVM */ +#define NVM_WORD24_COM_MDIO 0x0008 /* MDIO interface shared */ +#define NVM_WORD24_EXT_MDIO 0x0004 /* MDIO accesses routed external */ + /* Mask bits for fields in Word 0x0f of the NVM */ #define NVM_WORD0F_PAUSE_MASK 0x3000 #define NVM_WORD0F_PAUSE 0x1000 @@ -1312,12 +1339,19 @@ /* Mask bits for fields in Word 0x1a of the NVM */ #define NVM_WORD1A_ASPM_MASK 0x000C +/* Mask bits for fields in Word 0x03 of the EEPROM */ +#define NVM_COMPAT_LOM 0x0800 + +/* length of string needed to store PBA number */ +#define E1000_PBANUM_LENGTH 11 + /* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ #define NVM_SUM 0xBABA #define NVM_MAC_ADDR_OFFSET 0 #define NVM_PBA_OFFSET_0 8 #define NVM_PBA_OFFSET_1 9 +#define NVM_PBA_PTR_GUARD 0xFAFA #define NVM_RESERVED_WORD 0xFFFF #define NVM_PHY_CLASS_A 0x8000 #define NVM_SERDES_AMPLITUDE_MASK 0x000F @@ -1422,6 +1456,7 @@ #define BME1000_E_PHY_ID_R2 0x01410CB1 #define I82577_E_PHY_ID 0x01540050 #define I82578_E_PHY_ID 0x004DD040 +#define I82579_E_PHY_ID 0x01540090 #define I82580_I_PHY_ID 0x015403A0 #define IGP04E1000_E_PHY_ID 0x02A80391 #define M88_VENDOR 0x0141 @@ -1622,6 +1657,7 @@ #define E1000_MDIC_READY 0x10000000 #define E1000_MDIC_INT_EN 0x20000000 #define E1000_MDIC_ERROR 0x40000000 +#define E1000_MDIC_DEST 0x80000000 /* SerDes Control */ #define E1000_GEN_CTL_READY 0x80000000 @@ -1683,4 +1719,5 @@ #define E1000_PCIEMISC_LX_DECISION 0x00000080 /* Lx power decision based on DMA coal */ + #endif /* _E1000_DEFINES_H_ */ diff --git a/sys/dev/e1000/e1000_hw.h b/sys/dev/e1000/e1000_hw.h index b494074308c..ca9c97d7b03 100644 --- a/sys/dev/e1000/e1000_hw.h +++ b/sys/dev/e1000/e1000_hw.h @@ -120,17 +120,22 @@ struct e1000_hw; #define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC #define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD #define E1000_DEV_ID_ICH10_R_BM_V 0x10CE +#define E1000_DEV_ID_ICH10_HANKSVILLE 0xF0FE #define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE #define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF +#define E1000_DEV_ID_ICH10_D_BM_V 0x1525 #define E1000_DEV_ID_PCH_M_HV_LM 0x10EA #define E1000_DEV_ID_PCH_M_HV_LC 0x10EB #define E1000_DEV_ID_PCH_D_HV_DM 0x10EF #define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 +#define E1000_DEV_ID_PCH2_LV_LM 0x1502 +#define E1000_DEV_ID_PCH2_LV_V 0x1503 #define E1000_DEV_ID_82576 0x10C9 #define E1000_DEV_ID_82576_FIBER 0x10E6 #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 +#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526 #define E1000_DEV_ID_82576_NS 0x150A #define E1000_DEV_ID_82576_NS_SERDES 0x1518 #define E1000_DEV_ID_82576_SERDES_QUAD 0x150D @@ -144,6 +149,7 @@ struct e1000_hw; #define E1000_DEV_ID_82580_SERDES 0x1510 #define E1000_DEV_ID_82580_SGMII 0x1511 #define E1000_DEV_ID_82580_COPPER_DUAL 0x1516 +#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527 #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 @@ -184,6 +190,7 @@ enum e1000_mac_type { e1000_ich9lan, e1000_ich10lan, e1000_pchlan, + e1000_pch2lan, e1000_82575, e1000_82576, e1000_82580, @@ -228,6 +235,7 @@ enum e1000_phy_type { e1000_phy_bm, e1000_phy_82578, e1000_phy_82577, + e1000_phy_82579, e1000_phy_82580, e1000_phy_vf, }; @@ -316,6 +324,9 @@ enum e1000_serdes_link_state { e1000_serdes_link_forced_up }; +#define __le16 u16 +#define __le32 u32 +#define __le64 u64 /* Receive Descriptor */ struct e1000_rx_desc { __le64 buffer_addr; /* Address of the descriptor's data buffer */ @@ -799,6 +810,34 @@ struct e1000_fc_info { enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ }; +struct e1000_mbx_operations { + s32 (*init_params)(struct e1000_hw *hw); + s32 (*read)(struct e1000_hw *, u32 *, u16, u16); + s32 (*write)(struct e1000_hw *, u32 *, u16, u16); + s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16); + s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16); + s32 (*check_for_msg)(struct e1000_hw *, u16); + s32 (*check_for_ack)(struct e1000_hw *, u16); + s32 (*check_for_rst)(struct e1000_hw *, u16); +}; + +struct e1000_mbx_stats { + u32 msgs_tx; + u32 msgs_rx; + + u32 acks; + u32 reqs; + u32 rsts; +}; + +struct e1000_mbx_info { + struct e1000_mbx_operations ops; + struct e1000_mbx_stats stats; + u32 timeout; + u32 usec_delay; + u16 size; +}; + struct e1000_dev_spec_82541 { enum e1000_dsp_config dsp_config; enum e1000_ffe_config ffe_config; @@ -819,6 +858,7 @@ struct e1000_dev_spec_82543 { struct e1000_dev_spec_82571 { bool laa_is_present; u32 smb_counter; + E1000_MUTEX swflag_mutex; }; struct e1000_dev_spec_80003es2lan { @@ -838,33 +878,7 @@ struct e1000_dev_spec_ich8lan { E1000_MUTEX nvm_mutex; E1000_MUTEX swflag_mutex; bool nvm_k1_enabled; -}; - -struct e1000_mbx_operations { - s32 (*init_params)(struct e1000_hw *hw); - s32 (*read)(struct e1000_hw *, u32 *, u16, u16); - s32 (*write)(struct e1000_hw *, u32 *, u16, u16); - s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16); - s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16); - s32 (*check_for_msg)(struct e1000_hw *, u16); - s32 (*check_for_ack)(struct e1000_hw *, u16); - s32 (*check_for_rst)(struct e1000_hw *, u16); -}; - -struct e1000_mbx_stats { - u32 msgs_tx; - u32 msgs_rx; - u32 acks; - u32 reqs; - u32 rsts; -}; - -struct e1000_mbx_info { - struct e1000_mbx_operations ops; - struct e1000_mbx_stats stats; - u32 timeout; - u32 usec_delay; - u16 size; + bool eee_disable; }; struct e1000_dev_spec_82575 { @@ -877,7 +891,6 @@ struct e1000_dev_spec_vf { u32 v2p_mailbox; }; - struct e1000_hw { void *back; diff --git a/sys/dev/e1000/e1000_ich8lan.c b/sys/dev/e1000/e1000_ich8lan.c index 6b3c25d8218..fdd517233b5 100644 --- a/sys/dev/e1000/e1000_ich8lan.c +++ b/sys/dev/e1000/e1000_ich8lan.c @@ -58,6 +58,8 @@ * 82577LC Gigabit Network Connection * 82578DM Gigabit Network Connection * 82578DC Gigabit Network Connection + * 82579LM Gigabit Network Connection + * 82579V Gigabit Network Connection */ #include "e1000_api.h" @@ -71,6 +73,8 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw); static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw); static void e1000_release_nvm_ich8lan(struct e1000_hw *hw); static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); +static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); +static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw); static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw); static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); @@ -126,6 +130,8 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw); static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw); static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); +static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); +static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ /* Offset 04h HSFSTS */ @@ -177,7 +183,7 @@ union ich8_hws_flash_regacc { static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - u32 ctrl; + u32 ctrl, fwsm; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_init_phy_params_pchlan"); @@ -200,15 +206,14 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - if ((hw->mac.type == e1000_pchlan) && - (!(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID))) { - - /* - * The MAC-PHY interconnect may still be in SMBus mode - * after Sx->S0. Toggle the LANPHYPC Value bit to force - * the interconnect to PCIe mode, but only if there is no - * firmware present otherwise firmware will have done it. - */ + /* + * The MAC-PHY interconnect may still be in SMBus mode + * after Sx->S0. If the manageability engine (ME) is + * disabled, then toggle the LANPHYPC Value bit to force + * the interconnect to PCIe mode. + */ + fwsm = E1000_READ_REG(hw, E1000_FWSM); + if (!(fwsm & E1000_ICH_FWSM_FW_VALID)) { ctrl = E1000_READ_REG(hw, E1000_CTRL); ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; @@ -217,6 +222,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; E1000_WRITE_REG(hw, E1000_CTRL, ctrl); msec_delay(50); + + /* + * Gate automatic PHY configuration by hardware on + * non-managed 82579 + */ + if (hw->mac.type == e1000_pch2lan) + e1000_gate_hw_phy_config_ich8lan(hw, TRUE); } /* @@ -229,13 +241,25 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) if (ret_val) goto out; + /* Ungate automatic PHY configuration on non-managed 82579 */ + if ((hw->mac.type == e1000_pch2lan) && + !(fwsm & E1000_ICH_FWSM_FW_VALID)) { + msec_delay(10); + e1000_gate_hw_phy_config_ich8lan(hw, FALSE); + } + phy->id = e1000_phy_unknown; - ret_val = e1000_get_phy_id(hw); - if (ret_val) - goto out; - if ((phy->id == 0) || (phy->id == PHY_REVISION_MASK)) { + switch (hw->mac.type) { + default: + ret_val = e1000_get_phy_id(hw); + if (ret_val) + goto out; + if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) + break; + /* fall-through */ + case e1000_pch2lan: /* - * In case the PHY needs to be in mdio slow mode (eg. 82577), + * In case the PHY needs to be in mdio slow mode, * set slow mode and try to get the PHY id again. */ ret_val = e1000_set_mdio_slow_mode_hv(hw); @@ -244,11 +268,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) ret_val = e1000_get_phy_id(hw); if (ret_val) goto out; + break; } phy->type = e1000_get_phy_type_from_id(phy->id); switch (phy->type) { case e1000_phy_82577: + case e1000_phy_82579: phy->ops.check_polarity = e1000_check_polarity_82577; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577; @@ -485,8 +511,6 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan; /* check for link */ mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan; - /* check management mode */ - mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* link info */ mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan; /* multicast address update */ @@ -499,6 +523,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: + /* check management mode */ + mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; /* ID LED init */ mac->ops.id_led_init = e1000_id_led_init_generic; /* blink LED */ @@ -511,10 +537,16 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) mac->ops.led_on = e1000_led_on_ich8lan; mac->ops.led_off = e1000_led_off_ich8lan; break; + case e1000_pch2lan: + mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; + mac->ops.rar_set = e1000_rar_set_pch2lan; + /* fall-through */ case e1000_pchlan: /* save PCH revision_id */ e1000_read_pci_cfg(hw, 0x2, &pci_cfg); hw->revision_id = (u8)(pci_cfg &= 0x000F); + /* check management mode */ + mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; /* ID LED init */ mac->ops.id_led_init = e1000_id_led_init_pchlan; /* setup LED */ @@ -533,9 +565,45 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) if (mac->type == e1000_ich8lan) e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE); + /* Gate automatic PHY configuration by hardware on managed 82579 */ + if ((mac->type == e1000_pch2lan) && + (E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) + e1000_gate_hw_phy_config_ich8lan(hw, TRUE); + return E1000_SUCCESS; } +/** + * e1000_set_eee_pchlan - Enable/disable EEE support + * @hw: pointer to the HW structure + * + * Enable/disable EEE based on setting in dev_spec structure. The bits in + * the LPI Control register will remain set only if/when link is up. + **/ +static s32 e1000_set_eee_pchlan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 phy_reg; + + DEBUGFUNC("e1000_set_eee_pchlan"); + + if (hw->phy.type != e1000_phy_82579) + goto out; + + ret_val = hw->phy.ops.read_reg(hw, I82579_LPI_CTRL, &phy_reg); + if (ret_val) + goto out; + + if (hw->dev_spec.ich8lan.eee_disable) + phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK; + else + phy_reg |= I82579_LPI_CTRL_ENABLE_MASK; + + ret_val = hw->phy.ops.write_reg(hw, I82579_LPI_CTRL, phy_reg); +out: + return ret_val; +} + /** * e1000_check_for_copper_link_ich8lan - Check for link (Copper) * @hw: pointer to the HW structure @@ -589,12 +657,23 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) goto out; } + if (hw->mac.type == e1000_pch2lan) { + ret_val = e1000_k1_workaround_lv(hw); + if (ret_val) + goto out; + } + /* * Check if there was DownShift, must be checked * immediately after link-up */ e1000_check_downshift_generic(hw); + /* Enable/Disable EEE after link up */ + ret_val = e1000_set_eee_pchlan(hw); + if (ret_val) + goto out; + /* * If we are forcing speed/duplex, then we simply return since * we have already determined whether we have link or not. @@ -644,6 +723,7 @@ void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw) hw->phy.ops.init_params = e1000_init_phy_params_ich8lan; break; case e1000_pchlan: + case e1000_pch2lan: hw->phy.ops.init_params = e1000_init_phy_params_pchlan; break; default: @@ -767,7 +847,7 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) * e1000_check_mng_mode_ich8lan - Checks management mode * @hw: pointer to the HW structure * - * This checks if the adapter has manageability enabled. + * This checks if the adapter has any manageability enabled. * This is a function pointer entry point only called by read/write * routines for the PHY and NVM parts. **/ @@ -779,8 +859,86 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) fwsm = E1000_READ_REG(hw, E1000_FWSM); - return (fwsm & E1000_FWSM_MODE_MASK) == - (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); + return (fwsm & E1000_ICH_FWSM_FW_VALID) && + ((fwsm & E1000_FWSM_MODE_MASK) == + (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); +} + +/** + * e1000_check_mng_mode_pchlan - Checks management mode + * @hw: pointer to the HW structure + * + * This checks if the adapter has iAMT enabled. + * This is a function pointer entry point only called by read/write + * routines for the PHY and NVM parts. + **/ +static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) +{ + u32 fwsm; + + DEBUGFUNC("e1000_check_mng_mode_pchlan"); + + fwsm = E1000_READ_REG(hw, E1000_FWSM); + + return (fwsm & E1000_ICH_FWSM_FW_VALID) && + (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); +} + +/** + * e1000_rar_set_pch2lan - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. For 82579, RAR[0] is the base address register that is to + * contain the MAC address but RAR[1-6] are reserved for manageability (ME). + * Use SHRA[0-3] in place of those reserved for ME. + **/ +static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + DEBUGFUNC("e1000_rar_set_pch2lan"); + + /* + * HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32) addr[0] | + ((u32) addr[1] << 8) | + ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); + + rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); + + /* If MAC address zero, no need to set the AV bit */ + if (rar_low || rar_high) + rar_high |= E1000_RAH_AV; + + if (index == 0) { + E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); + E1000_WRITE_FLUSH(hw); + E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); + E1000_WRITE_FLUSH(hw); + return; + } + + if (index < hw->mac.rar_entry_count) { + E1000_WRITE_REG(hw, E1000_SHRAL(index - 1), rar_low); + E1000_WRITE_FLUSH(hw); + E1000_WRITE_REG(hw, E1000_SHRAH(index - 1), rar_high); + E1000_WRITE_FLUSH(hw); + + /* verify the register updates */ + if ((E1000_READ_REG(hw, E1000_SHRAL(index - 1)) == rar_low) && + (E1000_READ_REG(hw, E1000_SHRAH(index - 1)) == rar_high)) + return; + + DEBUGOUT2("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", + (index - 1), E1000_READ_REG(hw, E1000_FWSM)); + } + + DEBUGOUT1("Failed to write receive address at index %d\n", index); } /** @@ -806,6 +964,34 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) : E1000_BLK_PHY_RESET; } +/** + * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states + * @hw: pointer to the HW structure + * + * Assumes semaphore already acquired. + * + **/ +static s32 e1000_write_smbus_addr(struct e1000_hw *hw) +{ + u16 phy_data; + u32 strap = E1000_READ_REG(hw, E1000_STRAP); + s32 ret_val = E1000_SUCCESS; + + strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; + + ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data); + if (ret_val) + goto out; + + phy_data &= ~HV_SMB_ADDR_MASK; + phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); + phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; + ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); + +out: + return ret_val; +} + /** * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration * @hw: pointer to the HW structure @@ -820,13 +1006,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) s32 ret_val = E1000_SUCCESS; u16 word_addr, reg_data, reg_addr, phy_page = 0; - if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) && - !(hw->mac.type == e1000_pchlan)) - return ret_val; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; + DEBUGFUNC("e1000_sw_lcd_config_ich8lan"); /* * Initialize the PHY from the NVM on ICH platforms. This @@ -835,27 +1015,42 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) * Therefore, after each PHY reset, we will load the * configuration data out of the NVM manually. */ - if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || - (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || - (hw->mac.type == e1000_pchlan)) + switch (hw->mac.type) { + case e1000_ich8lan: + if (phy->type != e1000_phy_igp_3) + return ret_val; + + if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_AMT) || + (hw->device_id == E1000_DEV_ID_ICH8_IGP_C)) { + sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + break; + } + /* Fall-thru */ + case e1000_pchlan: + case e1000_pch2lan: sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; - else - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; + break; + default: + return ret_val; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; data = E1000_READ_REG(hw, E1000_FEXTNVM); if (!(data & sw_cfg_mask)) goto out; - /* Wait for basic configuration completes before proceeding */ - e1000_lan_init_done_ich8lan(hw); - /* * Make sure HW does not configure LCD from PHY * extended configuration before SW configuration */ data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto out; + if (!(hw->mac.type == e1000_pch2lan)) { + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + } cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE); cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; @@ -866,20 +1061,16 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && - (hw->mac.type == e1000_pchlan)) { + if ((!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && + (hw->mac.type == e1000_pchlan)) || + (hw->mac.type == e1000_pch2lan)) { /* * HW configures the SMBus address and LEDs when the * OEM and LCD Write Enable bits are set in the NVM. * When both NVM bits are cleared, SW will configure * them instead. */ - data = E1000_READ_REG(hw, E1000_STRAP); - data &= E1000_STRAP_SMBUS_ADDRESS_MASK; - reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT; - reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; - ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, - reg_data); + ret_val = e1000_write_smbus_addr(hw); if (ret_val) goto out; @@ -1026,6 +1217,8 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) u32 reg = 0; u16 kmrn_reg = 0; + DEBUGFUNC("e1000_configure_k1_ich8lan"); + ret_val = e1000_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, &kmrn_reg); @@ -1076,16 +1269,20 @@ s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) u32 mac_reg; u16 oem_reg; - if (hw->mac.type != e1000_pchlan) + DEBUGFUNC("e1000_oem_bits_config_ich8lan"); + + if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan)) return ret_val; ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); - if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) - goto out; + if (!(hw->mac.type == e1000_pch2lan)) { + mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + } mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM); if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) @@ -1130,6 +1327,8 @@ out: **/ s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) { + DEBUGFUNC("e1000_hv_phy_powerdown_workaround_ich8lan"); + if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2)) return E1000_SUCCESS; @@ -1145,6 +1344,8 @@ static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) s32 ret_val; u16 data; + DEBUGFUNC("e1000_set_mdio_slow_mode_hv"); + ret_val = hw->phy.ops.read_reg(hw, HV_KMRN_MODE_CTRL, &data); if (ret_val) return ret_val; @@ -1165,6 +1366,8 @@ static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) s32 ret_val = E1000_SUCCESS; u16 phy_data; + DEBUGFUNC("e1000_hv_phy_workarounds_ich8lan"); + if (hw->mac.type != e1000_pchlan) goto out; @@ -1293,6 +1496,336 @@ out: return ret_val; } +/** + * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY + * @hw: pointer to the HW structure + **/ +void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw) +{ + u32 mac_reg; + u16 i; + + DEBUGFUNC("e1000_copy_rx_addrs_to_phy_ich8lan"); + + /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */ + for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) { + mac_reg = E1000_READ_REG(hw, E1000_RAL(i)); + hw->phy.ops.write_reg(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF)); + hw->phy.ops.write_reg(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF)); + mac_reg = E1000_READ_REG(hw, E1000_RAH(i)); + hw->phy.ops.write_reg(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF)); + hw->phy.ops.write_reg(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0x8000)); + } +} + +static u32 e1000_calc_rx_da_crc(u8 mac[]) +{ + u32 poly = 0xEDB88320; /* Polynomial for 802.3 CRC calculation */ + u32 i, j, mask, crc; + + DEBUGFUNC("e1000_calc_rx_da_crc"); + + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + crc = crc ^ mac[i]; + for (j = 8; j > 0; j--) { + mask = (crc & 1) * (-1); + crc = (crc >> 1) ^ (poly & mask); + } + } + return ~crc; +} + +/** + * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation + * with 82579 PHY + * @hw: pointer to the HW structure + * @enable: flag to enable/disable workaround when enabling/disabling jumbos + **/ +s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) +{ + s32 ret_val = E1000_SUCCESS; + u16 phy_reg, data; + u32 mac_reg; + u16 i; + + DEBUGFUNC("e1000_lv_jumbo_workaround_ich8lan"); + + if (hw->mac.type != e1000_pch2lan) + goto out; + + /* disable Rx path while enabling/disabling workaround */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 20), &phy_reg); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg | (1 << 14)); + if (ret_val) + goto out; + + if (enable) { + /* + * Write Rx addresses (rar_entry_count for RAL/H, +4 for + * SHRAL/H) and initial CRC values to the MAC + */ + for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) { + u8 mac_addr[ETH_ADDR_LEN] = {0}; + u32 addr_high, addr_low; + + addr_high = E1000_READ_REG(hw, E1000_RAH(i)); + if (!(addr_high & E1000_RAH_AV)) + continue; + addr_low = E1000_READ_REG(hw, E1000_RAL(i)); + mac_addr[0] = (addr_low & 0xFF); + mac_addr[1] = ((addr_low >> 8) & 0xFF); + mac_addr[2] = ((addr_low >> 16) & 0xFF); + mac_addr[3] = ((addr_low >> 24) & 0xFF); + mac_addr[4] = (addr_high & 0xFF); + mac_addr[5] = ((addr_high >> 8) & 0xFF); + + E1000_WRITE_REG(hw, E1000_PCH_RAICC(i), + e1000_calc_rx_da_crc(mac_addr)); + } + + /* Write Rx addresses to the PHY */ + e1000_copy_rx_addrs_to_phy_ich8lan(hw); + + /* Enable jumbo frame workaround in the MAC */ + mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); + mac_reg &= ~(1 << 14); + mac_reg |= (7 << 15); + E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); + + mac_reg = E1000_READ_REG(hw, E1000_RCTL); + mac_reg |= E1000_RCTL_SECRC; + E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); + + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_CTRL_OFFSET, + &data); + if (ret_val) + goto out; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_CTRL_OFFSET, + data | (1 << 0)); + if (ret_val) + goto out; + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_HD_CTRL, + &data); + if (ret_val) + goto out; + data &= ~(0xF << 8); + data |= (0xB << 8); + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_HD_CTRL, + data); + if (ret_val) + goto out; + + /* Enable jumbo frame workaround in the PHY */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); + data &= ~(0x7F << 5); + data |= (0x37 << 5); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); + data &= ~(1 << 13); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); + data &= ~(0x3FF << 2); + data |= (0x1A << 2); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); + if (ret_val) + goto out; + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0xFE00); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); + ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data | (1 << 10)); + if (ret_val) + goto out; + } else { + /* Write MAC register values back to h/w defaults */ + mac_reg = E1000_READ_REG(hw, E1000_FFLT_DBG); + mac_reg &= ~(0xF << 14); + E1000_WRITE_REG(hw, E1000_FFLT_DBG, mac_reg); + + mac_reg = E1000_READ_REG(hw, E1000_RCTL); + mac_reg &= ~E1000_RCTL_SECRC; + E1000_WRITE_REG(hw, E1000_RCTL, mac_reg); + + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_CTRL_OFFSET, + &data); + if (ret_val) + goto out; + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_CTRL_OFFSET, + data & ~(1 << 0)); + if (ret_val) + goto out; + ret_val = e1000_read_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_HD_CTRL, + &data); + if (ret_val) + goto out; + data &= ~(0xF << 8); + data |= (0xB << 8); + ret_val = e1000_write_kmrn_reg_generic(hw, + E1000_KMRNCTRLSTA_HD_CTRL, + data); + if (ret_val) + goto out; + + /* Write PHY register values back to h/w defaults */ + hw->phy.ops.read_reg(hw, PHY_REG(769, 23), &data); + data &= ~(0x7F << 5); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 23), data); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, PHY_REG(769, 16), &data); + data |= (1 << 13); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 16), data); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, PHY_REG(776, 20), &data); + data &= ~(0x3FF << 2); + data |= (0x8 << 2); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 20), data); + if (ret_val) + goto out; + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(776, 23), 0x7E00); + if (ret_val) + goto out; + hw->phy.ops.read_reg(hw, HV_PM_CTRL, &data); + ret_val = hw->phy.ops.write_reg(hw, HV_PM_CTRL, data & ~(1 << 10)); + if (ret_val) + goto out; + } + + /* re-enable Rx path after enabling/disabling workaround */ + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14)); + +out: + return ret_val; +} + +/** + * e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + **/ +static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan"); + + if (hw->mac.type != e1000_pch2lan) + goto out; + + /* Set MDIO slow mode before any other MDIO access */ + ret_val = e1000_set_mdio_slow_mode_hv(hw); + +out: + return ret_val; +} + +/** + * e1000_k1_gig_workaround_lv - K1 Si workaround + * @hw: pointer to the HW structure + * + * Workaround to set the K1 beacon duration for 82579 parts + **/ +static s32 e1000_k1_workaround_lv(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 status_reg = 0; + u32 mac_reg; + + DEBUGFUNC("e1000_k1_workaround_lv"); + + if (hw->mac.type != e1000_pch2lan) + goto out; + + /* Set K1 beacon duration based on 1Gbps speed or otherwise */ + ret_val = hw->phy.ops.read_reg(hw, HV_M_STATUS, &status_reg); + if (ret_val) + goto out; + + if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) + == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) { + mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM4); + mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; + + if (status_reg & HV_M_STATUS_SPEED_1000) + mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; + else + mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; + + E1000_WRITE_REG(hw, E1000_FEXTNVM4, mac_reg); + } + +out: + return ret_val; +} + +/** + * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware + * @hw: pointer to the HW structure + * @gate: boolean set to TRUE to gate, FALSE to un-gate + * + * Gate/ungate the automatic PHY configuration via hardware; perform + * the configuration via software instead. + **/ +static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) +{ + u32 extcnf_ctrl; + + DEBUGFUNC("e1000_gate_hw_phy_config_ich8lan"); + + if (hw->mac.type != e1000_pch2lan) + return; + + extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL); + + if (gate) + extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; + else + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; + + E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl); + return; +} + +/** + * e1000_hv_phy_tuning_workaround_ich8lan - This is a Phy tuning work around + * needed for Nahum3 + Hanksville testing, requested by HW team + **/ +static s32 e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + + DEBUGFUNC("e1000_hv_phy_tuning_workaround_ich8lan"); + + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF); + +out: + return ret_val; +} + /** * e1000_lan_init_done_ich8lan - Check for PHY config completion * @hw: pointer to the HW structure @@ -1327,6 +1860,68 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_STATUS, data); } +/** + * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset + * @hw: pointer to the HW structure + **/ +static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) +{ + s32 ret_val = E1000_SUCCESS; + u16 reg; + + DEBUGFUNC("e1000_post_phy_reset_ich8lan"); + + if (hw->phy.ops.check_reset_block(hw)) + goto out; + + /* Allow time for h/w to get to quiescent state after reset */ + msec_delay(10); + + /* Perform any necessary post-reset workarounds */ + switch (hw->mac.type) { + case e1000_pchlan: + ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ret_val) + goto out; + break; + case e1000_pch2lan: + ret_val = e1000_lv_phy_workarounds_ich8lan(hw); + if (ret_val) + goto out; + break; + default: + break; + } + + if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) { + ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw); + if (ret_val) + goto out; + } + + /* Dummy read to clear the phy wakeup bit after lcd reset */ + if (hw->mac.type >= e1000_pchlan) + hw->phy.ops.read_reg(hw, BM_WUC, ®); + + /* Configure the LCD with the extended configuration region in NVM */ + ret_val = e1000_sw_lcd_config_ich8lan(hw); + if (ret_val) + goto out; + + /* Configure the LCD with the OEM bits in NVM */ + ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); + + /* Ungate automatic PHY configuration on non-managed 82579 */ + if ((hw->mac.type == e1000_pch2lan) && + !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) { + msec_delay(10); + e1000_gate_hw_phy_config_ich8lan(hw, FALSE); + } + +out: + return ret_val; +} + /** * e1000_phy_hw_reset_ich8lan - Performs a PHY reset * @hw: pointer to the HW structure @@ -1338,39 +1933,19 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; - u16 reg; DEBUGFUNC("e1000_phy_hw_reset_ich8lan"); + /* Gate automatic PHY configuration by hardware on non-managed 82579 */ + if ((hw->mac.type == e1000_pch2lan) && + !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) + e1000_gate_hw_phy_config_ich8lan(hw, TRUE); + ret_val = e1000_phy_hw_reset_generic(hw); if (ret_val) goto out; - /* Allow time for h/w to get to a quiescent state after reset */ - msec_delay(10); - - /* Perform any necessary post-reset workarounds */ - switch (hw->mac.type) { - case e1000_pchlan: - ret_val = e1000_hv_phy_workarounds_ich8lan(hw); - if (ret_val) - goto out; - break; - default: - break; - } - - /* Dummy read to clear the phy wakeup bit after lcd reset */ - if (hw->mac.type == e1000_pchlan) - hw->phy.ops.read_reg(hw, BM_WUC, ®); - - /* Configure the LCD with the extended configuration region in NVM */ - ret_val = e1000_sw_lcd_config_ich8lan(hw); - if (ret_val) - goto out; - - /* Configure the LCD with the OEM bits in NVM */ - ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); + ret_val = e1000_post_phy_reset_ich8lan(hw); out: return ret_val; @@ -1621,6 +2196,8 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) u8 sig_byte = 0; s32 ret_val = E1000_SUCCESS; + DEBUGFUNC("e1000_valid_nvm_bank_detect_ich8lan"); + switch (hw->mac.type) { case e1000_ich8lan: case e1000_ich9lan: @@ -2670,20 +3247,21 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ctrl = E1000_READ_REG(hw, E1000_CTRL); - if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) { - /* Clear PHY Reset Asserted bit */ - if (hw->mac.type >= e1000_pchlan) { - u32 status = E1000_READ_REG(hw, E1000_STATUS); - E1000_WRITE_REG(hw, E1000_STATUS, status & - ~E1000_STATUS_PHYRA); - } - + if (!hw->phy.ops.check_reset_block(hw)) { /* - * PHY HW reset requires MAC CORE reset at the same + * Full-chip reset requires MAC and PHY reset at the same * time to make sure the interface between MAC and the * external PHY is reset. */ ctrl |= E1000_CTRL_PHY_RST; + + /* + * Gate automatic PHY configuration by hardware on + * non-managed 82579 + */ + if ((hw->mac.type == e1000_pch2lan) && + !(E1000_READ_REG(hw, E1000_FWSM) & E1000_ICH_FWSM_FW_VALID)) + e1000_gate_hw_phy_config_ich8lan(hw, TRUE); } ret_val = e1000_acquire_swflag_ich8lan(hw); DEBUGOUT("Issuing a global reset to ich8lan\n"); @@ -2693,44 +3271,16 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) if (!ret_val) e1000_release_swflag_ich8lan(hw); - /* Perform any necessary post-reset workarounds */ - switch (hw->mac.type) { - case e1000_pchlan: - ret_val = e1000_hv_phy_workarounds_ich8lan(hw); + if (ctrl & E1000_CTRL_PHY_RST) { + ret_val = hw->phy.ops.get_cfg_done(hw); + if (ret_val) + goto out; + + ret_val = e1000_post_phy_reset_ich8lan(hw); if (ret_val) goto out; - break; - default: - break; } - if (ctrl & E1000_CTRL_PHY_RST) - ret_val = hw->phy.ops.get_cfg_done(hw); - - if (hw->mac.type >= e1000_ich10lan) { - e1000_lan_init_done_ich8lan(hw); - } else { - ret_val = e1000_get_auto_rd_done_generic(hw); - if (ret_val) { - /* - * When auto config read does not complete, do not - * return with an error. This can happen in situations - * where there is no eeprom and prevents getting link. - */ - DEBUGOUT("Auto Read Done did not complete\n"); - } - } - /* Dummy read to clear the phy wakeup bit after lcd reset */ - if (hw->mac.type == e1000_pchlan) - hw->phy.ops.read_reg(hw, BM_WUC, ®); - - ret_val = e1000_sw_lcd_config_ich8lan(hw); - if (ret_val) - goto out; - - ret_val = e1000_oem_bits_config_ich8lan(hw, TRUE); - if (ret_val) - goto out; /* * For PCH, this write will make sure that any noise * will be detected as a CRC error and be dropped rather than show up @@ -2948,7 +3498,10 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82579) || (hw->phy.type == e1000_phy_82577)) { + E1000_WRITE_REG(hw, E1000_FCRTV_PCH, hw->fc.refresh_time); + ret_val = hw->phy.ops.write_reg(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27), hw->fc.pause_time); @@ -3017,6 +3570,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) goto out; break; case e1000_phy_82577: + case e1000_phy_82579: ret_val = e1000_copper_link_setup_82577(hw); if (ret_val) goto out; @@ -3300,21 +3854,21 @@ out: void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw) { u32 phy_ctrl; + s32 ret_val; - switch (hw->mac.type) { - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - case e1000_pchlan: - phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); - phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | - E1000_PHY_CTRL_GBE_DISABLE; - E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + DEBUGFUNC("e1000_disable_gig_wol_ich8lan"); - if (hw->mac.type == e1000_pchlan) - e1000_phy_hw_reset_ich8lan(hw); - default: - break; + phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL); + phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE; + E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl); + + if (hw->mac.type >= e1000_pchlan) { + e1000_oem_bits_config_ich8lan(hw, FALSE); + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return; + e1000_write_smbus_addr(hw); + hw->phy.ops.release(hw); } return; @@ -3469,32 +4023,50 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw) } /** - * e1000_get_cfg_done_ich8lan - Read config done bit + * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset * @hw: pointer to the HW structure * - * Read the management control register for the config done bit for - * completion status. NOTE: silicon which is EEPROM-less will fail trying - * to read the config done bit, so an error is *ONLY* logged and returns - * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon - * would not be able to be reset or change link. + * Read appropriate register for the config done bit for completion status + * and configure the PHY through s/w for EEPROM-less parts. + * + * NOTE: some silicon which is EEPROM-less will fail trying to read the + * config done bit, so only an error is logged and continues. If we were + * to return with error, EEPROM-less silicon would not be able to be reset + * or change link. **/ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; u32 bank = 0; + u32 status; - if (hw->mac.type >= e1000_pchlan) { - u32 status = E1000_READ_REG(hw, E1000_STATUS); - - if (status & E1000_STATUS_PHYRA) - E1000_WRITE_REG(hw, E1000_STATUS, status & - ~E1000_STATUS_PHYRA); - else - DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); - } + DEBUGFUNC("e1000_get_cfg_done_ich8lan"); e1000_get_cfg_done_generic(hw); + /* Wait for indication from h/w that it has completed basic config */ + if (hw->mac.type >= e1000_ich10lan) { + e1000_lan_init_done_ich8lan(hw); + } else { + ret_val = e1000_get_auto_rd_done_generic(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + DEBUGOUT("Auto Read Done did not complete\n"); + ret_val = E1000_SUCCESS; + } + } + + /* Clear PHY Reset Asserted bit */ + status = E1000_READ_REG(hw, E1000_STATUS); + if (status & E1000_STATUS_PHYRA) + E1000_WRITE_REG(hw, E1000_STATUS, status & ~E1000_STATUS_PHYRA); + else + DEBUGOUT("PHY Reset Asserted not set - needs delay\n"); + /* If EEPROM is not marked present, init the IGP 3 PHY manually */ if (hw->mac.type <= e1000_ich9lan) { if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && @@ -3560,6 +4132,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) /* Clear PHY statistics registers */ if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82579) || (hw->phy.type == e1000_phy_82577)) { hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data); hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data); diff --git a/sys/dev/e1000/e1000_ich8lan.h b/sys/dev/e1000/e1000_ich8lan.h index f26b7b9f70a..2935af5689e 100644 --- a/sys/dev/e1000/e1000_ich8lan.h +++ b/sys/dev/e1000/e1000_ich8lan.h @@ -70,6 +70,23 @@ #define E1000_ICH_MNG_IAMT_MODE 0x2 +#define E1000_FWSM_PROXY_MODE 0x00000008 /* FW is in proxy mode */ + +/* Shared Receive Address Registers */ +#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8)) +#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8)) +#define E1000_SHRAH_AV 0x80000000 /* Addr Valid bit */ +#define E1000_SHRAH_MAV 0x40000000 /* Multicast Addr Valid bit */ + +#define E1000_H2ME 0x05B50 /* Host to ME */ +#define E1000_H2ME_LSECREQ 0x00000001 /* Linksec Request */ +#define E1000_H2ME_LSECA 0x00000002 /* Linksec Active */ +#define E1000_H2ME_LSECSF 0x00000004 /* Linksec Failed */ +#define E1000_H2ME_LSECD 0x00000008 /* Linksec Disabled */ +#define E1000_H2ME_SLCAPD 0x00000010 /* Start LCAPD */ +#define E1000_H2ME_IPV4_ARP_EN 0x00000020 /* Arp Offload enable bit */ +#define E1000_H2ME_IPV6_NS_EN 0x00000040 /* NS Offload enable bit */ + #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ (ID_LED_OFF1_OFF2 << 8) | \ (ID_LED_OFF1_ON2 << 4) | \ @@ -85,9 +102,14 @@ #define E1000_FEXTNVM_SW_CONFIG 1 #define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */ +#define E1000_FEXTNVM4_BEACON_DURATION_MASK 0x7 +#define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7 +#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3 + #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 +#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */ #define PHY_PAGE_SHIFT 5 #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ @@ -112,6 +134,14 @@ #define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) #define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) #define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) +#define BM_IPAV (BM_PHY_REG(BM_WUC_PAGE, 64)) +#define BM_IP4AT_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 82 + ((_i) * 2))) +#define BM_IP4AT_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 83 + ((_i) * 2))) + +#define BM_SHRAL_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 44 + ((_i) * 4))) +#define BM_SHRAL_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 45 + ((_i) * 4))) +#define BM_SHRAH_LOWER(_i) (BM_PHY_REG(BM_WUC_PAGE, 46 + ((_i) * 4))) +#define BM_SHRAH_UPPER(_i) (BM_PHY_REG(BM_WUC_PAGE, 47 + ((_i) * 4))) #define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ #define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ @@ -147,6 +177,7 @@ /* SMBus Address Phy Register */ #define HV_SMB_ADDR PHY_REG(768, 26) +#define HV_SMB_ADDR_MASK 0x007F #define HV_SMB_ADDR_PEC_EN 0x0200 #define HV_SMB_ADDR_VALID 0x0080 @@ -172,6 +203,10 @@ #define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */ +/* PHY Low Power Idle Control */ +#define I82579_LPI_CTRL PHY_REG(772, 20) +#define I82579_LPI_CTRL_ENABLE_MASK 0x6000 + /* * Additional interrupts need to be handled for ICH family: * DSW = The FW changed the status of the DISSW bit in FWSM @@ -195,6 +230,9 @@ #define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000 #define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000 +/* Receive Address Initial CRC Calculation */ +#define E1000_PCH_RAICC(_n) (0x05F50 + ((_n) * 4)) + void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, bool state); void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); @@ -203,4 +241,6 @@ void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw); s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config); s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); +void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); +s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); #endif diff --git a/sys/dev/e1000/e1000_mac.c b/sys/dev/e1000/e1000_mac.c index d4d2bec27bd..121667104e3 100644 --- a/sys/dev/e1000/e1000_mac.c +++ b/sys/dev/e1000/e1000_mac.c @@ -395,6 +395,16 @@ s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) DEBUGFUNC("e1000_check_alt_mac_addr_generic"); + ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &nvm_data); + if (ret_val) + goto out; + + /* Check for LOM (vs. NIC) or one of two valid mezzanine cards */ + if (!((nvm_data & NVM_COMPAT_LOM) || + (hw->device_id == E1000_DEV_ID_82571EB_SERDES_DUAL) || + (hw->device_id == E1000_DEV_ID_82571EB_SERDES_QUAD))) + goto out; + ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, &nvm_alt_mac_addr_offset); if (ret_val) { diff --git a/sys/dev/e1000/e1000_nvm.c b/sys/dev/e1000/e1000_nvm.c index 83557ef9650..05c79319377 100644 --- a/sys/dev/e1000/e1000_nvm.c +++ b/sys/dev/e1000/e1000_nvm.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -774,6 +774,184 @@ out: return ret_val; } +/** + * e1000_read_pba_string_generic - Read device part number + * @hw: pointer to the HW structure + * @pba_num: pointer to device part number + * @pba_num_size: size of part number buffer + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in pba_num. + **/ +s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num, + u32 pba_num_size) +{ + s32 ret_val; + u16 nvm_data; + u16 pba_ptr; + u16 offset; + u16 length; + + DEBUGFUNC("e1000_read_pba_string_generic"); + + if (pba_num == NULL) { + DEBUGOUT("PBA string buffer was null\n"); + ret_val = E1000_ERR_INVALID_ARGUMENT; + goto out; + } + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + /* + * if nvm_data is not ptr guard the PBA must be in legacy format which + * means pba_ptr is actually our second data word for the PBA number + * and we can decode it into an ascii string + */ + if (nvm_data != NVM_PBA_PTR_GUARD) { + DEBUGOUT("NVM PBA number is not stored as string\n"); + + /* we will need 11 characters to store the PBA */ + if (pba_num_size < 11) { + DEBUGOUT("PBA string buffer too small\n"); + return E1000_ERR_NO_SPACE; + } + + /* extract hex string from data and pba_ptr */ + pba_num[0] = (nvm_data >> 12) & 0xF; + pba_num[1] = (nvm_data >> 8) & 0xF; + pba_num[2] = (nvm_data >> 4) & 0xF; + pba_num[3] = nvm_data & 0xF; + pba_num[4] = (pba_ptr >> 12) & 0xF; + pba_num[5] = (pba_ptr >> 8) & 0xF; + pba_num[6] = '-'; + pba_num[7] = 0; + pba_num[8] = (pba_ptr >> 4) & 0xF; + pba_num[9] = pba_ptr & 0xF; + + /* put a null character on the end of our string */ + pba_num[10] = '\0'; + + /* switch all the data but the '-' to hex char */ + for (offset = 0; offset < 10; offset++) { + if (pba_num[offset] < 0xA) + pba_num[offset] += '0'; + else if (pba_num[offset] < 0x10) + pba_num[offset] += 'A' - 0xA; + } + + goto out; + } + + ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if (length == 0xFFFF || length == 0) { + DEBUGOUT("NVM PBA number section invalid length\n"); + ret_val = E1000_ERR_NVM_PBA_SECTION; + goto out; + } + /* check if pba_num buffer is big enough */ + if (pba_num_size < (((u32)length * 2) - 1)) { + DEBUGOUT("PBA string buffer too small\n"); + ret_val = E1000_ERR_NO_SPACE; + goto out; + } + + /* trim pba length from start of string */ + pba_ptr++; + length--; + + for (offset = 0; offset < length; offset++) { + ret_val = hw->nvm.ops.read(hw, pba_ptr + offset, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + pba_num[offset * 2] = (u8)(nvm_data >> 8); + pba_num[(offset * 2) + 1] = (u8)(nvm_data & 0xFF); + } + pba_num[offset * 2] = '\0'; + +out: + return ret_val; +} + +/** + * e1000_read_pba_length_generic - Read device part number length + * @hw: pointer to the HW structure + * @pba_num_size: size of part number buffer + * + * Reads the product board assembly (PBA) number length from the EEPROM and + * stores the value in pba_num_size. + **/ +s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size) +{ + s32 ret_val; + u16 nvm_data; + u16 pba_ptr; + u16 length; + + DEBUGFUNC("e1000_read_pba_length_generic"); + + if (pba_num_size == NULL) { + DEBUGOUT("PBA buffer size was null\n"); + ret_val = E1000_ERR_INVALID_ARGUMENT; + goto out; + } + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &pba_ptr); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + /* if data is not ptr guard the PBA must be in legacy format */ + if (nvm_data != NVM_PBA_PTR_GUARD) { + *pba_num_size = 11; + goto out; + } + + ret_val = hw->nvm.ops.read(hw, pba_ptr, 1, &length); + if (ret_val) { + DEBUGOUT("NVM Read Error\n"); + goto out; + } + + if (length == 0xFFFF || length == 0) { + DEBUGOUT("NVM PBA number section invalid length\n"); + ret_val = E1000_ERR_NVM_PBA_SECTION; + goto out; + } + + /* + * Convert from length in u16 values to u8 chars, add 1 for NULL, + * and subtract 2 because length field is included in length. + */ + *pba_num_size = ((u32)length * 2) - 1; + +out: + return ret_val; +} + /** * e1000_read_pba_num_generic - Read device part number * @hw: pointer to the HW structure @@ -793,6 +971,10 @@ s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) if (ret_val) { DEBUGOUT("NVM Read Error\n"); goto out; + } else if (nvm_data == NVM_PBA_PTR_GUARD) { + DEBUGOUT("NVM Not Supported\n"); + ret_val = E1000_NOT_IMPLEMENTED; + goto out; } *pba_num = (u32)(nvm_data << 16); @@ -880,7 +1062,7 @@ out: **/ s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw) { - s32 ret_val; + s32 ret_val; u16 checksum = 0; u16 i, nvm_data; diff --git a/sys/dev/e1000/e1000_nvm.h b/sys/dev/e1000/e1000_nvm.h index 974c407b41f..36ee4448ff7 100644 --- a/sys/dev/e1000/e1000_nvm.h +++ b/sys/dev/e1000/e1000_nvm.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2009, Intel Corporation + Copyright (c) 2001-2010, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -45,6 +45,9 @@ s32 e1000_acquire_nvm_generic(struct e1000_hw *hw); s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); +s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num, + u32 pba_num_size); +s32 e1000_read_pba_length_generic(struct e1000_hw *hw, u32 *pba_num_size); s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); diff --git a/sys/dev/e1000/e1000_phy.c b/sys/dev/e1000/e1000_phy.c index 24ca36f6ebb..fb666233a12 100644 --- a/sys/dev/e1000/e1000_phy.c +++ b/sys/dev/e1000/e1000_phy.c @@ -281,6 +281,13 @@ s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) goto out; } *data = (u16) mdic; + + /* + * Allow some time after each MDIC transaction to avoid + * reading duplicate data in the next MDIC transaction. + */ + if (hw->mac.type == e1000_pch2lan) + usec_delay(100); out: return ret_val; @@ -345,6 +352,13 @@ s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) goto out; } + /* + * Allow some time after each MDIC transaction to avoid + * reading duplicate data in the next MDIC transaction. + */ + if (hw->mac.type == e1000_pch2lan) + usec_delay(100); + out: return ret_val; } @@ -868,9 +882,10 @@ s32 e1000_copper_link_setup_m88(struct e1000_hw *hw) if (ret_val) goto out; + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; /* For BM PHY this bit is downshift enable */ - if (phy->type != e1000_phy_bm) - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + if (phy->type == e1000_phy_bm) + phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX; /* * Options: @@ -2618,6 +2633,9 @@ enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) case I82577_E_PHY_ID: phy_type = e1000_phy_82577; break; + case I82579_E_PHY_ID: + phy_type = e1000_phy_82579; + break; case I82580_I_PHY_ID: phy_type = e1000_phy_82580; break; diff --git a/sys/dev/e1000/e1000_phy.h b/sys/dev/e1000/e1000_phy.h index 692cbaa91eb..c42ef6c688b 100644 --- a/sys/dev/e1000/e1000_phy.h +++ b/sys/dev/e1000/e1000_phy.h @@ -230,12 +230,14 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw); #define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 #define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 #define E1000_KMRNCTRLSTA_REN 0x00200000 +#define E1000_KMRNCTRLSTA_CTRL_OFFSET 0x1 /* Kumeran Control */ #define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ #define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ #define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ #define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ #define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 #define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 +#define E1000_KMRNCTRLSTA_HD_CTRL 0x10 /* Kumeran HD Control */ #define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 #define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ diff --git a/sys/dev/e1000/e1000_regs.h b/sys/dev/e1000/e1000_regs.h index 2cb43971db2..38ccff326ae 100644 --- a/sys/dev/e1000/e1000_regs.h +++ b/sys/dev/e1000/e1000_regs.h @@ -53,6 +53,7 @@ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FEXT 0x0002C /* Future Extended - RW */ +#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ #define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ @@ -186,6 +187,8 @@ (0x054E0 + ((_i - 16) * 8))) #define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ (0x054E4 + ((_i - 16) * 8))) +#define E1000_SHRAL(_i) (0x05438 + ((_i) * 8)) +#define E1000_SHRAH(_i) (0x0543C + ((_i) * 8)) #define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) #define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) #define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) @@ -457,6 +460,7 @@ #define E1000_VFTE 0x00C90 /* VF Transmit Enables */ #define E1000_QDE 0x02408 /* Queue Drop Enable - RW */ #define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */ +#define E1000_WVBR 0x03554 /* VM Wrong Behavior - RWS */ #define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */ #define E1000_UTA 0x0A000 /* Unicast Table Array - RW */ #define E1000_IOVTCL 0x05BBC /* IOV Control Register */ @@ -539,4 +543,6 @@ /* PCIe Parity Status Register */ #define E1000_PCIEERRSTS 0x05BA8 + + #endif diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index e520512b20f..af6100a39e9 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -93,7 +93,7 @@ int em_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char em_driver_version[] = "7.0.5"; +char em_driver_version[] = "7.0.8"; /********************************************************************* @@ -165,6 +165,7 @@ static em_vendor_info_t em_vendor_info_array[] = { 0x8086, E1000_DEV_ID_ICH10_R_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_D_BM_LM, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_ICH10_D_BM_LF, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_ICH10_D_BM_V, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_PCH_M_HV_LM, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_PCH_M_HV_LC, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_PCH_D_HV_DM, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -213,7 +214,7 @@ static int em_setup_msix(struct adapter *); static void em_free_pci_resources(struct adapter *); static void em_local_timer(void *); static void em_reset(struct adapter *); -static void em_setup_interface(device_t, struct adapter *); +static int em_setup_interface(device_t, struct adapter *); static void em_setup_transmit_structures(struct adapter *); static void em_initialize_transmit_unit(struct adapter *); @@ -237,9 +238,10 @@ static bool em_rxeof(struct rx_ring *, int, int *); static int em_fixup_rx(struct rx_ring *); #endif static void em_receive_checksum(struct e1000_rx_desc *, struct mbuf *); -static void em_transmit_checksum_setup(struct tx_ring *, struct mbuf *, - u32 *, u32 *); -static bool em_tso_setup(struct tx_ring *, struct mbuf *, u32 *, u32 *); +static void em_transmit_checksum_setup(struct tx_ring *, struct mbuf *, int, + struct ip *, u32 *, u32 *); +static void em_tso_setup(struct tx_ring *, struct mbuf *, int, struct ip *, + struct tcphdr *, u32 *, u32 *); static void em_set_promisc(struct adapter *); static void em_disable_promisc(struct adapter *); static void em_set_multi(struct adapter *); @@ -281,6 +283,8 @@ static void em_handle_link(void *context, int pending); static void em_add_rx_process_limit(struct adapter *, const char *, const char *, int *, int); +static __inline void em_rx_discard(struct rx_ring *, int); + #ifdef DEVICE_POLLING static poll_handler_t em_poll; #endif /* POLLING */ @@ -344,16 +348,8 @@ TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); static int em_debug_sbp = FALSE; TUNABLE_INT("hw.em.sbp", &em_debug_sbp); -/* Local controls for MSI/MSIX */ -#ifdef EM_MULTIQUEUE static int em_enable_msix = TRUE; -static int em_msix_queues = 2; /* for 82574, can be 1 or 2 */ -#else -static int em_enable_msix = FALSE; -static int em_msix_queues = 0; /* disable */ -#endif TUNABLE_INT("hw.em.enable_msix", &em_enable_msix); -TUNABLE_INT("hw.em.msix_queues", &em_msix_queues); /* How many packets rxeof tries to clean at a time */ static int em_rx_process_limit = 100; @@ -576,6 +572,15 @@ em_attach(device_t dev) goto err_pci; } + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(u8) * ETH_ADDR_LEN * + MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_late; + } + /* ** Start from a known state, this is ** important in reading the nvm and @@ -628,7 +633,8 @@ em_attach(device_t dev) em_get_wakeup(dev); /* Setup OS specific network interface */ - em_setup_interface(dev, adapter); + if (em_setup_interface(dev, adapter) != 0) + goto err_late; em_reset(adapter); @@ -669,8 +675,11 @@ err_late: em_free_transmit_structures(adapter); em_free_receive_structures(adapter); em_release_hw_control(adapter); + if (adapter->ifp != NULL) + if_free(adapter->ifp); err_pci: em_free_pci_resources(adapter); + free(adapter->mta, M_DEVBUF); EM_CORE_LOCK_DESTROY(adapter); return (error); @@ -736,6 +745,7 @@ em_detach(device_t dev) em_free_receive_structures(adapter); em_release_hw_control(adapter); + free(adapter->mta, M_DEVBUF); return (0); } @@ -854,21 +864,18 @@ em_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) } /* -** Multiqueue capable stack interface, this is not -** yet truely multiqueue, but that is coming... +** Multiqueue capable stack interface */ static int em_mq_start(struct ifnet *ifp, struct mbuf *m) { struct adapter *adapter = ifp->if_softc; struct tx_ring *txr; - int i, error = 0; + int i = 0, error = 0; /* Which queue to use */ if ((m->m_flags & M_FLOWID) != 0) i = m->m_pkthdr.flowid % adapter->num_queues; - else - i = curcpu % adapter->num_queues; txr = &adapter->tx_rings[i]; @@ -1451,8 +1458,7 @@ em_handle_que(void *context, int pending) more = em_rxeof(rxr, adapter->rx_process_limit, NULL); EM_TX_LOCK(txr); - if (em_txeof(txr)) - more = TRUE; + em_txeof(txr); #ifdef EM_MULTIQUEUE if (!drbr_empty(ifp, txr->br)) em_mq_start_locked(ifp, txr, NULL); @@ -1460,6 +1466,7 @@ em_handle_que(void *context, int pending) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp, txr); #endif + em_txeof(txr); EM_TX_UNLOCK(txr); if (more) { taskqueue_enqueue(adapter->tq, &adapter->que_task); @@ -1564,11 +1571,8 @@ em_handle_tx(void *context, int pending) struct adapter *adapter = txr->adapter; struct ifnet *ifp = adapter->ifp; - if (!EM_TX_TRYLOCK(txr)) - return; - + EM_TX_LOCK(txr); em_txeof(txr); - #ifdef EM_MULTIQUEUE if (!drbr_empty(ifp, txr->br)) em_mq_start_locked(ifp, txr, NULL); @@ -1576,6 +1580,7 @@ em_handle_tx(void *context, int pending) if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) em_start_locked(ifp, txr); #endif + em_txeof(txr); E1000_WRITE_REG(&adapter->hw, E1000_IMS, txr->ims); EM_TX_UNLOCK(txr); } @@ -1729,13 +1734,18 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp) struct em_buffer *tx_buffer, *tx_buffer_mapped; struct e1000_tx_desc *ctxd = NULL; struct mbuf *m_head; + struct ether_header *eh; + struct ip *ip = NULL; + struct tcphdr *tp = NULL; u32 txd_upper, txd_lower, txd_used, txd_saved; + int ip_off, poff; int nsegs, i, j, first, last = 0; int error, do_tso, tso_desc = 0; m_head = *m_headp; txd_upper = txd_lower = txd_used = txd_saved = 0; do_tso = ((m_head->m_pkthdr.csum_flags & CSUM_TSO) != 0); + ip_off = poff = 0; /* ** When doing checksum offload, it is critical to @@ -1751,15 +1761,100 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp) } /* - * TSO workaround: - * If an mbuf is only header we need - * to pull 4 bytes of data into it. + * Intel recommends entire IP/TCP header length reside in a single + * buffer. If multiple descriptors are used to describe the IP and + * TCP header, each descriptor should describe one or more + * complete headers; descriptors referencing only parts of headers + * are not supported. If all layer headers are not coalesced into + * a single buffer, each buffer should not cross a 4KB boundary, + * or be larger than the maximum read request size. + * Controller also requires modifing IP/TCP header to make TSO work + * so we firstly get a writable mbuf chain then coalesce ethernet/ + * IP/TCP header into a single buffer to meet the requirement of + * controller. This also simplifies IP/TCP/UDP checksum offloading + * which also has similiar restrictions. */ - if (do_tso && (m_head->m_len <= M_TSO_LEN)) { - m_head = m_pullup(m_head, M_TSO_LEN + 4); - *m_headp = m_head; - if (m_head == NULL) + if (do_tso || m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) { + if (do_tso || (m_head->m_next != NULL && + m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD)) { + if (M_WRITABLE(*m_headp) == 0) { + m_head = m_dup(*m_headp, M_DONTWAIT); + m_freem(*m_headp); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + *m_headp = m_head; + } + } + /* + * XXX + * Assume IPv4, we don't have TSO/checksum offload support + * for IPv6 yet. + */ + ip_off = sizeof(struct ether_header); + m_head = m_pullup(m_head, ip_off); + if (m_head == NULL) { + *m_headp = NULL; return (ENOBUFS); + } + eh = mtod(m_head, struct ether_header *); + if (eh->ether_type == htons(ETHERTYPE_VLAN)) { + ip_off = sizeof(struct ether_vlan_header); + m_head = m_pullup(m_head, ip_off); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + } + m_head = m_pullup(m_head, ip_off + sizeof(struct ip)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + ip = (struct ip *)(mtod(m_head, char *) + ip_off); + poff = ip_off + (ip->ip_hl << 2); + m_head = m_pullup(m_head, poff + sizeof(struct tcphdr)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + if (do_tso) { + tp = (struct tcphdr *)(mtod(m_head, char *) + poff); + /* + * TSO workaround: + * pull 4 more bytes of data into it. + */ + m_head = m_pullup(m_head, poff + (tp->th_off << 2) + 4); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + ip->ip_len = 0; + ip->ip_sum = 0; + /* + * The pseudo TCP checksum does not include TCP payload + * length so driver should recompute the checksum here + * what hardware expect to see. This is adherence of + * Microsoft's Large Send specification. + */ + tp->th_sum = in_pseudo(ip->ip_src.s_addr, + ip->ip_dst.s_addr, htons(IPPROTO_TCP)); + } else if (m_head->m_pkthdr.csum_flags & CSUM_TCP) { + tp = (struct tcphdr *)(mtod(m_head, char *) + poff); + m_head = m_pullup(m_head, poff + (tp->th_off << 2)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + } else if (m_head->m_pkthdr.csum_flags & CSUM_UDP) { + m_head = m_pullup(m_head, poff + sizeof(struct udphdr)); + if (m_head == NULL) { + *m_headp = NULL; + return (ENOBUFS); + } + } + *m_headp = m_head; } /* @@ -1836,16 +1931,15 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp) /* Do hardware assists */ #if __FreeBSD_version >= 700000 if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { - error = em_tso_setup(txr, m_head, &txd_upper, &txd_lower); - if (error != TRUE) - return (ENXIO); /* something foobar */ + em_tso_setup(txr, m_head, ip_off, ip, tp, &txd_upper, + &txd_lower); /* we need to make a final sentinel transmit desc */ tso_desc = TRUE; } else #endif if (m_head->m_pkthdr.csum_flags & CSUM_OFFLOAD) - em_transmit_checksum_setup(txr, m_head, - &txd_upper, &txd_lower); + em_transmit_checksum_setup(txr, m_head, + ip_off, ip, &txd_upper, &txd_lower); i = txr->next_avail_desc; @@ -1930,6 +2024,8 @@ em_xmit(struct tx_ring *txr, struct mbuf **m_headp) */ tx_buffer = &txr->tx_buffers[first]; tx_buffer->next_eop = last; + /* Update the watchdog time early and often */ + txr->watchdog_time = ticks; /* * Advance the Transmit Descriptor Tail (TDT), this tells the E1000 @@ -1995,6 +2091,9 @@ em_set_multi(struct adapter *adapter) IOCTL_DEBUGOUT("em_set_multi: begin"); + mta = adapter->mta; + bzero(mta, sizeof(u8) * ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES); + if (adapter->hw.mac.type == e1000_82542 && adapter->hw.revision_id == E1000_REVISION_2) { reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); @@ -2005,13 +2104,6 @@ em_set_multi(struct adapter *adapter) msec_delay(5); } - /* Allocate temporary memory to setup array */ - mta = malloc(sizeof(u8) * - (ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES), - M_DEVBUF, M_NOWAIT | M_ZERO); - if (mta == NULL) - panic("em_set_multi memory failure\n"); - #if __FreeBSD_version < 800000 IF_ADDR_LOCK(ifp); #else @@ -2049,7 +2141,6 @@ em_set_multi(struct adapter *adapter) if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) e1000_pci_set_mwi(&adapter->hw); } - free(mta, M_DEVBUF); } @@ -2076,6 +2167,14 @@ em_local_timer(void *arg) if (e1000_get_laa_state_82571(&adapter->hw) == TRUE) e1000_rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + /* + ** If flow control has paused us since last checking + ** it invalidates the watchdog timing, so dont run it. + */ + if (adapter->pause_frames) { + adapter->pause_frames = 0; + goto out; + } /* ** Check for time since any descriptor was cleaned */ @@ -2089,11 +2188,18 @@ em_local_timer(void *arg) goto hung; EM_TX_UNLOCK(txr); } - +out: callout_reset(&adapter->timer, hz, em_local_timer, adapter); return; hung: device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); + device_printf(adapter->dev, + "Queue(%d) tdh = %d, hw tdt = %d\n", txr->me, + E1000_READ_REG(&adapter->hw, E1000_TDH(txr->me)), + E1000_READ_REG(&adapter->hw, E1000_TDT(txr->me))); + device_printf(adapter->dev,"TX(%d) desc avail = %d," + "Next TX to Clean = %d\n", + txr->me, txr->tx_avail, txr->next_to_clean); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; adapter->watchdog_events++; EM_TX_UNLOCK(txr); @@ -2107,6 +2213,7 @@ em_update_link_status(struct adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct ifnet *ifp = adapter->ifp; device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; u32 link_check = 0; /* Get the cached link value or read phy for real */ @@ -2164,8 +2271,8 @@ em_update_link_status(struct adapter *adapter) device_printf(dev, "Link is Down\n"); adapter->link_active = 0; /* Link down, disable watchdog */ - // JFV change later - //adapter->watchdog_check = FALSE; + for (int i = 0; i < adapter->num_queues; i++, txr++) + txr->watchdog_check = FALSE; if_link_state_change(ifp, LINK_STATE_DOWN); } } @@ -2367,6 +2474,9 @@ em_allocate_msix(struct adapter *adapter) device_printf(dev, "Failed to register RX handler"); return (error); } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, rxr->res, rxr->tag, "rx %d", i); +#endif rxr->msix = vector++; /* NOTE increment vector for TX */ TASK_INIT(&rxr->rx_task, 0, em_handle_rx, rxr); rxr->tq = taskqueue_create_fast("em_rxq", M_NOWAIT, @@ -2398,6 +2508,9 @@ em_allocate_msix(struct adapter *adapter) device_printf(dev, "Failed to register TX handler"); return (error); } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, txr->res, txr->tag, "tx %d", i); +#endif txr->msix = vector++; /* Increment vector for next pass */ TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr); txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT, @@ -2432,6 +2545,9 @@ em_allocate_msix(struct adapter *adapter) device_printf(dev, "Failed to register LINK handler"); return (error); } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, adapter->res, adapter->tag, "link"); +#endif adapter->linkvec = vector; adapter->ivars |= (8 | vector) << 16; adapter->ivars |= 0x80000000; @@ -2513,7 +2629,12 @@ em_setup_msix(struct adapter *adapter) int val = 0; - /* Setup MSI/X for Hartwell */ + /* + ** Setup MSI/X for Hartwell: tests have shown + ** use of two queues to be unstable, and to + ** provide no great gain anyway, so we simply + ** seperate the interrupts and use a single queue. + */ if ((adapter->hw.mac.type == e1000_82574) && (em_enable_msix == TRUE)) { /* Map the MSIX BAR */ @@ -2527,21 +2648,16 @@ em_setup_msix(struct adapter *adapter) goto msi; } val = pci_msix_count(dev); - if (val != 5) { + if (val < 3) { bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(EM_MSIX_BAR), adapter->msix_mem); adapter->msix_mem = NULL; device_printf(adapter->dev, - "MSIX vectors wrong, using MSI \n"); + "MSIX: insufficient vectors, using MSI\n"); goto msi; } - if (em_msix_queues == 2) { - val = 5; - adapter->num_queues = 2; - } else { - val = 3; - adapter->num_queues = 1; - } + val = 3; + adapter->num_queues = 1; if (pci_alloc_msix(dev, &val) == 0) { device_printf(adapter->dev, "Using MSIX interrupts " @@ -2554,11 +2670,11 @@ msi: val = pci_msi_count(dev); if (val == 1 && pci_alloc_msi(dev, &val) == 0) { adapter->msix = 1; - device_printf(adapter->dev,"Using MSI interrupt\n"); + device_printf(adapter->dev,"Using an MSI interrupt\n"); return (val); } - /* Should only happen due to manual invention */ - device_printf(adapter->dev,"Setup MSIX failure\n"); + /* Should only happen due to manual configuration */ + device_printf(adapter->dev,"No MSI/MSIX using a Legacy IRQ\n"); return (0); } @@ -2646,7 +2762,7 @@ em_reset(struct adapter *adapter) * Setup networking device structure and register an interface. * **********************************************************************/ -static void +static int em_setup_interface(device_t dev, struct adapter *adapter) { struct ifnet *ifp; @@ -2654,8 +2770,10 @@ em_setup_interface(device_t dev, struct adapter *adapter) INIT_DEBUGOUT("em_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - panic("%s: can not if_alloc()", device_get_nameunit(dev)); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_init = em_init; @@ -2742,6 +2860,7 @@ em_setup_interface(device_t dev, struct adapter *adapter) } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + return (0); } @@ -3055,6 +3174,13 @@ em_setup_transmit_ring(struct tx_ring *txr) /* Set number of descriptors available */ txr->tx_avail = adapter->num_tx_desc; + /* Clear checksum offload context. */ + txr->last_hw_offload = 0; + txr->last_hw_ipcss = 0; + txr->last_hw_ipcso = 0; + txr->last_hw_tucss = 0; + txr->last_hw_tucso = 0; + bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); EM_TX_UNLOCK(txr); @@ -3249,146 +3375,138 @@ em_free_transmit_buffers(struct tx_ring *txr) /********************************************************************* - * - * The offload context needs to be set when we transfer the first - * packet of a particular protocol (TCP/UDP). This routine has been - * enhanced to deal with inserted VLAN headers, and IPV6 (not complete) - * - * Added back the old method of keeping the current context type - * and not setting if unnecessary, as this is reported to be a - * big performance win. -jfv + * The offload context is protocol specific (TCP/UDP) and thus + * only needs to be set when the protocol changes. The occasion + * of a context change can be a performance detriment, and + * might be better just disabled. The reason arises in the way + * in which the controller supports pipelined requests from the + * Tx data DMA. Up to four requests can be pipelined, and they may + * belong to the same packet or to multiple packets. However all + * requests for one packet are issued before a request is issued + * for a subsequent packet and if a request for the next packet + * requires a context change, that request will be stalled + * until the previous request completes. This means setting up + * a new context effectively disables pipelined Tx data DMA which + * in turn greatly slow down performance to send small sized + * frames. **********************************************************************/ static void -em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp, - u32 *txd_upper, u32 *txd_lower) +em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp, int ip_off, + struct ip *ip, u32 *txd_upper, u32 *txd_lower) { struct adapter *adapter = txr->adapter; struct e1000_context_desc *TXD = NULL; - struct em_buffer *tx_buffer; - struct ether_vlan_header *eh; - struct ip *ip = NULL; - struct ip6_hdr *ip6; - int cur, ehdrlen; - u32 cmd, hdr_len, ip_hlen; - u16 etype; - u8 ipproto; + struct em_buffer *tx_buffer; + int cur, hdr_len; + u32 cmd = 0; + u16 offload = 0; + u8 ipcso, ipcss, tucso, tucss; - - cmd = hdr_len = ipproto = 0; - *txd_upper = *txd_lower = 0; + ipcss = ipcso = tucss = tucso = 0; + hdr_len = ip_off + (ip->ip_hl << 2); cur = txr->next_avail_desc; - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present, - * helpful for QinQ too. - */ - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - ehdrlen = ETHER_HDR_LEN; + /* Setup of IP header checksum. */ + if (mp->m_pkthdr.csum_flags & CSUM_IP) { + *txd_upper |= E1000_TXD_POPTS_IXSM << 8; + offload |= CSUM_IP; + ipcss = ip_off; + ipcso = ip_off + offsetof(struct ip, ip_sum); + /* + * Start offset for header checksum calculation. + * End offset for header checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *)&txr->tx_base[cur]; + TXD->lower_setup.ip_fields.ipcss = ipcss; + TXD->lower_setup.ip_fields.ipcse = htole16(hdr_len); + TXD->lower_setup.ip_fields.ipcso = ipcso; + cmd |= E1000_TXD_CMD_IP; } - /* - * We only support TCP/UDP for IPv4 and IPv6 for the moment. - * TODO: Support SCTP too when it hits the tree. - */ - switch (etype) { - case ETHERTYPE_IP: - ip = (struct ip *)(mp->m_data + ehdrlen); - ip_hlen = ip->ip_hl << 2; + if (mp->m_pkthdr.csum_flags & CSUM_TCP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + offload |= CSUM_TCP; + tucss = hdr_len; + tucso = hdr_len + offsetof(struct tcphdr, th_sum); + /* + * Setting up new checksum offload context for every frames + * takes a lot of processing time for hardware. This also + * reduces performance a lot for small sized frames so avoid + * it if driver can use previously configured checksum + * offload context. + */ + if (txr->last_hw_offload == offload) { + if (offload & CSUM_IP) { + if (txr->last_hw_ipcss == ipcss && + txr->last_hw_ipcso == ipcso && + txr->last_hw_tucss == tucss && + txr->last_hw_tucso == tucso) + return; + } else { + if (txr->last_hw_tucss == tucss && + txr->last_hw_tucso == tucso) + return; + } + } + txr->last_hw_offload = offload; + txr->last_hw_tucss = tucss; + txr->last_hw_tucso = tucso; + /* + * Start offset for payload checksum calculation. + * End offset for payload checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *)&txr->tx_base[cur]; + TXD->upper_setup.tcp_fields.tucss = hdr_len; + TXD->upper_setup.tcp_fields.tucse = htole16(0); + TXD->upper_setup.tcp_fields.tucso = tucso; + cmd |= E1000_TXD_CMD_TCP; + } else if (mp->m_pkthdr.csum_flags & CSUM_UDP) { + *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; + *txd_upper |= E1000_TXD_POPTS_TXSM << 8; + tucss = hdr_len; + tucso = hdr_len + offsetof(struct udphdr, uh_sum); + /* + * Setting up new checksum offload context for every frames + * takes a lot of processing time for hardware. This also + * reduces performance a lot for small sized frames so avoid + * it if driver can use previously configured checksum + * offload context. + */ + if (txr->last_hw_offload == offload) { + if (offload & CSUM_IP) { + if (txr->last_hw_ipcss == ipcss && + txr->last_hw_ipcso == ipcso && + txr->last_hw_tucss == tucss && + txr->last_hw_tucso == tucso) + return; + } else { + if (txr->last_hw_tucss == tucss && + txr->last_hw_tucso == tucso) + return; + } + } + txr->last_hw_offload = offload; + txr->last_hw_tucss = tucss; + txr->last_hw_tucso = tucso; + /* + * Start offset for header checksum calculation. + * End offset for header checksum calculation. + * Offset of place to put the checksum. + */ + TXD = (struct e1000_context_desc *)&txr->tx_base[cur]; + TXD->upper_setup.tcp_fields.tucss = tucss; + TXD->upper_setup.tcp_fields.tucse = htole16(0); + TXD->upper_setup.tcp_fields.tucso = tucso; + } + + if (offload & CSUM_IP) { + txr->last_hw_ipcss = ipcss; + txr->last_hw_ipcso = ipcso; + } - /* Setup of IP header checksum. */ - if (mp->m_pkthdr.csum_flags & CSUM_IP) { - /* - * Start offset for header checksum calculation. - * End offset for header checksum calculation. - * Offset of place to put the checksum. - */ - TXD = (struct e1000_context_desc *) - &txr->tx_base[cur]; - TXD->lower_setup.ip_fields.ipcss = ehdrlen; - TXD->lower_setup.ip_fields.ipcse = - htole16(ehdrlen + ip_hlen); - TXD->lower_setup.ip_fields.ipcso = - ehdrlen + offsetof(struct ip, ip_sum); - cmd |= E1000_TXD_CMD_IP; - *txd_upper |= E1000_TXD_POPTS_IXSM << 8; - } - - hdr_len = ehdrlen + ip_hlen; - ipproto = ip->ip_p; - break; - - case ETHERTYPE_IPV6: - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - ip_hlen = sizeof(struct ip6_hdr); /* XXX: No header stacking. */ - - /* IPv6 doesn't have a header checksum. */ - - hdr_len = ehdrlen + ip_hlen; - ipproto = ip6->ip6_nxt; - break; - - default: - return; - } - - switch (ipproto) { - case IPPROTO_TCP: - if (mp->m_pkthdr.csum_flags & CSUM_TCP) { - *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; - *txd_upper |= E1000_TXD_POPTS_TXSM << 8; - /* no need for context if already set */ - if (txr->last_hw_offload == CSUM_TCP) - return; - txr->last_hw_offload = CSUM_TCP; - /* - * Start offset for payload checksum calculation. - * End offset for payload checksum calculation. - * Offset of place to put the checksum. - */ - TXD = (struct e1000_context_desc *) - &txr->tx_base[cur]; - TXD->upper_setup.tcp_fields.tucss = hdr_len; - TXD->upper_setup.tcp_fields.tucse = htole16(0); - TXD->upper_setup.tcp_fields.tucso = - hdr_len + offsetof(struct tcphdr, th_sum); - cmd |= E1000_TXD_CMD_TCP; - } - break; - case IPPROTO_UDP: - { - if (mp->m_pkthdr.csum_flags & CSUM_UDP) { - *txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; - *txd_upper |= E1000_TXD_POPTS_TXSM << 8; - /* no need for context if already set */ - if (txr->last_hw_offload == CSUM_UDP) - return; - txr->last_hw_offload = CSUM_UDP; - /* - * Start offset for header checksum calculation. - * End offset for header checksum calculation. - * Offset of place to put the checksum. - */ - TXD = (struct e1000_context_desc *) - &txr->tx_base[cur]; - TXD->upper_setup.tcp_fields.tucss = hdr_len; - TXD->upper_setup.tcp_fields.tucse = htole16(0); - TXD->upper_setup.tcp_fields.tucso = - hdr_len + offsetof(struct udphdr, uh_sum); - } - /* Fall Thru */ - } - default: - break; - } - - if (TXD == NULL) - return; TXD->tcp_seg_setup.data = htole32(0); TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | cmd); @@ -3409,124 +3527,52 @@ em_transmit_checksum_setup(struct tx_ring *txr, struct mbuf *mp, * Setup work for hardware segmentation offload (TSO) * **********************************************************************/ -static bool -em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper, - u32 *txd_lower) +static void +em_tso_setup(struct tx_ring *txr, struct mbuf *mp, int ip_off, + struct ip *ip, struct tcphdr *tp, u32 *txd_upper, u32 *txd_lower) { struct adapter *adapter = txr->adapter; struct e1000_context_desc *TXD; struct em_buffer *tx_buffer; - struct ether_vlan_header *eh; - struct ip *ip; - struct ip6_hdr *ip6; - struct tcphdr *th; - int cur, ehdrlen, hdr_len, ip_hlen, isip6; - u16 etype; + int cur, hdr_len; /* - * This function could/should be extended to support IP/IPv6 - * fragmentation as well. But as they say, one step at a time. + * In theory we can use the same TSO context if and only if + * frame is the same type(IP/TCP) and the same MSS. However + * checking whether a frame has the same IP/TCP structure is + * hard thing so just ignore that and always restablish a + * new TSO context. */ - - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present, - * helpful for QinQ too. - */ - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - etype = ntohs(eh->evl_proto); - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - } else { - etype = ntohs(eh->evl_encap_proto); - ehdrlen = ETHER_HDR_LEN; - } - - /* Ensure we have at least the IP+TCP header in the first mbuf. */ - if (mp->m_len < ehdrlen + sizeof(struct ip) + sizeof(struct tcphdr)) - return FALSE; /* -1 */ - - /* - * We only support TCP for IPv4 and IPv6 (notyet) for the moment. - * TODO: Support SCTP too when it hits the tree. - */ - switch (etype) { - case ETHERTYPE_IP: - isip6 = 0; - ip = (struct ip *)(mp->m_data + ehdrlen); - if (ip->ip_p != IPPROTO_TCP) - return FALSE; /* 0 */ - ip->ip_len = 0; - ip->ip_sum = 0; - ip_hlen = ip->ip_hl << 2; - if (mp->m_len < ehdrlen + ip_hlen + sizeof(struct tcphdr)) - return FALSE; /* -1 */ - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); -#if 1 - th->th_sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htons(IPPROTO_TCP)); -#else - th->th_sum = mp->m_pkthdr.csum_data; -#endif - break; - case ETHERTYPE_IPV6: - isip6 = 1; - return FALSE; /* Not supported yet. */ - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - if (ip6->ip6_nxt != IPPROTO_TCP) - return FALSE; /* 0 */ - ip6->ip6_plen = 0; - ip_hlen = sizeof(struct ip6_hdr); /* XXX: no header stacking. */ - if (mp->m_len < ehdrlen + ip_hlen + sizeof(struct tcphdr)) - return FALSE; /* -1 */ - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); -#if 0 - th->th_sum = in6_pseudo(ip6->ip6_src, ip->ip6_dst, - htons(IPPROTO_TCP)); /* XXX: function notyet. */ -#else - th->th_sum = mp->m_pkthdr.csum_data; -#endif - break; - default: - return FALSE; - } - hdr_len = ehdrlen + ip_hlen + (th->th_off << 2); - + hdr_len = ip_off + (ip->ip_hl << 2) + (tp->th_off << 2); *txd_lower = (E1000_TXD_CMD_DEXT | /* Extended descr type */ E1000_TXD_DTYP_D | /* Data descr type */ E1000_TXD_CMD_TSE); /* Do TSE on this packet */ /* IP and/or TCP header checksum calculation and insertion. */ - *txd_upper = ((isip6 ? 0 : E1000_TXD_POPTS_IXSM) | - E1000_TXD_POPTS_TXSM) << 8; + *txd_upper = (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; cur = txr->next_avail_desc; tx_buffer = &txr->tx_buffers[cur]; TXD = (struct e1000_context_desc *) &txr->tx_base[cur]; - /* IPv6 doesn't have a header checksum. */ - if (!isip6) { - /* - * Start offset for header checksum calculation. - * End offset for header checksum calculation. - * Offset of place put the checksum. - */ - TXD->lower_setup.ip_fields.ipcss = ehdrlen; - TXD->lower_setup.ip_fields.ipcse = - htole16(ehdrlen + ip_hlen - 1); - TXD->lower_setup.ip_fields.ipcso = - ehdrlen + offsetof(struct ip, ip_sum); - } + /* + * Start offset for header checksum calculation. + * End offset for header checksum calculation. + * Offset of place put the checksum. + */ + TXD->lower_setup.ip_fields.ipcss = ip_off; + TXD->lower_setup.ip_fields.ipcse = + htole16(ip_off + (ip->ip_hl << 2) - 1); + TXD->lower_setup.ip_fields.ipcso = ip_off + offsetof(struct ip, ip_sum); /* * Start offset for payload checksum calculation. * End offset for payload checksum calculation. * Offset of place to put the checksum. */ - TXD->upper_setup.tcp_fields.tucss = - ehdrlen + ip_hlen; + TXD->upper_setup.tcp_fields.tucss = ip_off + (ip->ip_hl << 2); TXD->upper_setup.tcp_fields.tucse = 0; TXD->upper_setup.tcp_fields.tucso = - ehdrlen + ip_hlen + offsetof(struct tcphdr, th_sum); + ip_off + (ip->ip_hl << 2) + offsetof(struct tcphdr, th_sum); /* * Payload size per packet w/o any headers. * Length of all headers up to payload. @@ -3537,7 +3583,7 @@ em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper, TXD->cmd_and_length = htole32(adapter->txd_cmd | E1000_TXD_CMD_DEXT | /* Extended descr */ E1000_TXD_CMD_TSE | /* TSE context */ - (isip6 ? 0 : E1000_TXD_CMD_IP) | + E1000_TXD_CMD_IP | /* Do IP csum */ E1000_TXD_CMD_TCP | /* Do TCP checksum */ (mp->m_pkthdr.len - (hdr_len))); /* Total len */ @@ -3550,8 +3596,6 @@ em_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *txd_upper, txr->tx_avail--; txr->next_avail_desc = cur; txr->tx_tso = TRUE; - - return TRUE; } @@ -3566,7 +3610,7 @@ static bool em_txeof(struct tx_ring *txr) { struct adapter *adapter = txr->adapter; - int first, last, done, num_avail; + int first, last, done; struct em_buffer *tx_buffer; struct e1000_tx_desc *tx_desc, *eop_desc; struct ifnet *ifp = adapter->ifp; @@ -3576,7 +3620,6 @@ em_txeof(struct tx_ring *txr) if (txr->tx_avail == adapter->num_tx_desc) return (FALSE); - num_avail = txr->tx_avail; first = txr->next_to_clean; tx_desc = &txr->tx_base[first]; tx_buffer = &txr->tx_buffers[first]; @@ -3602,16 +3645,14 @@ em_txeof(struct tx_ring *txr) tx_desc->upper.data = 0; tx_desc->lower.data = 0; tx_desc->buffer_addr = 0; - ++num_avail; + ++txr->tx_avail; if (tx_buffer->m_head) { - ifp->if_opackets++; bus_dmamap_sync(txr->txtag, tx_buffer->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(txr->txtag, tx_buffer->map); - m_freem(tx_buffer->m_head); tx_buffer->m_head = NULL; } @@ -3624,6 +3665,7 @@ em_txeof(struct tx_ring *txr) tx_buffer = &txr->tx_buffers[first]; tx_desc = &txr->tx_base[first]; } + ++ifp->if_opackets; /* See if we can continue to the next packet */ last = tx_buffer->next_eop; if (last != -1) { @@ -3640,20 +3682,18 @@ em_txeof(struct tx_ring *txr) txr->next_to_clean = first; /* - * If we have enough room, clear IFF_DRV_OACTIVE to - * tell the stack that it is OK to send packets. - * If there are no pending descriptors, clear the watchdog. + * If we have enough room, clear IFF_DRV_OACTIVE + * to tell the stack that it is OK to send packets. */ - if (num_avail > EM_TX_CLEANUP_THRESHOLD) { + if (txr->tx_avail > EM_TX_CLEANUP_THRESHOLD) { ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - if (num_avail == adapter->num_tx_desc) { + /* Disable watchdog if all clean */ + if (txr->tx_avail == adapter->num_tx_desc) { txr->watchdog_check = FALSE; - txr->tx_avail = num_avail; return (FALSE); } } - txr->tx_avail = num_avail; return (TRUE); } @@ -3669,14 +3709,27 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit) struct adapter *adapter = rxr->adapter; struct mbuf *m; bus_dma_segment_t segs[1]; - bus_dmamap_t map; struct em_buffer *rxbuf; int i, error, nsegs, cleaned; i = rxr->next_to_refresh; cleaned = -1; while (i != limit) { + rxbuf = &rxr->rx_buffers[i]; + /* + ** Just skip entries with a buffer, + ** they can only be due to an error + ** and are to be reused. + */ + if (rxbuf->m_head != NULL) + goto reuse; m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + /* + ** If we have a temporary resource shortage + ** that causes a failure, just abort refresh + ** for now, we will return to this point when + ** reinvoked from em_rxeof. + */ if (m == NULL) goto update; m->m_len = m->m_pkthdr.len = MCLBYTES; @@ -3684,11 +3737,8 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit) if (adapter->max_frame_size <= (MCLBYTES - ETHER_ALIGN)) m_adj(m, ETHER_ALIGN); - /* - * Using memory from the mbuf cluster pool, invoke the - * bus_dma machinery to arrange the memory mapping. - */ - error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxr->rx_sparemap, + /* Use bus_dma machinery to setup the memory mapping */ + error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxbuf->map, m, segs, &nsegs, BUS_DMA_NOWAIT); if (error != 0) { m_free(m); @@ -3698,18 +3748,11 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit) /* If nsegs is wrong then the stack is corrupt. */ KASSERT(nsegs == 1, ("Too many segments returned!")); - rxbuf = &rxr->rx_buffers[i]; - if (rxbuf->m_head != NULL) - bus_dmamap_unload(rxr->rxtag, rxbuf->map); - - map = rxbuf->map; - rxbuf->map = rxr->rx_sparemap; - rxr->rx_sparemap = map; bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_PREREAD); rxbuf->m_head = m; rxr->rx_base[i].buffer_addr = htole64(segs[0].ds_addr); - +reuse: cleaned = i; /* Calculate next index */ if (++i == adapter->num_rx_desc) @@ -3718,8 +3761,10 @@ em_refresh_mbufs(struct rx_ring *rxr, int limit) rxr->next_to_refresh = i; } update: - bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + /* + ** Update the tail pointer only if, + ** and as far as we have refreshed. + */ if (cleaned != -1) /* Update tail index */ E1000_WRITE_REG(&adapter->hw, E1000_RDT(rxr->me), cleaned); @@ -3769,15 +3814,6 @@ em_allocate_receive_buffers(struct rx_ring *rxr) goto fail; } - /* Create the spare map (used by getbuf) */ - error = bus_dmamap_create(rxr->rxtag, BUS_DMA_NOWAIT, - &rxr->rx_sparemap); - if (error) { - device_printf(dev, "%s: bus_dmamap_create failed: %d\n", - __func__, error); - goto fail; - } - rxbuf = rxr->rx_buffers; for (int i = 0; i < adapter->num_rx_desc; i++, rxbuf++) { rxbuf = &rxr->rx_buffers[i]; @@ -3837,7 +3873,7 @@ em_setup_receive_ring(struct rx_ring *rxr) rxbuf = &rxr->rx_buffers[j]; rxbuf->m_head = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); if (rxbuf->m_head == NULL) - panic("RX ring hdr initialization failed!\n"); + return (ENOBUFS); rxbuf->m_head->m_len = MCLBYTES; rxbuf->m_head->m_flags &= ~M_HASFCS; /* we strip it */ rxbuf->m_head->m_pkthdr.len = MCLBYTES; @@ -3846,8 +3882,11 @@ em_setup_receive_ring(struct rx_ring *rxr) error = bus_dmamap_load_mbuf_sg(rxr->rxtag, rxbuf->map, rxbuf->m_head, seg, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) - panic("RX ring dma initialization failed!\n"); + if (error != 0) { + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + return (error); + } bus_dmamap_sync(rxr->rxtag, rxbuf->map, BUS_DMASYNC_PREREAD); @@ -3941,11 +3980,6 @@ em_free_receive_buffers(struct rx_ring *rxr) INIT_DEBUGOUT("free_receive_buffers: begin"); - if (rxr->rx_sparemap) { - bus_dmamap_destroy(rxr->rxtag, rxr->rx_sparemap); - rxr->rx_sparemap = NULL; - } - if (rxr->rx_buffers != NULL) { for (int i = 0; i < adapter->num_rx_desc; i++) { rxbuf = &rxr->rx_buffers[i]; @@ -4117,12 +4151,16 @@ em_rxeof(struct rx_ring *rxr, int count, int *done) eop = (status & E1000_RXD_STAT_EOP) != 0; count--; - if ((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) { + if (((cur->errors & E1000_RXD_ERR_FRAME_ERR_MASK) == 0) && + (rxr->discard == FALSE)) { /* Assign correct length to the current fragment */ mp = rxr->rx_buffers[i].m_head; mp->m_len = len; + /* Trigger for refresh */ + rxr->rx_buffers[i].m_head = NULL; + if (rxr->fmp == NULL) { mp->m_pkthdr.len = len; rxr->fmp = mp; /* Store the first mbuf */ @@ -4164,19 +4202,12 @@ skip: } } else { ifp->if_ierrors++; - /* Reuse loaded DMA map and just update mbuf chain */ - mp = rxr->rx_buffers[i].m_head; - mp->m_len = mp->m_pkthdr.len = MCLBYTES; - mp->m_data = mp->m_ext.ext_buf; - mp->m_next = NULL; - if (adapter->max_frame_size <= - (MCLBYTES - ETHER_ALIGN)) - m_adj(mp, ETHER_ALIGN); - if (rxr->fmp != NULL) { - m_freem(rxr->fmp); - rxr->fmp = NULL; - rxr->lmp = NULL; - } + ++rxr->rx_discarded; + if (!eop) /* Catch subsequent segs */ + rxr->discard = TRUE; + else + rxr->discard = FALSE; + em_rx_discard(rxr, i); sendmp = NULL; } @@ -4219,6 +4250,31 @@ skip: return ((status & E1000_RXD_STAT_DD) ? TRUE : FALSE); } +static __inline void +em_rx_discard(struct rx_ring *rxr, int i) +{ + struct em_buffer *rbuf; + struct mbuf *m; + + rbuf = &rxr->rx_buffers[i]; + /* Free any previous pieces */ + if (rxr->fmp != NULL) { + rxr->fmp->m_flags |= M_PKTHDR; + m_freem(rxr->fmp); + rxr->fmp = NULL; + rxr->lmp = NULL; + } + + /* Reset state, keep loaded DMA map and reuse */ + m = rbuf->m_head; + m->m_len = m->m_pkthdr.len = MCLBYTES; + m->m_flags |= M_PKTHDR; + m->m_data = m->m_ext.ext_buf; + m->m_next = NULL; + + return; +} + #ifndef __NO_STRICT_ALIGNMENT /* * When jumbo frames are enabled we should realign entire payload on @@ -4797,7 +4853,12 @@ em_update_stats_counters(struct adapter *adapter) adapter->stats.rlec += E1000_READ_REG(&adapter->hw, E1000_RLEC); adapter->stats.xonrxc += E1000_READ_REG(&adapter->hw, E1000_XONRXC); adapter->stats.xontxc += E1000_READ_REG(&adapter->hw, E1000_XONTXC); - adapter->stats.xoffrxc += E1000_READ_REG(&adapter->hw, E1000_XOFFRXC); + /* + ** For watchdog management we need to know if we have been + ** paused during the last interval, so capture that here. + */ + adapter->pause_frames = E1000_READ_REG(&adapter->hw, E1000_XOFFRXC); + adapter->stats.xoffrxc += adapter->pause_frames; adapter->stats.xofftxc += E1000_READ_REG(&adapter->hw, E1000_XOFFTXC); adapter->stats.fcruc += E1000_READ_REG(&adapter->hw, E1000_FCRUC); adapter->stats.prc64 += E1000_READ_REG(&adapter->hw, E1000_PRC64); @@ -4814,8 +4875,10 @@ em_update_stats_counters(struct adapter *adapter) /* For the 64-bit byte counters the low dword must be read first. */ /* Both registers clear on the read of the high dword */ - adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCH); - adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCH); + adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCL) + + ((u64)E1000_READ_REG(&adapter->hw, E1000_GORCH) << 32); + adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCL) + + ((u64)E1000_READ_REG(&adapter->hw, E1000_GOTCH) << 32); adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, E1000_RNBC); adapter->stats.ruc += E1000_READ_REG(&adapter->hw, E1000_RUC); @@ -4837,6 +4900,18 @@ em_update_stats_counters(struct adapter *adapter) adapter->stats.mptc += E1000_READ_REG(&adapter->hw, E1000_MPTC); adapter->stats.bptc += E1000_READ_REG(&adapter->hw, E1000_BPTC); + /* Interrupt Counts */ + + adapter->stats.iac += E1000_READ_REG(&adapter->hw, E1000_IAC); + adapter->stats.icrxptc += E1000_READ_REG(&adapter->hw, E1000_ICRXPTC); + adapter->stats.icrxatc += E1000_READ_REG(&adapter->hw, E1000_ICRXATC); + adapter->stats.ictxptc += E1000_READ_REG(&adapter->hw, E1000_ICTXPTC); + adapter->stats.ictxatc += E1000_READ_REG(&adapter->hw, E1000_ICTXATC); + adapter->stats.ictxqec += E1000_READ_REG(&adapter->hw, E1000_ICTXQEC); + adapter->stats.ictxqmtc += E1000_READ_REG(&adapter->hw, E1000_ICTXQMTC); + adapter->stats.icrxdmtc += E1000_READ_REG(&adapter->hw, E1000_ICRXDMTC); + adapter->stats.icrxoc += E1000_READ_REG(&adapter->hw, E1000_ICRXOC); + if (adapter->hw.mac.type >= e1000_82543) { adapter->stats.algnerrc += E1000_READ_REG(&adapter->hw, E1000_ALGNERRC); @@ -4866,6 +4941,17 @@ em_update_stats_counters(struct adapter *adapter) adapter->stats.latecol + adapter->watchdog_events; } +/* Export a single 32-bit register via a read-only sysctl. */ +static int +em_sysctl_reg_handler(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter; + u_int val; + + adapter = oidp->oid_arg1; + val = E1000_READ_REG(&adapter->hw, oidp->oid_arg2); + return (sysctl_handle_int(oidp, &val, 0, req)); +} /* * Add sysctl variables, one per statistic, to the system. @@ -4873,17 +4959,22 @@ em_update_stats_counters(struct adapter *adapter) static void em_add_hw_stats(struct adapter *adapter) { - device_t dev = adapter->dev; + struct tx_ring *txr = adapter->tx_rings; + struct rx_ring *rxr = adapter->rx_rings; + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); struct e1000_hw_stats *stats = &adapter->stats; - struct sysctl_oid *stat_node, *int_node, *host_node; - struct sysctl_oid_list *stat_list, *int_list, *host_list; + struct sysctl_oid *stat_node, *queue_node, *int_node; + struct sysctl_oid_list *stat_list, *queue_list, *int_list; +#define QUEUE_NAME_LEN 32 + char namebuf[QUEUE_NAME_LEN]; + /* Driver Statistics */ SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "link_irq", CTLFLAG_RD, &adapter->link_irq, 0, @@ -4900,7 +4991,21 @@ em_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_dma_fail", CTLFLAG_RD, &adapter->no_tx_dma_setup, "Driver tx dma failure in xmit"); - + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "rx_overruns", + CTLFLAG_RD, &adapter->rx_overruns, + "RX overruns"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_timeouts", + CTLFLAG_RD, &adapter->watchdog_events, + "Watchdog timeouts"); + + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control", + CTLFLAG_RD, adapter, E1000_CTRL, + em_sysctl_reg_handler, "IU", + "Device Control Register"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_control", + CTLFLAG_RD, adapter, E1000_RCTL, + em_sysctl_reg_handler, "IU", + "Receiver Control Register"); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_high_water", CTLFLAG_RD, &adapter->hw.fc.high_water, 0, "Flow Control High Watermark"); @@ -4908,7 +5013,41 @@ em_add_hw_stats(struct adapter *adapter) CTLFLAG_RD, &adapter->hw.fc.low_water, 0, "Flow Control Low Watermark"); - /* MAC stats get the own sub node */ + for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", + CTLFLAG_RD, adapter, E1000_TDH(txr->me), + em_sysctl_reg_handler, "IU", + "Transmit Descriptor Head"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", + CTLFLAG_RD, adapter, E1000_TDT(txr->me), + em_sysctl_reg_handler, "IU", + "Transmit Descriptor Tail"); + SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tx_irq", + CTLFLAG_RD, &txr->tx_irq, + "Queue MSI-X Transmit Interrupts"); + SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_desc_avail", + CTLFLAG_RD, &txr->no_desc_avail, + "Queue No Descriptor Available"); + + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", + CTLFLAG_RD, adapter, E1000_RDH(rxr->me), + em_sysctl_reg_handler, "IU", + "Receive Descriptor Head"); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", + CTLFLAG_RD, adapter, E1000_RDT(rxr->me), + em_sysctl_reg_handler, "IU", + "Receive Descriptor Tail"); + SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "rx_irq", + CTLFLAG_RD, &rxr->rx_irq, + "Queue MSI-X Receive Interrupts"); + } + + /* MAC stats get their own sub node */ stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", CTLFLAG_RD, NULL, "Statistics"); @@ -4917,6 +5056,18 @@ em_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "excess_coll", CTLFLAG_RD, &stats->ecol, "Excessive collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "single_coll", + CTLFLAG_RD, &stats->scc, + "Single collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "multiple_coll", + CTLFLAG_RD, &stats->mcc, + "Multiple collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "late_coll", + CTLFLAG_RD, &stats->latecol, + "Late collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "collision_count", + CTLFLAG_RD, &stats->colc, + "Collision Count"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "symbol_errors", CTLFLAG_RD, &adapter->stats.symerrs, "Symbol Errors"); @@ -4932,11 +5083,18 @@ em_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_no_buff", CTLFLAG_RD, &adapter->stats.rnbc, "Receive No Buffers"); - /* RLEC is inaccurate on some hardware, calculate our own. */ -/* SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_len_errs", */ -/* CTLFLAG_RD, adapter->stats.roc + adapter->stats.ruc, */ -/* "Receive Length Errors"); */ - + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_undersize", + CTLFLAG_RD, &adapter->stats.ruc, + "Receive Undersize"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", + CTLFLAG_RD, &adapter->stats.rfc, + "Fragmented Packets Received "); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_oversize", + CTLFLAG_RD, &adapter->stats.roc, + "Oversized Packets Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_jabber", + CTLFLAG_RD, &adapter->stats.rjc, + "Recevied Jabber"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_errs", CTLFLAG_RD, &adapter->stats.rxerrc, "Receive Errors"); @@ -4950,12 +5108,6 @@ em_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs", CTLFLAG_RD, &adapter->stats.cexterr, "Collision/Carrier extension errors"); - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_overruns", - CTLFLAG_RD, &adapter->rx_overruns, - "RX overruns"); - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "watchdog_timeouts", - CTLFLAG_RD, &adapter->watchdog_events, - "Watchdog timeouts"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_recvd", CTLFLAG_RD, &adapter->stats.xonrxc, "XON Received"); @@ -5005,9 +5157,9 @@ em_add_hw_stats(struct adapter *adapter) "Good Octets Received"); /* Packet Transmission Stats */ - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octest_txd", + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", CTLFLAG_RD, &adapter->stats.gotc, - "Good Octest Transmitted"); + "Good Octets Transmitted"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", CTLFLAG_RD, &adapter->stats.tpt, "Total Packets Transmitted"); @@ -5087,65 +5239,6 @@ em_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, int_list, OID_AUTO, "rx_overrun", CTLFLAG_RD, &adapter->stats.icrxoc, "Interrupt Cause Receiver Overrun Count"); - - /* Host to Card Stats */ - - host_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "host", - CTLFLAG_RD, NULL, - "Host to Card Statistics"); - - host_list = SYSCTL_CHILDREN(host_node); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_tx_pkt", - CTLFLAG_RD, &adapter->stats.cbtmpc, - "Circuit Breaker Tx Packet Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "host_tx_pkt_discard", - CTLFLAG_RD, &adapter->stats.htdpmc, - "Host Transmit Discarded Packets"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "rx_pkt", - CTLFLAG_RD, &adapter->stats.rpthc, - "Rx Packets To Host"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_rx_pkts", - CTLFLAG_RD, &adapter->stats.cbrmpc, - "Circuit Breaker Rx Packet Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_rx_pkt_drop", - CTLFLAG_RD, &adapter->stats.cbrdpc, - "Circuit Breaker Rx Dropped Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "tx_good_pkt", - CTLFLAG_RD, &adapter->stats.hgptc, - "Host Good Packets Tx Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "breaker_tx_pkt_drop", - CTLFLAG_RD, &adapter->stats.htcbdpc, - "Host Tx Circuit Breaker Dropped Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "rx_good_bytes", - CTLFLAG_RD, &adapter->stats.hgorc, - "Host Good Octets Received Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "tx_good_bytes", - CTLFLAG_RD, &adapter->stats.hgotc, - "Host Good Octets Transmit Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "length_errors", - CTLFLAG_RD, &adapter->stats.lenerrs, - "Length Errors"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "serdes_violation_pkt", - CTLFLAG_RD, &adapter->stats.scvpc, - "SerDes/SGMII Code Violation Pkt Count"); - - SYSCTL_ADD_QUAD(ctx, host_list, OID_AUTO, "header_redir_missed", - CTLFLAG_RD, &adapter->stats.hrmpc, - "Header Redirection Missed Packet Count"); - - - } /********************************************************************** @@ -5155,7 +5248,6 @@ em_add_hw_stats(struct adapter *adapter) * 32 words, stuff that matters is in that extent. * **********************************************************************/ - static int em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS) { diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h index 225a8d08b8e..fec34acd7c5 100644 --- a/sys/dev/e1000/if_em.h +++ b/sys/dev/e1000/if_em.h @@ -284,6 +284,10 @@ struct tx_ring { volatile u16 tx_avail; u32 tx_tso; /* last tx was tso */ u16 last_hw_offload; + u8 last_hw_ipcso; + u8 last_hw_ipcss; + u8 last_hw_tucso; + u8 last_hw_tucss; #if __FreeBSD_version >= 800000 struct buf_ring *br; #endif @@ -320,10 +324,11 @@ struct rx_ring { void *tag; struct resource *res; bus_dma_tag_t rxtag; - bus_dmamap_t rx_sparemap; + bool discard; /* Soft stats */ unsigned long rx_irq; + unsigned long rx_discarded; unsigned long rx_packets; unsigned long rx_bytes; }; @@ -354,6 +359,7 @@ struct adapter { int if_flags; int max_frame_size; int min_frame_size; + int pause_frames; struct mtx core_mtx; int em_insert_vlan_header; u32 ims; @@ -391,6 +397,9 @@ struct adapter { bool has_manage; bool has_amt; + /* Multicast array memory */ + u8 *mta; + /* Info about the board itself */ uint8_t link_active; uint16_t link_speed; diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index c908517e45c..ee7ba7166c8 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -99,7 +99,7 @@ int igb_display_debug_stats = 0; /********************************************************************* * Driver version: *********************************************************************/ -char igb_driver_version[] = "version - 2.0.1"; +char igb_driver_version[] = "version - 2.0.4"; /********************************************************************* @@ -128,6 +128,8 @@ static igb_vendor_info_t igb_vendor_info_array[] = PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_QUAD_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, + { 0x8086, E1000_DEV_ID_82576_QUAD_COPPER_ET2, + PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82576_VF, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82580_COPPER, PCI_ANY_ID, PCI_ANY_ID, 0}, { 0x8086, E1000_DEV_ID_82580_FIBER, PCI_ANY_ID, PCI_ANY_ID, 0}, @@ -178,7 +180,7 @@ static int igb_setup_msix(struct adapter *); static void igb_free_pci_resources(struct adapter *); static void igb_local_timer(void *); static void igb_reset(struct adapter *); -static void igb_setup_interface(device_t, struct adapter *); +static int igb_setup_interface(device_t, struct adapter *); static int igb_allocate_queues(struct adapter *); static void igb_configure_queues(struct adapter *); @@ -509,6 +511,20 @@ igb_attach(device_t dev) adapter->stats = (struct e1000_hw_stats *)malloc(sizeof \ (struct e1000_hw_stats), M_DEVBUF, M_NOWAIT | M_ZERO); + if (adapter->stats == NULL) { + device_printf(dev, "Can not allocate stats memory\n"); + error = ENOMEM; + goto err_late; + } + + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(u8) * ETH_ADDR_LEN * + MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_late; + } /* ** Start from a known state, this is @@ -559,7 +575,8 @@ igb_attach(device_t dev) goto err_late; /* Setup OS specific network interface */ - igb_setup_interface(dev, adapter); + if (igb_setup_interface(dev, adapter) != 0) + goto err_late; /* Now get a good starting state */ igb_reset(adapter); @@ -608,8 +625,11 @@ err_late: igb_free_transmit_structures(adapter); igb_free_receive_structures(adapter); igb_release_hw_control(adapter); + if (adapter->ifp != NULL) + if_free(adapter->ifp); err_pci: igb_free_pci_resources(adapter); + free(adapter->mta, M_DEVBUF); IGB_CORE_LOCK_DESTROY(adapter); return (error); @@ -680,6 +700,7 @@ igb_detach(device_t dev) igb_free_transmit_structures(adapter); igb_free_receive_structures(adapter); + free(adapter->mta, M_DEVBUF); IGB_CORE_LOCK_DESTROY(adapter); @@ -1853,12 +1874,16 @@ igb_set_multi(struct adapter *adapter) struct ifnet *ifp = adapter->ifp; struct ifmultiaddr *ifma; u32 reg_rctl = 0; - u8 mta[MAX_NUM_MULTICAST_ADDRESSES * ETH_ADDR_LEN]; + u8 *mta; int mcnt = 0; IOCTL_DEBUGOUT("igb_set_multi: begin"); + mta = adapter->mta; + bzero(mta, sizeof(uint8_t) * ETH_ADDR_LEN * + MAX_NUM_MULTICAST_ADDRESSES); + #if __FreeBSD_version < 800000 IF_ADDR_LOCK(ifp); #else @@ -1910,16 +1935,31 @@ igb_local_timer(void *arg) igb_update_link_status(adapter); igb_update_stats_counters(adapter); + /* + ** If flow control has paused us since last checking + ** it invalidates the watchdog timing, so dont run it. + */ + if (adapter->pause_frames) { + adapter->pause_frames = 0; + goto out; + } + /* ** Watchdog: check for time since any descriptor was cleaned */ for (int i = 0; i < adapter->num_queues; i++, txr++) { - if (txr->watchdog_check == FALSE) + IGB_TX_LOCK(txr); + if ((txr->watchdog_check == FALSE) || + (txr->tx_avail == adapter->num_tx_desc)) { + IGB_TX_UNLOCK(txr); continue; + } if ((ticks - txr->watchdog_time) > IGB_WATCHDOG) goto timeout; + IGB_TX_UNLOCK(txr); } +out: callout_reset(&adapter->timer, hz, igb_local_timer, adapter); return; @@ -1933,6 +1973,7 @@ timeout: txr->me, txr->tx_avail, txr->next_to_clean); adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; adapter->watchdog_events++; + IGB_TX_UNLOCK(txr); igb_init_locked(adapter); } @@ -2473,8 +2514,8 @@ igb_setup_msix(struct adapter *adapter) if ((adapter->hw.mac.type == e1000_82575) && (queues > 4)) queues = 4; - /* Limit the VF adapter to one queues */ - if ((adapter->hw.mac.type == e1000_vfadapt) && (queues > 2)) + /* Limit the VF adapter to one queue */ + if (adapter->hw.mac.type == e1000_vfadapt) queues = 1; /* @@ -2653,7 +2694,7 @@ igb_reset(struct adapter *adapter) * Setup networking device structure and register an interface. * **********************************************************************/ -static void +static int igb_setup_interface(device_t dev, struct adapter *adapter) { struct ifnet *ifp; @@ -2661,8 +2702,10 @@ igb_setup_interface(device_t dev, struct adapter *adapter) INIT_DEBUGOUT("igb_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - panic("%s: can not if_alloc()", device_get_nameunit(dev)); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_init = igb_init; @@ -2739,6 +2782,7 @@ igb_setup_interface(device_t dev, struct adapter *adapter) } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + return (0); } @@ -4166,9 +4210,11 @@ igb_rx_discard(struct rx_ring *rxr, int i) mp = rbuf->m_pack; /* Reuse loaded DMA map and just update mbuf chain */ - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - mh->m_next = NULL; + if (mh) { /* with no hdr split would be null */ + mh->m_len = MHLEN; + mh->m_flags |= M_PKTHDR; + mh->m_next = NULL; + } mp->m_len = mp->m_pkthdr.len = adapter->rx_mbuf_sz; mp->m_data = mp->m_ext.ext_buf; @@ -4779,7 +4825,12 @@ igb_update_stats_counters(struct adapter *adapter) stats->rlec += E1000_READ_REG(hw, E1000_RLEC); stats->xonrxc += E1000_READ_REG(hw, E1000_XONRXC); stats->xontxc += E1000_READ_REG(hw, E1000_XONTXC); - stats->xoffrxc += E1000_READ_REG(hw, E1000_XOFFRXC); + /* + ** For watchdog management we need to know if we have been + ** paused during the last interval, so capture that here. + */ + adapter->pause_frames = E1000_READ_REG(&adapter->hw, E1000_XOFFRXC); + stats->xoffrxc += adapter->pause_frames; stats->xofftxc += E1000_READ_REG(hw, E1000_XOFFTXC); stats->fcruc += E1000_READ_REG(hw, E1000_FCRUC); stats->prc64 += E1000_READ_REG(hw, E1000_PRC64); @@ -4797,9 +4848,9 @@ igb_update_stats_counters(struct adapter *adapter) /* Both registers clear on the read of the high dword */ stats->gorc += E1000_READ_REG(hw, E1000_GORCL) + - ((u64)E1000_READ_REG(hw, E1000_GORCH) << 32); + ((u64)E1000_READ_REG(hw, E1000_GORCH) << 32); stats->gotc += E1000_READ_REG(hw, E1000_GOTCL) + - ((u64)E1000_READ_REG(hw, E1000_GOTCH) << 32) ; + ((u64)E1000_READ_REG(hw, E1000_GOTCH) << 32); stats->rnbc += E1000_READ_REG(hw, E1000_RNBC); stats->ruc += E1000_READ_REG(hw, E1000_RUC); @@ -4893,7 +4944,8 @@ igb_vf_init_stats(struct adapter *adapter) struct e1000_vf_stats *stats; stats = (struct e1000_vf_stats *)adapter->stats; - + if (stats == NULL) + return; stats->last_gprc = E1000_READ_REG(hw, E1000_VFGPRC); stats->last_gorc = E1000_READ_REG(hw, E1000_VFGORC); stats->last_gptc = E1000_READ_REG(hw, E1000_VFGPTC); @@ -4929,77 +4981,16 @@ igb_update_vf_stats_counters(struct adapter *adapter) stats->last_mprc, stats->mprc); } - -/** igb_sysctl_tdh_handler - Handler function - * Retrieves the TDH value from the hardware - */ -static int -igb_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) +/* Export a single 32-bit register via a read-only sysctl. */ +static int +igb_sysctl_reg_handler(SYSCTL_HANDLER_ARGS) { - int error; + struct adapter *adapter; + u_int val; - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; - - unsigned val = E1000_READ_REG(&txr->adapter->hw, E1000_TDH(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** igb_sysctl_tdt_handler - Handler function - * Retrieves the TDT value from the hardware - */ -static int -igb_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; - - unsigned val = E1000_READ_REG(&txr->adapter->hw, E1000_TDT(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** igb_sysctl_rdh_handler - Handler function - * Retrieves the RDH value from the hardware - */ -static int -igb_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; - - unsigned val = E1000_READ_REG(&rxr->adapter->hw, E1000_RDH(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** igb_sysctl_rdt_handler - Handler function - * Retrieves the RDT value from the hardware - */ -static int -igb_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; - - unsigned val = E1000_READ_REG(&rxr->adapter->hw, E1000_RDT(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; + adapter = oidp->oid_arg1; + val = E1000_READ_REG(&adapter->hw, oidp->oid_arg2); + return (sysctl_handle_int(oidp, &val, 0, req)); } /* @@ -5008,7 +4999,6 @@ igb_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) static void igb_add_hw_stats(struct adapter *adapter) { - device_t dev = adapter->dev; struct tx_ring *txr = adapter->tx_rings; @@ -5035,6 +5025,12 @@ igb_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_dma_fail", CTLFLAG_RD, &adapter->no_tx_dma_setup, "Driver tx dma failure in xmit"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "rx_overruns", + CTLFLAG_RD, &adapter->rx_overruns, + "RX overruns"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_timeouts", + CTLFLAG_RD, &adapter->watchdog_events, + "Watchdog timeouts"); SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "device_control", CTLFLAG_RD, &adapter->device_control, @@ -5061,19 +5057,21 @@ igb_add_hw_stats(struct adapter *adapter) CTLFLAG_RD, &adapter->hw.fc.low_water, 0, "Flow Control Low Watermark"); - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) { + struct lro_ctrl *lro = &rxr->lro; + snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, CTLFLAG_RD, NULL, "Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", - CTLFLAG_RD, txr, sizeof(txr), - igb_sysctl_tdh_handler, "IU", + CTLFLAG_RD, adapter, E1000_TDH(txr->me), + igb_sysctl_reg_handler, "IU", "Transmit Descriptor Head"); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", - CTLFLAG_RD, txr, sizeof(txr), - igb_sysctl_tdt_handler, "IU", + CTLFLAG_RD, adapter, E1000_TDT(txr->me), + igb_sysctl_reg_handler, "IU", "Transmit Descriptor Tail"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", CTLFLAG_RD, &txr->no_desc_avail, @@ -5081,28 +5079,14 @@ igb_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "tx_packets", CTLFLAG_RD, &txr->tx_packets, "Queue Packets Transmitted"); - } - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - - struct lro_ctrl *lro = &rxr->lro; - - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", - CTLFLAG_RD, rxr, sizeof(rxr), - igb_sysctl_rdh_handler, "IU", + CTLFLAG_RD, adapter, E1000_RDH(rxr->me), + igb_sysctl_reg_handler, "IU", "Receive Descriptor Head"); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", - CTLFLAG_RD, rxr, sizeof(rxr), - igb_sysctl_rdt_handler, "IU", + CTLFLAG_RD, adapter, E1000_RDT(rxr->me), + igb_sysctl_reg_handler, "IU", "Receive Descriptor Tail"); SYSCTL_ADD_QUAD(ctx, queue_list, OID_AUTO, "rx_packets", CTLFLAG_RD, &rxr->rx_packets, @@ -5118,7 +5102,7 @@ igb_add_hw_stats(struct adapter *adapter) "LRO Flushed"); } - /* MAC stats get the own sub node */ + /* MAC stats get their own sub node */ stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", CTLFLAG_RD, NULL, "MAC Statistics"); @@ -5138,9 +5122,9 @@ igb_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd", CTLFLAG_RD, &stats->gorc, "Good Octets Received"); - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octest_txd", + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", CTLFLAG_RD, &stats->gotc, - "Good Octest Transmitted"); + "Good Octets Transmitted"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd", CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); @@ -5202,12 +5186,6 @@ igb_add_hw_stats(struct adapter *adapter) SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs", CTLFLAG_RD, &stats->cexterr, "Collision/Carrier extension errors"); - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_overruns", - CTLFLAG_RD, &adapter->rx_overruns, - "RX overruns"); - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "watchdog_timeouts", - CTLFLAG_RD, &adapter->watchdog_events, - "Watchdog timeouts"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_recvd", CTLFLAG_RD, &stats->xonrxc, "XON Received"); @@ -5256,9 +5234,9 @@ igb_add_hw_stats(struct adapter *adapter) "Good Octets Received"); /* Packet Transmission Stats */ - SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octest_txd", + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", CTLFLAG_RD, &stats->gotc, - "Good Octest Transmitted"); + "Good Octets Transmitted"); SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", CTLFLAG_RD, &stats->tpt, "Total Packets Transmitted"); diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index 4388e0769f2..059a8b9cb0d 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -203,14 +203,6 @@ /* PCI Config defines */ #define IGB_MSIX_BAR 3 -/* -** This is the total number of MSIX vectors you wish -** to use, it also controls the size of resources. -** The 82575 has a total of 10, 82576 has 25. Set this -** to the real amount you need to streamline data storage. -*/ -#define IGB_MSIX_VEC 6 /* MSIX vectors configured */ - /* Defines for printing debug information */ #define DEBUG_INIT 0 #define DEBUG_IOCTL 0 @@ -247,12 +239,6 @@ #define IGB_INTS_PER_SEC 8000 #define IGB_DEFAULT_ITR 1000000000/(IGB_INTS_PER_SEC * 256) - -/* Header split codes for get_buf */ -#define IGB_CLEAN_HEADER 0x01 -#define IGB_CLEAN_PAYLOAD 0x02 -#define IGB_CLEAN_BOTH (IGB_CLEAN_HEADER | IGB_CLEAN_PAYLOAD) - #define IGB_LINK_ITR 2000 /* Precision Time Sync (IEEE 1588) defines */ @@ -385,6 +371,7 @@ struct adapter { int if_flags; int max_frame_size; int min_frame_size; + int pause_frames; struct mtx core_mtx; int igb_insert_vlan_header; u16 num_queues; @@ -412,6 +399,9 @@ struct adapter { struct tx_ring *tx_rings; u16 num_tx_desc; + /* Multicast array pointer */ + u8 *mta; + /* * Receive rings */ diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c index 1f03f7b46d2..846d6bfef9a 100644 --- a/sys/dev/e1000/if_lem.c +++ b/sys/dev/e1000/if_lem.c @@ -83,15 +83,10 @@ #include "e1000_api.h" #include "if_lem.h" -/********************************************************************* - * Set this to one to display debug statistics - *********************************************************************/ -int lem_display_debug_stats = 0; - /********************************************************************* * Legacy Em Driver version: *********************************************************************/ -char lem_driver_version[] = "1.0.1"; +char lem_driver_version[] = "1.0.2"; /********************************************************************* @@ -186,7 +181,7 @@ static int lem_allocate_irq(struct adapter *adapter); static void lem_free_pci_resources(struct adapter *); static void lem_local_timer(void *); static int lem_hardware_init(struct adapter *); -static void lem_setup_interface(device_t, struct adapter *); +static int lem_setup_interface(device_t, struct adapter *); static void lem_setup_transmit_structures(struct adapter *); static void lem_initialize_transmit_unit(struct adapter *); static int lem_setup_receive_structures(struct adapter *); @@ -196,6 +191,7 @@ static void lem_disable_intr(struct adapter *); static void lem_free_transmit_structures(struct adapter *); static void lem_free_receive_structures(struct adapter *); static void lem_update_stats_counters(struct adapter *); +static void lem_add_hw_stats(struct adapter *adapter); static void lem_txeof(struct adapter *); static void lem_tx_purge(struct adapter *); static int lem_allocate_receive_structures(struct adapter *); @@ -211,7 +207,6 @@ static void lem_transmit_checksum_setup(struct adapter *, struct mbuf *, static void lem_set_promisc(struct adapter *); static void lem_disable_promisc(struct adapter *); static void lem_set_multi(struct adapter *); -static void lem_print_hw_stats(struct adapter *); static void lem_update_link_status(struct adapter *); static int lem_get_buf(struct adapter *, int); #if __FreeBSD_version >= 700029 @@ -228,11 +223,9 @@ static void lem_82547_move_tail(void *); static int lem_dma_malloc(struct adapter *, bus_size_t, struct em_dma_alloc *, int); static void lem_dma_free(struct adapter *, struct em_dma_alloc *); -static void lem_print_debug_info(struct adapter *); +static int lem_sysctl_nvm_info(SYSCTL_HANDLER_ARGS); static void lem_print_nvm_info(struct adapter *); static int lem_is_valid_ether_addr(u8 *); -static int lem_sysctl_stats(SYSCTL_HANDLER_ARGS); -static int lem_sysctl_debug_info(SYSCTL_HANDLER_ARGS); static u32 lem_fill_descriptors (bus_addr_t address, u32 length, PDESC_ARRAY desc_array); static int lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS); @@ -417,13 +410,8 @@ lem_attach(device_t dev) /* SYSCTL stuff */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, - lem_sysctl_debug_info, "I", "Debug Information"); - - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "stats", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, - lem_sysctl_stats, "I", "Statistics"); + OID_AUTO, "nvm", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, + lem_sysctl_nvm_info, "I", "NVM Information"); callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); callout_init_mtx(&adapter->tx_fifo_timer, &adapter->tx_mtx, 0); @@ -550,6 +538,15 @@ lem_attach(device_t dev) adapter->rx_desc_base = (struct e1000_rx_desc *)adapter->rxdma.dma_vaddr; + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(u8) * ETH_ADDR_LEN * + MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_hw_init; + } + /* ** Start from a known state, this is ** important in reading the nvm and @@ -620,7 +617,8 @@ lem_attach(device_t dev) lem_get_wakeup(dev); /* Setup OS specific network interface */ - lem_setup_interface(dev, adapter); + if (lem_setup_interface(dev, adapter) != 0) + goto err_rx_struct; /* Initialize statistics */ lem_update_stats_counters(adapter); @@ -648,6 +646,8 @@ lem_attach(device_t dev) lem_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); #endif + lem_add_hw_stats(adapter); + /* Non-AMT based hardware can now take control from firmware */ if (adapter->has_manage && !adapter->has_amt) lem_get_hw_control(adapter); @@ -672,7 +672,10 @@ err_rx_desc: lem_dma_free(adapter, &adapter->txdma); err_tx_desc: err_pci: + if (adapter->ifp != NULL) + if_free(adapter->ifp); lem_free_pci_resources(adapter); + free(adapter->mta, M_DEVBUF); EM_TX_LOCK_DESTROY(adapter); EM_RX_LOCK_DESTROY(adapter); EM_CORE_LOCK_DESTROY(adapter); @@ -759,6 +762,7 @@ lem_detach(device_t dev) } lem_release_hw_control(adapter); + free(adapter->mta, M_DEVBUF); EM_TX_LOCK_DESTROY(adapter); EM_RX_LOCK_DESTROY(adapter); EM_CORE_LOCK_DESTROY(adapter); @@ -1749,6 +1753,7 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp) */ tx_buffer = &adapter->tx_buffer_area[first]; tx_buffer->next_eop = last; + adapter->watchdog_time = ticks; /* * Advance the Transmit Descriptor Tail (TDT), this tells the E1000 @@ -1939,6 +1944,9 @@ lem_set_multi(struct adapter *adapter) IOCTL_DEBUGOUT("lem_set_multi: begin"); + mta = adapter->mta; + bzero(mta, sizeof(u8) * ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES); + if (adapter->hw.mac.type == e1000_82542 && adapter->hw.revision_id == E1000_REVISION_2) { reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); @@ -1949,13 +1957,6 @@ lem_set_multi(struct adapter *adapter) msec_delay(5); } - /* Allocate temporary memory to setup array */ - mta = malloc(sizeof(u8) * - (ETH_ADDR_LEN * MAX_NUM_MULTICAST_ADDRESSES), - M_DEVBUF, M_NOWAIT | M_ZERO); - if (mta == NULL) - panic("lem_set_multi memory failure\n"); - #if __FreeBSD_version < 800000 IF_ADDR_LOCK(ifp); #else @@ -1993,7 +1994,6 @@ lem_set_multi(struct adapter *adapter) if (adapter->hw.bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) e1000_pci_set_mwi(&adapter->hw); } - free(mta, M_DEVBUF); } @@ -2008,18 +2008,12 @@ static void lem_local_timer(void *arg) { struct adapter *adapter = arg; - struct ifnet *ifp = adapter->ifp; EM_CORE_LOCK_ASSERT(adapter); - taskqueue_enqueue(adapter->tq, - &adapter->rxtx_task); lem_update_link_status(adapter); lem_update_stats_counters(adapter); - if (lem_display_debug_stats && ifp->if_drv_flags & IFF_DRV_RUNNING) - lem_print_hw_stats(adapter); - lem_smartspeed(adapter); /* @@ -2388,7 +2382,7 @@ lem_hardware_init(struct adapter *adapter) * Setup networking device structure and register an interface. * **********************************************************************/ -static void +static int lem_setup_interface(device_t dev, struct adapter *adapter) { struct ifnet *ifp; @@ -2396,8 +2390,10 @@ lem_setup_interface(device_t dev, struct adapter *adapter) INIT_DEBUGOUT("lem_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - panic("%s: can not if_alloc()", device_get_nameunit(dev)); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_init = lem_init; @@ -2473,6 +2469,7 @@ lem_setup_interface(device_t dev, struct adapter *adapter) } ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + return (0); } @@ -4256,8 +4253,10 @@ lem_update_stats_counters(struct adapter *adapter) /* For the 64-bit byte counters the low dword must be read first. */ /* Both registers clear on the read of the high dword */ - adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCH); - adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCH); + adapter->stats.gorc += E1000_READ_REG(&adapter->hw, E1000_GORCL) + + ((u64)E1000_READ_REG(&adapter->hw, E1000_GORCH) << 32); + adapter->stats.gotc += E1000_READ_REG(&adapter->hw, E1000_GOTCL) + + ((u64)E1000_READ_REG(&adapter->hw, E1000_GOTCH) << 32); adapter->stats.rnbc += E1000_READ_REG(&adapter->hw, E1000_RNBC); adapter->stats.ruc += E1000_READ_REG(&adapter->hw, E1000_RUC); @@ -4308,109 +4307,247 @@ lem_update_stats_counters(struct adapter *adapter) adapter->stats.latecol + adapter->watchdog_events; } - -/********************************************************************** - * - * This routine is called only when lem_display_debug_stats is enabled. - * This routine provides a way to take a look at important statistics - * maintained by the driver and hardware. - * - **********************************************************************/ -static void -lem_print_debug_info(struct adapter *adapter) +/* Export a single 32-bit register via a read-only sysctl. */ +static int +lem_sysctl_reg_handler(SYSCTL_HANDLER_ARGS) { - device_t dev = adapter->dev; - u8 *hw_addr = adapter->hw.hw_addr; + struct adapter *adapter; + u_int val; - device_printf(dev, "Adapter hardware address = %p \n", hw_addr); - device_printf(dev, "CTRL = 0x%x RCTL = 0x%x \n", - E1000_READ_REG(&adapter->hw, E1000_CTRL), - E1000_READ_REG(&adapter->hw, E1000_RCTL)); - device_printf(dev, "Packet buffer = Tx=%dk Rx=%dk \n", - ((E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff0000) >> 16),\ - (E1000_READ_REG(&adapter->hw, E1000_PBA) & 0xffff) ); - device_printf(dev, "Flow control watermarks high = %d low = %d\n", - adapter->hw.fc.high_water, - adapter->hw.fc.low_water); - device_printf(dev, "tx_int_delay = %d, tx_abs_int_delay = %d\n", - E1000_READ_REG(&adapter->hw, E1000_TIDV), - E1000_READ_REG(&adapter->hw, E1000_TADV)); - device_printf(dev, "rx_int_delay = %d, rx_abs_int_delay = %d\n", - E1000_READ_REG(&adapter->hw, E1000_RDTR), - E1000_READ_REG(&adapter->hw, E1000_RADV)); - device_printf(dev, "fifo workaround = %lld, fifo_reset_count = %lld\n", - (long long)adapter->tx_fifo_wrk_cnt, - (long long)adapter->tx_fifo_reset_cnt); - device_printf(dev, "hw tdh = %d, hw tdt = %d\n", - E1000_READ_REG(&adapter->hw, E1000_TDH(0)), - E1000_READ_REG(&adapter->hw, E1000_TDT(0))); - device_printf(dev, "hw rdh = %d, hw rdt = %d\n", - E1000_READ_REG(&adapter->hw, E1000_RDH(0)), - E1000_READ_REG(&adapter->hw, E1000_RDT(0))); - device_printf(dev, "Num Tx descriptors avail = %d\n", - adapter->num_tx_desc_avail); - device_printf(dev, "Tx Descriptors not avail1 = %ld\n", - adapter->no_tx_desc_avail1); - device_printf(dev, "Tx Descriptors not avail2 = %ld\n", - adapter->no_tx_desc_avail2); - device_printf(dev, "Std mbuf failed = %ld\n", - adapter->mbuf_alloc_failed); - device_printf(dev, "Std mbuf cluster failed = %ld\n", - adapter->mbuf_cluster_failed); - device_printf(dev, "Driver dropped packets = %ld\n", - adapter->dropped_pkts); - device_printf(dev, "Driver tx dma failure in encap = %ld\n", - adapter->no_tx_dma_setup); + adapter = oidp->oid_arg1; + val = E1000_READ_REG(&adapter->hw, oidp->oid_arg2); + return (sysctl_handle_int(oidp, &val, 0, req)); } +/* + * Add sysctl variables, one per statistic, to the system. + */ static void -lem_print_hw_stats(struct adapter *adapter) +lem_add_hw_stats(struct adapter *adapter) { device_t dev = adapter->dev; - device_printf(dev, "Excessive collisions = %lld\n", - (long long)adapter->stats.ecol); -#if (DEBUG_HW > 0) /* Dont output these errors normally */ - device_printf(dev, "Symbol errors = %lld\n", - (long long)adapter->stats.symerrs); -#endif - device_printf(dev, "Sequence errors = %lld\n", - (long long)adapter->stats.sec); - device_printf(dev, "Defer count = %lld\n", - (long long)adapter->stats.dc); - device_printf(dev, "Missed Packets = %lld\n", - (long long)adapter->stats.mpc); - device_printf(dev, "Receive No Buffers = %lld\n", - (long long)adapter->stats.rnbc); - /* RLEC is inaccurate on some hardware, calculate our own. */ - device_printf(dev, "Receive Length Errors = %lld\n", - ((long long)adapter->stats.roc + (long long)adapter->stats.ruc)); - device_printf(dev, "Receive errors = %lld\n", - (long long)adapter->stats.rxerrc); - device_printf(dev, "Crc errors = %lld\n", - (long long)adapter->stats.crcerrs); - device_printf(dev, "Alignment errors = %lld\n", - (long long)adapter->stats.algnerrc); - device_printf(dev, "Collision/Carrier extension errors = %lld\n", - (long long)adapter->stats.cexterr); - device_printf(dev, "RX overruns = %ld\n", adapter->rx_overruns); - device_printf(dev, "watchdog timeouts = %ld\n", - adapter->watchdog_events); - device_printf(dev, "RX MSIX IRQ = %ld TX MSIX IRQ = %ld" - " LINK MSIX IRQ = %ld\n", adapter->rx_irq, - adapter->tx_irq , adapter->link_irq); - device_printf(dev, "XON Rcvd = %lld\n", - (long long)adapter->stats.xonrxc); - device_printf(dev, "XON Xmtd = %lld\n", - (long long)adapter->stats.xontxc); - device_printf(dev, "XOFF Rcvd = %lld\n", - (long long)adapter->stats.xoffrxc); - device_printf(dev, "XOFF Xmtd = %lld\n", - (long long)adapter->stats.xofftxc); - device_printf(dev, "Good Packets Rcvd = %lld\n", - (long long)adapter->stats.gprc); - device_printf(dev, "Good Packets Xmtd = %lld\n", - (long long)adapter->stats.gptc); + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + struct e1000_hw_stats *stats = &adapter->stats; + + struct sysctl_oid *stat_node; + struct sysctl_oid_list *stat_list; + + /* Driver Statistics */ + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_alloc_fail", + CTLFLAG_RD, &adapter->mbuf_alloc_failed, + "Std mbuf failed"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "cluster_alloc_fail", + CTLFLAG_RD, &adapter->mbuf_cluster_failed, + "Std mbuf cluster failed"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", + CTLFLAG_RD, &adapter->dropped_pkts, + "Driver dropped packets"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_dma_fail", + CTLFLAG_RD, &adapter->no_tx_dma_setup, + "Driver tx dma failure in xmit"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_desc_fail1", + CTLFLAG_RD, &adapter->no_tx_desc_avail1, + "Not enough tx descriptors failure in xmit"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tx_desc_fail2", + CTLFLAG_RD, &adapter->no_tx_desc_avail2, + "Not enough tx descriptors failure in xmit"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "rx_overruns", + CTLFLAG_RD, &adapter->rx_overruns, + "RX overruns"); + SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_timeouts", + CTLFLAG_RD, &adapter->watchdog_events, + "Watchdog timeouts"); + + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "device_control", + CTLFLAG_RD, adapter, E1000_CTRL, + lem_sysctl_reg_handler, "IU", + "Device Control Register"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_control", + CTLFLAG_RD, adapter, E1000_RCTL, + lem_sysctl_reg_handler, "IU", + "Receiver Control Register"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_high_water", + CTLFLAG_RD, &adapter->hw.fc.high_water, 0, + "Flow Control High Watermark"); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "fc_low_water", + CTLFLAG_RD, &adapter->hw.fc.low_water, 0, + "Flow Control Low Watermark"); + SYSCTL_ADD_QUAD(ctx, child, OID_AUTO, "fifo_workaround", + CTLFLAG_RD, &adapter->tx_fifo_wrk_cnt, + "TX FIFO workaround events"); + SYSCTL_ADD_QUAD(ctx, child, OID_AUTO, "fifo_reset", + CTLFLAG_RD, &adapter->tx_fifo_reset_cnt, + "TX FIFO resets"); + + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txd_head", + CTLFLAG_RD, adapter, E1000_TDH(0), + lem_sysctl_reg_handler, "IU", + "Transmit Descriptor Head"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "txd_tail", + CTLFLAG_RD, adapter, E1000_TDT(0), + lem_sysctl_reg_handler, "IU", + "Transmit Descriptor Tail"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxd_head", + CTLFLAG_RD, adapter, E1000_RDH(0), + lem_sysctl_reg_handler, "IU", + "Receive Descriptor Head"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxd_tail", + CTLFLAG_RD, adapter, E1000_RDT(0), + lem_sysctl_reg_handler, "IU", + "Receive Descriptor Tail"); + + + /* MAC stats get their own sub node */ + + stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", + CTLFLAG_RD, NULL, "Statistics"); + stat_list = SYSCTL_CHILDREN(stat_node); + + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "excess_coll", + CTLFLAG_RD, &stats->ecol, + "Excessive collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "single_coll", + CTLFLAG_RD, &stats->scc, + "Single collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "multiple_coll", + CTLFLAG_RD, &stats->mcc, + "Multiple collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "late_coll", + CTLFLAG_RD, &stats->latecol, + "Late collisions"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "collision_count", + CTLFLAG_RD, &stats->colc, + "Collision Count"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "symbol_errors", + CTLFLAG_RD, &adapter->stats.symerrs, + "Symbol Errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "sequence_errors", + CTLFLAG_RD, &adapter->stats.sec, + "Sequence Errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "defer_count", + CTLFLAG_RD, &adapter->stats.dc, + "Defer Count"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "missed_packets", + CTLFLAG_RD, &adapter->stats.mpc, + "Missed Packets"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_no_buff", + CTLFLAG_RD, &adapter->stats.rnbc, + "Receive No Buffers"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_undersize", + CTLFLAG_RD, &adapter->stats.ruc, + "Receive Undersize"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", + CTLFLAG_RD, &adapter->stats.rfc, + "Fragmented Packets Received "); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_oversize", + CTLFLAG_RD, &adapter->stats.roc, + "Oversized Packets Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_jabber", + CTLFLAG_RD, &adapter->stats.rjc, + "Recevied Jabber"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "recv_errs", + CTLFLAG_RD, &adapter->stats.rxerrc, + "Receive Errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "crc_errs", + CTLFLAG_RD, &adapter->stats.crcerrs, + "CRC errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "alignment_errs", + CTLFLAG_RD, &adapter->stats.algnerrc, + "Alignment Errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "coll_ext_errs", + CTLFLAG_RD, &adapter->stats.cexterr, + "Collision/Carrier extension errors"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_recvd", + CTLFLAG_RD, &adapter->stats.xonrxc, + "XON Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xon_txd", + CTLFLAG_RD, &adapter->stats.xontxc, + "XON Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", + CTLFLAG_RD, &adapter->stats.xoffrxc, + "XOFF Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "xoff_txd", + CTLFLAG_RD, &adapter->stats.xofftxc, + "XOFF Transmitted"); + + /* Packet Reception Stats */ + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_recvd", + CTLFLAG_RD, &adapter->stats.tpr, + "Total Packets Received "); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_recvd", + CTLFLAG_RD, &adapter->stats.gprc, + "Good Packets Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_recvd", + CTLFLAG_RD, &adapter->stats.bprc, + "Broadcast Packets Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_recvd", + CTLFLAG_RD, &adapter->stats.mprc, + "Multicast Packets Received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", + CTLFLAG_RD, &adapter->stats.prc64, + "64 byte frames received "); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", + CTLFLAG_RD, &adapter->stats.prc127, + "65-127 byte frames received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", + CTLFLAG_RD, &adapter->stats.prc255, + "128-255 byte frames received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", + CTLFLAG_RD, &adapter->stats.prc511, + "256-511 byte frames received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", + CTLFLAG_RD, &adapter->stats.prc1023, + "512-1023 byte frames received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", + CTLFLAG_RD, &adapter->stats.prc1522, + "1023-1522 byte frames received"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_recvd", + CTLFLAG_RD, &adapter->stats.gorc, + "Good Octets Received"); + + /* Packet Transmission Stats */ + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", + CTLFLAG_RD, &adapter->stats.gotc, + "Good Octets Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", + CTLFLAG_RD, &adapter->stats.tpt, + "Total Packets Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", + CTLFLAG_RD, &adapter->stats.gptc, + "Good Packets Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", + CTLFLAG_RD, &adapter->stats.bptc, + "Broadcast Packets Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", + CTLFLAG_RD, &adapter->stats.mptc, + "Multicast Packets Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", + CTLFLAG_RD, &adapter->stats.ptc64, + "64 byte frames transmitted "); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", + CTLFLAG_RD, &adapter->stats.ptc127, + "65-127 byte frames transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", + CTLFLAG_RD, &adapter->stats.ptc255, + "128-255 byte frames transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", + CTLFLAG_RD, &adapter->stats.ptc511, + "256-511 byte frames transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", + CTLFLAG_RD, &adapter->stats.ptc1023, + "512-1023 byte frames transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", + CTLFLAG_RD, &adapter->stats.ptc1522, + "1024-1522 byte frames transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_txd", + CTLFLAG_RD, &adapter->stats.tsctc, + "TSO Contexts Transmitted"); + SYSCTL_ADD_QUAD(ctx, stat_list, OID_AUTO, "tso_ctx_fail", + CTLFLAG_RD, &adapter->stats.tsctfc, + "TSO Contexts Failed"); } /********************************************************************** @@ -4420,6 +4557,33 @@ lem_print_hw_stats(struct adapter *adapter) * 32 words, stuff that matters is in that extent. * **********************************************************************/ + +static int +lem_sysctl_nvm_info(SYSCTL_HANDLER_ARGS) +{ + struct adapter *adapter; + int error; + int result; + + result = -1; + error = sysctl_handle_int(oidp, &result, 0, req); + + if (error || !req->newptr) + return (error); + + /* + * This value will cause a hex dump of the + * first 32 16-bit words of the EEPROM to + * the screen. + */ + if (result == 1) { + adapter = (struct adapter *)arg1; + lem_print_nvm_info(adapter); + } + + return (error); +} + static void lem_print_nvm_info(struct adapter *adapter) { @@ -4440,58 +4604,6 @@ lem_print_nvm_info(struct adapter *adapter) printf("\n"); } -static int -lem_sysctl_debug_info(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter; - int error; - int result; - - result = -1; - error = sysctl_handle_int(oidp, &result, 0, req); - - if (error || !req->newptr) - return (error); - - if (result == 1) { - adapter = (struct adapter *)arg1; - lem_print_debug_info(adapter); - } - /* - * This value will cause a hex dump of the - * first 32 16-bit words of the EEPROM to - * the screen. - */ - if (result == 2) { - adapter = (struct adapter *)arg1; - lem_print_nvm_info(adapter); - } - - return (error); -} - - -static int -lem_sysctl_stats(SYSCTL_HANDLER_ARGS) -{ - struct adapter *adapter; - int error; - int result; - - result = -1; - error = sysctl_handle_int(oidp, &result, 0, req); - - if (error || !req->newptr) - return (error); - - if (result == 1) { - adapter = (struct adapter *)arg1; - lem_print_hw_stats(adapter); - } - - return (error); -} - static int lem_sysctl_int_delay(SYSCTL_HANDLER_ARGS) { diff --git a/sys/dev/e1000/if_lem.h b/sys/dev/e1000/if_lem.h index 13c2cbc4dd3..2f76aa8041b 100644 --- a/sys/dev/e1000/if_lem.h +++ b/sys/dev/e1000/if_lem.h @@ -339,6 +339,8 @@ struct adapter { bool has_manage; bool has_amt; + /* Multicast array memory */ + u8 *mta; /* Info about the board itself */ uint8_t link_active; uint16_t link_speed; @@ -405,9 +407,6 @@ struct adapter { unsigned long no_tx_dma_setup; unsigned long watchdog_events; unsigned long rx_overruns; - unsigned long rx_irq; - unsigned long tx_irq; - unsigned long link_irq; /* 82547 workaround */ uint32_t tx_fifo_size; diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 839e2a52cc9..6213ce763d7 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -1476,9 +1476,12 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst) } } else { /* NE2000s are a pain */ - unsigned char *data; + uint8_t *data; int len, wantbyte; - unsigned char savebyte[2]; + union { + uint16_t w; + uint8_t b[2]; + } saveword; wantbyte = 0; @@ -1488,9 +1491,9 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst) data = mtod(m, caddr_t); /* finish the last word */ if (wantbyte) { - savebyte[1] = *data; + saveword.b[1] = *data; ed_asic_outw(sc, ED_NOVELL_DATA, - *(u_short *)savebyte); + saveword.w); data++; len--; wantbyte = 0; @@ -1504,7 +1507,7 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst) } /* save last byte, if necessary */ if (len == 1) { - savebyte[0] = *data; + saveword.b[0] = *data; wantbyte = 1; } } @@ -1512,7 +1515,7 @@ ed_pio_write_mbufs(struct ed_softc *sc, struct mbuf *m, bus_size_t dst) } /* spit last byte */ if (wantbyte) - ed_asic_outw(sc, ED_NOVELL_DATA, *(u_short *)savebyte); + ed_asic_outw(sc, ED_NOVELL_DATA, saveword.w); } /* diff --git a/sys/dev/ed/if_ed_isa.c b/sys/dev/ed/if_ed_isa.c index 0d7a583c020..afaa37758a3 100644 --- a/sys/dev/ed/if_ed_isa.c +++ b/sys/dev/ed/if_ed_isa.c @@ -58,6 +58,7 @@ static struct isa_pnp_id ed_ids[] = { { 0x0131d805, NULL }, /* ANX3101 */ { 0x4cf48906, NULL }, /* ATIf44c */ { 0x01200507, NULL }, /* AXE2001 */ + { 0x0115180e, NULL }, /* CPX1501 */ { 0x0090252a, NULL }, /* JQE9000 */ { 0x0020832e, NULL }, /* KTC2000 */ { 0xd680d041, NULL }, /* PNP80d6 */ diff --git a/sys/dev/ed/if_ed_novell.c b/sys/dev/ed/if_ed_novell.c index 90f2068dc8f..d81b50997bc 100644 --- a/sys/dev/ed/if_ed_novell.c +++ b/sys/dev/ed/if_ed_novell.c @@ -123,39 +123,53 @@ ed_probe_Novell_generic(device_t dev, int flags) ed_nic_outb(sc, ED_P0_PSTART, 8192 / ED_PAGE_SIZE); ed_nic_outb(sc, ED_P0_PSTOP, 16384 / ED_PAGE_SIZE); - sc->isa16bit = 0; - /* - * Write a test pattern in byte mode. If this fails, then there - * probably isn't any memory at 8k - which likely means that the board - * is an NE2000. + * Some devices identify themselves. Some of those devices + * can't handle being probed, so we allow forcing a mode. If + * these flags are set, force it, otherwise probe. */ - ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); - ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); - - if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { + if (flags & ED_FLAGS_FORCE_8BIT_MODE) { + sc->isa16bit = 0; sc->type = ED_TYPE_NE1000; sc->type_str = "NE1000"; - } else { - - /* Not an NE1000 - try NE2000 */ + } else if (flags & ED_FLAGS_FORCE_16BIT_MODE) { + sc->isa16bit = 1; + sc->type = ED_TYPE_NE2000; + sc->type_str = "NE2000"; ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); ed_nic_outb(sc, ED_P0_PSTART, 16384 / ED_PAGE_SIZE); ed_nic_outb(sc, ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); - - sc->isa16bit = 1; - + } else { /* - * Write a test pattern in word mode. If this also fails, then - * we don't know what this board is. + * Write a test pattern in byte mode. If this fails, then there + * probably isn't any memory at 8k - which likely means that the board + * is an NE2000. */ - ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); - ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); + ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern)); + ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern)); + if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { - sc->type = ED_TYPE_NE2000; - sc->type_str = "NE2000"; + sc->type = ED_TYPE_NE1000; + sc->type_str = "NE1000"; + sc->isa16bit = 0; } else { - return (ENXIO); + /* Not an NE1000 - try NE2000 */ + sc->isa16bit = 1; + ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); + ed_nic_outb(sc, ED_P0_PSTART, 16384 / ED_PAGE_SIZE); + ed_nic_outb(sc, ED_P0_PSTOP, 32768 / ED_PAGE_SIZE); + /* + * Write a test pattern in word mode. If this also fails, then + * we don't know what this board is. + */ + ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); + ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); + if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { + sc->type = ED_TYPE_NE2000; + sc->type_str = "NE2000"; + } else { + return (ENXIO); + } } } sc->chip_type = ED_CHIP_TYPE_DP8390; diff --git a/sys/dev/ed/if_ed_pccard.c b/sys/dev/ed/if_ed_pccard.c index b9c1cad334c..ed8704b7a9e 100644 --- a/sys/dev/ed/if_ed_pccard.c +++ b/sys/dev/ed/if_ed_pccard.c @@ -578,25 +578,21 @@ ed_pccard_attach(device_t dev) goto bad; if (sc->chip_type == ED_CHIP_TYPE_DL10019 || sc->chip_type == ED_CHIP_TYPE_DL10022) { - /* Probe for an MII bus, but ignore errors. */ + /* Try to attach an MII bus, but ignore errors. */ ed_pccard_dl100xx_mii_reset(sc); - (void)mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, - ed_ifmedia_sts); + (void)mii_attach(dev, &sc->miibus, sc->ifp, ed_ifmedia_upd, + ed_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, + MII_OFFSET_ANY, 0); } else if (sc->chip_type == ED_CHIP_TYPE_AX88190 || - sc->chip_type == ED_CHIP_TYPE_AX88790) { - if ((error = mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, - ed_ifmedia_sts)) != 0) { - device_printf(dev, "Missing mii %d!\n", error); + sc->chip_type == ED_CHIP_TYPE_AX88790 || + sc->chip_type == ED_CHIP_TYPE_TC5299J) { + error = mii_attach(dev, &sc->miibus, sc->ifp, ed_ifmedia_upd, + ed_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, + MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto bad; } - - } else if (sc->chip_type == ED_CHIP_TYPE_TC5299J) { - if ((error = mii_phy_probe(dev, &sc->miibus, ed_ifmedia_upd, - ed_ifmedia_sts)) != 0) { - device_printf(dev, "Missing mii!\n"); - goto bad; - } - } if (sc->miibus != NULL) { sc->sc_tick = ed_pccard_tick; diff --git a/sys/dev/ed/if_ed_pci.c b/sys/dev/ed/if_ed_pci.c index 21ddb741ae8..3cf353c252a 100644 --- a/sys/dev/ed/if_ed_pci.c +++ b/sys/dev/ed/if_ed_pci.c @@ -49,18 +49,19 @@ static struct _pcsid const char *desc; } pci_ids[] = { - { ED_RTL8029_PCI_ID, "RealTek 8029" }, /* Needs realtek full duplex */ + { 0x140111f6, "Compex RL2000" }, + { 0x005812c3, "Holtek HT80232" }, + { 0x30008e2e, "KTI ET32P2" }, { 0x50004a14, "NetVin NV5000SC" }, { 0x09401050, "ProLAN" }, - { 0x140111f6, "Compex RL2000" }, - { 0x30008e2e, "KTI ET32P2" }, - { 0x19808c4a, "Winbond W89C940" }, + { ED_RTL8029_PCI_ID, "RealTek 8029" }, /* Needs realtek full duplex */ { 0x0e3410bd, "Surecom NE-34" }, - { 0x09261106, "VIA VT86C926" }, /* only do 16-bit */ + { 0x09261106, "VIA VT86C926" }, + { 0x19808c4a, "Winbond W89C940" }, { 0x5a5a1050, "Winbond W89C940F" }, #if 0 - /* Holtek needs special lovin', disabled by default */ - { 0x005812c3, "Holtek HT80232" }, /* Only 16-bit I/O, Holtek fdx */ + /* some Holtek needs special lovin', disabled by default */ + /* The Holtek can report/do full duplex, but that's unimplemented */ { 0x559812c3, "Holtek HT80229" }, /* Only 32-bit I/O, Holtek fdx, STOP_PG_60? */ #endif { 0x00000000, NULL } @@ -87,7 +88,6 @@ static int ed_pci_attach(device_t dev) { struct ed_softc *sc = device_get_softc(dev); - int flags = 0; int error = ENXIO; /* @@ -96,9 +96,10 @@ ed_pci_attach(device_t dev) * are areally just generic ne-2000 cards. */ if (pci_get_devid(dev) == ED_RTL8029_PCI_ID) - error = ed_probe_RTL80x9(dev, PCIR_BAR(0), flags); + error = ed_probe_RTL80x9(dev, PCIR_BAR(0), 0); if (error) - error = ed_probe_Novell(dev, PCIR_BAR(0), flags); + error = ed_probe_Novell(dev, PCIR_BAR(0), + ED_FLAGS_FORCE_16BIT_MODE); if (error) { ed_release_resources(dev); return (error); diff --git a/sys/dev/et/if_et.c b/sys/dev/et/if_et.c index e6a2163bf71..326309eb51a 100644 --- a/sys/dev/et/if_et.c +++ b/sys/dev/et/if_et.c @@ -63,8 +63,8 @@ __FBSDID("$FreeBSD$"); #include +#include #include -#include #include #include @@ -343,10 +343,10 @@ et_attach(device_t dev) et_chip_attach(sc); - error = mii_phy_probe(dev, &sc->sc_miibus, - et_ifmedia_upd, et_ifmedia_sts); + error = mii_attach(dev, &sc->sc_miibus, ifp, et_ifmedia_upd, + et_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); if (error) { - device_printf(dev, "can't probe any PHY\n"); + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1320,6 +1320,8 @@ et_watchdog(struct et_softc *sc) if_printf(sc->ifp, "watchdog timed out\n"); + sc->ifp->if_oerrors++; + sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; et_init_locked(sc); et_start_locked(sc->ifp); } diff --git a/sys/dev/fb/vesa.c b/sys/dev/fb/vesa.c index d369175bb92..0c05699ff97 100644 --- a/sys/dev/fb/vesa.c +++ b/sys/dev/fb/vesa.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -61,6 +62,8 @@ __FBSDID("$FreeBSD$"); #include +#define VESA_BIOS_OFFSET 0xc0000 +#define VESA_PALETTE_SIZE (256 * 4) #define VESA_VIA_CLE266 "VIA CLE266\r\n" #ifndef VESA_DEBUG @@ -83,11 +86,21 @@ static ssize_t vesa_state_buf_size = 0; static u_char *vesa_palette = NULL; static uint32_t vesa_palette_offs = 0; -#define VESA_PALETTE_SIZE (256 * 4) + +static void *vesa_bios = NULL; +static uint32_t vesa_bios_offs = VESA_BIOS_OFFSET; +static uint32_t vesa_bios_int10 = 0; +static size_t vesa_bios_size = 0; /* VESA video adapter */ static video_adapter_t *vesa_adp = NULL; +SYSCTL_NODE(_debug, OID_AUTO, vesa, CTLFLAG_RD, NULL, "VESA debugging"); +static int vesa_shadow_rom = 0; +TUNABLE_INT("debug.vesa.shadow_rom", &vesa_shadow_rom); +SYSCTL_INT(_debug_vesa, OID_AUTO, shadow_rom, CTLFLAG_RDTUN, &vesa_shadow_rom, + 0, "Enable video BIOS shadow"); + /* VESA functions */ #if 0 static int vesa_nop(void); @@ -242,7 +255,7 @@ vesa_bios_post(void) device_t dev; int count, i, is_pci; - if (x86bios_get_orm(0xc0000) == NULL) + if (x86bios_get_orm(vesa_bios_offs) == NULL) return (1); dev = NULL; @@ -253,7 +266,7 @@ vesa_bios_post(void) if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) { for (i = 0; i < count; i++) if (device_get_flags(devs[i]) != 0 && - x86bios_match_device(0xc0000, devs[i])) { + x86bios_match_device(vesa_bios_offs, devs[i])) { dev = devs[i]; is_pci = 1; break; @@ -279,7 +292,8 @@ vesa_bios_post(void) (pci_get_function(dev) & 0x07); } regs.R_DL = 0x80; - x86bios_call(®s, 0xc000, 0x0003); + x86bios_call(®s, X86BIOS_PHYSTOSEG(vesa_bios_offs + 3), + X86BIOS_PHYSTOOFF(vesa_bios_offs + 3)); if (x86bios_get_intr(0x10) == 0) return (1); @@ -754,6 +768,7 @@ vesa_bios_init(void) size_t bsize; size_t msize; void *vmbuf; + uint8_t *vbios; uint32_t offs; uint16_t vers; int is_via_cle266; @@ -765,22 +780,48 @@ vesa_bios_init(void) has_vesa_bios = FALSE; vesa_adp_info = NULL; + vesa_bios_offs = VESA_BIOS_OFFSET; vesa_vmode_max = 0; vesa_vmode[0].vi_mode = EOT; /* * If the VBE real mode interrupt vector is not found, try BIOS POST. */ - if (x86bios_get_intr(0x10) == 0) { + vesa_bios_int10 = x86bios_get_intr(0x10); + if (vesa_bios_int10 == 0) { if (vesa_bios_post() != 0) return (1); - if (bootverbose) { - offs = x86bios_get_intr(0x10); - printf("VESA: interrupt vector installed (0x%x)\n", - BIOS_SADDRTOLADDR(offs)); - } + vesa_bios_int10 = x86bios_get_intr(0x10); + if (vesa_bios_int10 == 0) + return (1); } + /* + * Shadow video ROM. + */ + offs = vesa_bios_int10; + if (vesa_shadow_rom) { + vbios = x86bios_get_orm(vesa_bios_offs); + if (vbios != NULL) { + vesa_bios_size = vbios[2] * 512; + if (((VESA_BIOS_OFFSET << 12) & 0xffff0000) == + (vesa_bios_int10 & 0xffff0000) && + vesa_bios_size > (vesa_bios_int10 & 0xffff)) { + vesa_bios = x86bios_alloc(&vesa_bios_offs, + vesa_bios_size, M_WAITOK); + memcpy(vesa_bios, vbios, vesa_bios_size); + offs = ((vesa_bios_offs << 12) & 0xffff0000) + + (vesa_bios_int10 & 0xffff); + x86bios_set_intr(0x10, offs); + } + } + if (vesa_bios == NULL) + printf("VESA: failed to shadow video ROM\n"); + } + if (bootverbose) + printf("VESA: INT 0x10 vector 0x%04x:0x%04x\n", + (offs >> 16) & 0xffff, offs & 0xffff); + x86bios_init_regs(®s); regs.R_AX = 0x4f00; @@ -1011,6 +1052,12 @@ vesa_bios_init(void) return (0); fail: + if (vesa_bios != NULL) { + x86bios_set_intr(0x10, vesa_bios_int10); + vesa_bios_offs = VESA_BIOS_OFFSET; + x86bios_free(vesa_bios, vesa_bios_size); + vesa_bios = NULL; + } if (vmbuf != NULL) x86bios_free(vmbuf, sizeof(buf)); if (vesa_adp_info != NULL) { @@ -1862,6 +1909,10 @@ vesa_unload(void) } } + if (vesa_bios != NULL) { + x86bios_set_intr(0x10, vesa_bios_int10); + x86bios_free(vesa_bios, vesa_bios_size); + } if (vesa_adp_info != NULL) free(vesa_adp_info, M_DEVBUF); if (vesa_oemstr != NULL) diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index a035959d16d..490f39bcfb4 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -102,7 +102,7 @@ static void firewire_xfer_timeout(void *, int); #if 0 static int firewire_shutdown (device_t); #endif -static device_t firewire_add_child (device_t, int, const char *, int); +static device_t firewire_add_child(device_t, u_int, const char *, int); static void fw_try_bmr (void *); static void fw_try_bmr_callback (struct fw_xfer *); static void fw_asystart (struct fw_xfer *); @@ -488,7 +488,7 @@ firewire_attach(device_t dev) * Attach it as child. */ static device_t -firewire_add_child(device_t dev, int order, const char *name, int unit) +firewire_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct firewire_softc *sc; diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index edfc04799ac..07a1a420fd4 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -1971,8 +1971,8 @@ fwohci_intr_dma(struct fwohci_softc *sc, uint32_t stat, int count) OWRITE(sc, OHCI_LNKCTLCLR, OHCI_CNTL_CYCTIMER); #endif OWRITE(sc, FWOHCI_INTMASKCLR, OHCI_INT_CYC_LOST); - device_printf(fc->dev, "too many cycle lost, " - "no cycle master presents?\n"); + device_printf(fc->dev, "too many cycles lost, " + "no cycle master present?\n"); } } if (stat & OHCI_INT_DMA_ATRQ) { diff --git a/sys/dev/firewire/fwohci_pci.c b/sys/dev/firewire/fwohci_pci.c index 5524954c756..0bb66a9ed5e 100644 --- a/sys/dev/firewire/fwohci_pci.c +++ b/sys/dev/firewire/fwohci_pci.c @@ -487,7 +487,7 @@ fwohci_pci_shutdown(device_t dev) } static device_t -fwohci_pci_add_child(device_t dev, int order, const char *name, int unit) +fwohci_pci_add_child(device_t dev, u_int order, const char *name, int unit) { struct fwohci_softc *sc; device_t child; diff --git a/sys/dev/flash/mx25l.c b/sys/dev/flash/mx25l.c index 98b3bb37980..71e2eb04ab0 100644 --- a/sys/dev/flash/mx25l.c +++ b/sys/dev/flash/mx25l.c @@ -93,6 +93,7 @@ struct mx25l_flash_ident flash_devices[] = { { "mx25ll64", 0xc2, 0x2017, 64 * 1024, 128, FL_NONE }, { "mx25ll128", 0xc2, 0x2018, 64 * 1024, 256, FL_ERASE_4K | FL_ERASE_32K }, { "s25fl128", 0x01, 0x2018, 64 * 1024, 256, FL_NONE }, + { "s25sl064a", 0x01, 0x0216, 64 * 1024, 128, FL_NONE }, }; static uint8_t diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index 079ecc1e82d..5710ca77ca9 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -804,10 +804,14 @@ fxp_attach(device_t dev) ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); } else { - if (mii_phy_probe(dev, &sc->miibus, fxp_ifmedia_upd, - fxp_ifmedia_sts)) { - device_printf(dev, "MII without any PHY!\n"); - error = ENXIO; + /* + * i82557 wedge when isolating all of their PHYs. + */ + error = mii_attach(dev, &sc->miibus, ifp, fxp_ifmedia_upd, + fxp_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, + MII_OFFSET_ANY, MIIF_NOISOLATE); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } } @@ -858,9 +862,9 @@ fxp_attach(device_t dev) ifp->if_capenable |= IFCAP_VLAN_MTU; /* the hw bits already set */ if ((sc->flags & FXP_FLAG_EXT_RFA) != 0) { ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | - IFCAP_VLAN_HWCSUM; + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | - IFCAP_VLAN_HWCSUM; + IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWTSO; } /* @@ -1454,6 +1458,8 @@ fxp_encap(struct fxp_softc *sc, struct mbuf **m_head) * Since 82550/82551 doesn't modify IP length and pseudo * checksum in the first frame driver should compute it. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); + tcp = (struct tcphdr *)(mtod(m, char *) + poff); ip->ip_sum = 0; ip->ip_len = htons(m->m_pkthdr.tso_segsz + (ip->ip_hl << 2) + (tcp->th_off << 2)); @@ -2860,10 +2866,19 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data) if (ifp->if_flags & IFF_UP) reinit++; } + if ((mask & IFCAP_VLAN_HWCSUM) != 0 && + (ifp->if_capabilities & IFCAP_VLAN_HWCSUM) != 0) + ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; + if ((mask & IFCAP_VLAN_HWTSO) != 0 && + (ifp->if_capabilities & IFCAP_VLAN_HWTSO) != 0) + ifp->if_capenable ^= IFCAP_VLAN_HWTSO; if ((mask & IFCAP_VLAN_HWTAGGING) != 0 && (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) != 0) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - reinit++; + if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) + ifp->if_capenable &= + ~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM); + reinit++; } if (reinit > 0 && ifp->if_flags & IFF_UP) fxp_init_body(sc); diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c index 6edb49e2f85..5c5750e3eab 100644 --- a/sys/dev/gem/if_gem.c +++ b/sys/dev/gem/if_gem.c @@ -149,7 +149,7 @@ gem_attach(struct gem_softc *sc) { struct gem_txsoft *txs; struct ifnet *ifp; - int error, i; + int error, i, phy; uint32_t v; if (bootverbose) @@ -268,10 +268,17 @@ gem_attach(struct gem_softc *sc) sc->sc_rxsoft[i].rxs_mbuf = NULL; } + /* Bypass probing PHYs if we already know for sure to use a SERDES. */ + if ((sc->sc_flags & GEM_SERDES) != 0) + goto serdes; + /* Bad things will happen when touching this register on ERI. */ - if (sc->sc_variant != GEM_SUN_ERI) + if (sc->sc_variant != GEM_SUN_ERI) { GEM_BANK1_WRITE_4(sc, GEM_MII_DATAPATH_MODE, GEM_MII_DATAPATH_MII); + GEM_BANK1_BARRIER(sc, GEM_MII_DATAPATH_MODE, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + } gem_mifinit(sc); @@ -283,16 +290,19 @@ gem_attach(struct gem_softc *sc) if ((v & GEM_MIF_CONFIG_MDI1) != 0) { v |= GEM_MIF_CONFIG_PHY_SEL; GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, v); + GEM_BANK1_BARRIER(sc, GEM_MIF_CONFIG, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); switch (sc->sc_variant) { case GEM_SUN_ERI: - sc->sc_phyad = GEM_PHYAD_EXTERNAL; + phy = GEM_PHYAD_EXTERNAL; break; default: - sc->sc_phyad = -1; + phy = MII_PHY_ANY; break; } - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - gem_mediachange, gem_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, phy, + MII_OFFSET_ANY, 0); } /* @@ -304,39 +314,48 @@ gem_attach(struct gem_softc *sc) ((v & GEM_MIF_CONFIG_MDI0) != 0 || GEM_IS_APPLE(sc))) { v &= ~GEM_MIF_CONFIG_PHY_SEL; GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, v); + GEM_BANK1_BARRIER(sc, GEM_MIF_CONFIG, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); switch (sc->sc_variant) { case GEM_SUN_ERI: case GEM_APPLE_K2_GMAC: - sc->sc_phyad = GEM_PHYAD_INTERNAL; + phy = GEM_PHYAD_INTERNAL; break; case GEM_APPLE_GMAC: - sc->sc_phyad = GEM_PHYAD_EXTERNAL; + phy = GEM_PHYAD_EXTERNAL; break; default: - sc->sc_phyad = -1; + phy = MII_PHY_ANY; break; } - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - gem_mediachange, gem_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, phy, + MII_OFFSET_ANY, 0); } /* * Try the external PCS SERDES if we didn't find any PHYs. */ if (error != 0 && sc->sc_variant == GEM_SUN_GEM) { + serdes: GEM_BANK1_WRITE_4(sc, GEM_MII_DATAPATH_MODE, GEM_MII_DATAPATH_SERDES); + GEM_BANK1_BARRIER(sc, GEM_MII_DATAPATH_MODE, 4, + BUS_SPACE_BARRIER_WRITE); GEM_BANK1_WRITE_4(sc, GEM_MII_SLINK_CONTROL, GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); + GEM_BANK1_BARRIER(sc, GEM_MII_SLINK_CONTROL, 4, + BUS_SPACE_BARRIER_WRITE); GEM_BANK1_WRITE_4(sc, GEM_MII_CONFIG, GEM_MII_CONFIG_ENABLE); + GEM_BANK1_BARRIER(sc, GEM_MII_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); sc->sc_flags |= GEM_SERDES; - sc->sc_phyad = GEM_PHYAD_EXTERNAL; - error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, - gem_mediachange, gem_mediastatus); + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, + gem_mediachange, gem_mediastatus, BMSR_DEFCAPMASK, + GEM_PHYAD_EXTERNAL, MII_OFFSET_ANY, 0); } - if (error != 0) { - device_printf(sc->sc_dev, "PHY probe failed: %d\n", error); + device_printf(sc->sc_dev, "attaching PHYs failed\n"); goto fail_rxd; } sc->sc_mii = device_get_softc(sc->sc_miibus); @@ -918,8 +937,9 @@ gem_init_locked(struct gem_softc *sc) __func__); #endif - /* Re-initialize the MIF. */ - gem_mifinit(sc); + if ((sc->sc_flags & GEM_SERDES) == 0) + /* Re-initialize the MIF. */ + gem_mifinit(sc); /* step 3. Setup data structures in host memory. */ if (gem_meminit(sc) != 0) @@ -1800,6 +1820,8 @@ gem_mifinit(struct gem_softc *sc) /* Configure the MIF in frame mode. */ GEM_BANK1_WRITE_4(sc, GEM_MIF_CONFIG, GEM_BANK1_READ_4(sc, GEM_MIF_CONFIG) & ~GEM_MIF_CONFIG_BB_ENA); + GEM_BANK1_BARRIER(sc, GEM_MIF_CONFIG, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } /* @@ -1828,9 +1850,6 @@ gem_mii_readreg(device_t dev, int phy, int reg) #endif sc = device_get_softc(dev); - if (sc->sc_phyad != -1 && phy != sc->sc_phyad) - return (0); - if ((sc->sc_flags & GEM_SERDES) != 0) { switch (reg) { case MII_BMCR: @@ -1889,9 +1908,6 @@ gem_mii_writereg(device_t dev, int phy, int reg, int val) #endif sc = device_get_softc(dev); - if (sc->sc_phyad != -1 && phy != sc->sc_phyad) - return (0); - if ((sc->sc_flags & GEM_SERDES) != 0) { switch (reg) { case MII_BMSR: @@ -1914,10 +1930,16 @@ gem_mii_writereg(device_t dev, int phy, int reg, int val) GEM_BANK1_BARRIER(sc, GEM_MII_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); GEM_BANK1_WRITE_4(sc, GEM_MII_ANAR, val); + GEM_BANK1_BARRIER(sc, GEM_MII_ANAR, 4, + BUS_SPACE_BARRIER_WRITE); GEM_BANK1_WRITE_4(sc, GEM_MII_SLINK_CONTROL, GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_EN_SYNC_D); + GEM_BANK1_BARRIER(sc, GEM_MII_SLINK_CONTROL, 4, + BUS_SPACE_BARRIER_WRITE); GEM_BANK1_WRITE_4(sc, GEM_MII_CONFIG, GEM_MII_CONFIG_ENABLE); + GEM_BANK1_BARRIER(sc, GEM_MII_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); return (0); case MII_ANLPAR: reg = GEM_MII_ANLPAR; @@ -1928,6 +1950,8 @@ gem_mii_writereg(device_t dev, int phy, int reg, int val) return (0); } GEM_BANK1_WRITE_4(sc, reg, val); + GEM_BANK1_BARRIER(sc, reg, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return (0); } @@ -1964,8 +1988,7 @@ gem_mii_statchg(device_t dev) #ifdef GEM_DEBUG if ((sc->sc_ifp->if_flags & IFF_DEBUG) != 0) - device_printf(sc->sc_dev, "%s: status change: PHY = %d\n", - __func__, sc->sc_phyad); + device_printf(sc->sc_dev, "%s: status change\n", __func__); #endif if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) != 0 && diff --git a/sys/dev/gem/if_gem_pci.c b/sys/dev/gem/if_gem_pci.c index 051dbcc5bfb..cfea337312c 100644 --- a/sys/dev/gem/if_gem_pci.c +++ b/sys/dev/gem/if_gem_pci.c @@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #if defined(__powerpc__) || defined(__sparc64__) +#include #include #include #endif @@ -140,12 +141,17 @@ static struct resource_spec gem_pci_res_spec[] = { { -1, 0 } }; +#define GEM_SHARED_PINS "shared-pins" +#define GEM_SHARED_PINS_SERDES "serdes" + static int gem_pci_attach(device_t dev) { struct gem_softc *sc; int i; -#if !(defined(__powerpc__) || defined(__sparc64__)) +#if defined(__powerpc__) || defined(__sparc64__) + char buf[sizeof(GEM_SHARED_PINS)]; +#else int j; #endif @@ -207,6 +213,12 @@ gem_pci_attach(device_t dev) #if defined(__powerpc__) || defined(__sparc64__) OF_getetheraddr(dev, sc->sc_enaddr); + if (OF_getprop(ofw_bus_get_node(dev), GEM_SHARED_PINS, buf, + sizeof(buf)) > 0) { + buf[sizeof(buf) - 1] = '\0'; + if (strcmp(buf, GEM_SHARED_PINS_SERDES) == 0) + sc->sc_flags |= GEM_SERDES; + } #else /* * Dig out VPD (vital product data) and read NA (network address). diff --git a/sys/dev/gem/if_gem_sbus.c b/sys/dev/gem/if_gem_sbus.c index 4402251354e..205285d08e0 100644 --- a/sys/dev/gem/if_gem_sbus.c +++ b/sys/dev/gem/if_gem_sbus.c @@ -131,6 +131,8 @@ gem_sbus_attach(device_t dev) sc = device_get_softc(dev); sc->sc_variant = GEM_SUN_GEM; sc->sc_dev = dev; + /* All known SBus models use a SERDES. */ + sc->sc_flags = GEM_SERDES; if (bus_alloc_resources(dev, gem_sbus_res_spec, sc->sc_res)) { device_printf(dev, "failed to allocate resources\n"); diff --git a/sys/dev/gem/if_gemvar.h b/sys/dev/gem/if_gemvar.h index ab5b2f6ea7f..59cb5823102 100644 --- a/sys/dev/gem/if_gemvar.h +++ b/sys/dev/gem/if_gemvar.h @@ -126,8 +126,6 @@ struct gem_softc { bus_dma_tag_t sc_cdmatag; /* control data bus DMA tag */ bus_dmamap_t sc_dmamap; /* bus DMA handle */ - int sc_phyad; /* PHY to use or -1 for any */ - u_int sc_variant; #define GEM_UNKNOWN 0 /* don't know */ #define GEM_SUN_GEM 1 /* Sun GEM */ diff --git a/sys/dev/gpio/gpio_if.m b/sys/dev/gpio/gpio_if.m new file mode 100644 index 00000000000..78383d3d46d --- /dev/null +++ b/sys/dev/gpio/gpio_if.m @@ -0,0 +1,102 @@ +#- +# Copyright (c) 2009 Oleksandr Tymoshenko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include +#include + +INTERFACE gpio; + +# +# Get total number of pins +# +METHOD int pin_max { + device_t dev; + int *npins; +}; + +# +# Set value of pin specifed by pin_num +# +METHOD int pin_set { + device_t dev; + uint32_t pin_num; + uint32_t pin_value; +}; + +# +# Get value of pin specifed by pin_num +# +METHOD int pin_get { + device_t dev; + uint32_t pin_num; + uint32_t *pin_value; +}; + +# +# Toggle value of pin specifed by pin_num +# +METHOD int pin_toggle { + device_t dev; + uint32_t pin_num; +}; + +# +# Get pin capabilities +# +METHOD int pin_getcaps { + device_t dev; + uint32_t pin_num; + uint32_t *caps; +}; + +# +# Get pin flags +# +METHOD int pin_getflags { + device_t dev; + uint32_t pin_num; + uint32_t *flags; +}; + +# +# Get pin name +# +METHOD int pin_getname { + device_t dev; + uint32_t pin_num; + char *name; +}; + +# +# Set current configuration and capabilities +# +METHOD int pin_setflags { + device_t dev; + uint32_t pin_num; + uint32_t flags; +}; diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c new file mode 100644 index 00000000000..3a044fd75f4 --- /dev/null +++ b/sys/dev/gpio/gpiobus.c @@ -0,0 +1,493 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "gpio_if.h" +#include "gpiobus_if.h" + +static void gpiobus_print_pins(struct gpiobus_ivar *); +static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int); +static int gpiobus_probe(device_t); +static int gpiobus_attach(device_t); +static int gpiobus_detach(device_t); +static int gpiobus_suspend(device_t); +static int gpiobus_resume(device_t); +static int gpiobus_print_child(device_t, device_t); +static int gpiobus_child_location_str(device_t, device_t, char *, size_t); +static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t); +static device_t gpiobus_add_child(device_t, u_int, const char *, int); +static void gpiobus_hinted_child(device_t, const char *, int); + +/* + * GPIOBUS interface + */ +static void gpiobus_lock_bus(device_t); +static void gpiobus_unlock_bus(device_t); +static void gpiobus_acquire_bus(device_t, device_t); +static void gpiobus_release_bus(device_t, device_t); +static int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t); +static int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*); +static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*); +static int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int); +static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*); +static int gpiobus_pin_toggle(device_t, device_t, uint32_t); + +#define GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define GPIOBUS_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "gpiobus", MTX_DEF) +#define GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define GPIOBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define GPIOBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + + +static void +gpiobus_print_pins(struct gpiobus_ivar *devi) +{ + int range_start, range_stop, need_coma; + int i; + + if (devi->npins == 0) + return; + + need_coma = 0; + range_start = range_stop = devi->pins[0]; + for (i = 1; i < devi->npins; i++) { + if (devi->pins[i] != (range_stop + 1)) { + if (need_coma) + printf(","); + if (range_start != range_stop) + printf("%d-%d", range_start, range_stop); + else + printf("%d", range_start); + + range_start = range_stop = devi->pins[i]; + need_coma = 1; + } + else + range_stop++; + } + + if (need_coma) + printf(","); + if (range_start != range_stop) + printf("%d-%d", range_start, range_stop); + else + printf("%d", range_start); +} + +static int +gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + int i, npins; + + npins = 0; + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) + npins++; + } + + if (npins == 0) { + device_printf(child, "empty pin mask"); + return (EINVAL); + } + + devi->npins = npins; + devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, + M_NOWAIT | M_ZERO); + + if (!devi->pins) + return (ENOMEM); + + npins = 0; + for (i = 0; i < 32; i++) { + + if ((mask & (1 << i)) == 0) + continue; + + if (i >= sc->sc_npins) { + device_printf(child, + "invalid pin %d, max: %d\n", i, sc->sc_npins - 1); + return (EINVAL); + } + + devi->pins[npins++] = i; + /* + * Mark pin as mapped and give warning if it's already mapped + */ + if (sc->sc_pins_mapped[i]) { + device_printf(child, + "warning: pin %d is already mapped\n", i); + return (EINVAL); + } + sc->sc_pins_mapped[i] = 1; + } + + return (0); +} + +static int +gpiobus_probe(device_t dev) +{ + device_set_desc(dev, "GPIO bus"); + return (0); +} + +static int +gpiobus_attach(device_t dev) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + int res; + + sc->sc_busdev = dev; + sc->sc_dev = device_get_parent(dev); + res = GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins); + if (res) + return (ENXIO); + + /* + * Increase to get number of pins + */ + sc->sc_npins++; + + KASSERT(sc->sc_npins != 0, ("GPIO device with no pins")); + + sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF, + M_NOWAIT | M_ZERO); + + if (!sc->sc_pins_mapped) + return (ENOMEM); + + /* init bus lock */ + GPIOBUS_LOCK_INIT(sc); + + /* + * Get parent's pins and mark them as unmapped + */ + bus_enumerate_hinted_children(dev); + return (bus_generic_attach(dev)); +} + +/* + * Since this is not a self-enumerating bus, and since we always add + * children in attach, we have to always delete children here. + */ +static int +gpiobus_detach(device_t dev) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + int err, ndevs, i; + device_t *devlist; + + KASSERT(mtx_initialized(&sc->sc_mtx), + ("gpiobus mutex not initialized")); + GPIOBUS_LOCK_DESTROY(sc); + + if ((err = bus_generic_detach(dev)) != 0) + return (err); + if ((err = device_get_children(dev, &devlist, &ndevs)) != 0) + return (err); + for (i = 0; i < ndevs; i++) + device_delete_child(dev, devlist[i]); + + if (sc->sc_pins_mapped) { + free(sc->sc_pins_mapped, M_DEVBUF); + sc->sc_pins_mapped = NULL; + } + free(devlist, M_TEMP); + + return (0); +} + +static int +gpiobus_suspend(device_t dev) +{ + + return (bus_generic_suspend(dev)); +} + +static int +gpiobus_resume(device_t dev) +{ + + return (bus_generic_resume(dev)); +} + +static int +gpiobus_print_child(device_t dev, device_t child) +{ + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + int retval = 0; + + retval += bus_print_child_header(dev, child); + retval += printf(" at pin(s) "); + gpiobus_print_pins(devi); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +gpiobus_child_location_str(device_t bus, device_t child, char *buf, + size_t buflen) +{ + // struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + snprintf(buf, buflen, "pins=?"); + return (0); +} + +static int +gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf, + size_t buflen) +{ + + *buf = '\0'; + return (0); +} + +static device_t +gpiobus_add_child(device_t dev, u_int order, const char *name, int unit) +{ + device_t child; + struct gpiobus_ivar *devi; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (child); + devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (devi == NULL) { + device_delete_child(dev, child); + return (0); + } + device_set_ivars(child, devi); + return (child); +} + +static void +gpiobus_hinted_child(device_t bus, const char *dname, int dunit) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus); + struct gpiobus_ivar *devi; + device_t child; + int pins; + + + child = BUS_ADD_CHILD(bus, 0, dname, dunit); + devi = GPIOBUS_IVAR(child); + resource_int_value(dname, dunit, "pins", &pins); + if (gpiobus_parse_pins(sc, child, pins)) + device_delete_child(bus, child); +} + +static void +gpiobus_lock_bus(device_t busdev) +{ + struct gpiobus_softc *sc; + + sc = device_get_softc(busdev); + GPIOBUS_ASSERT_UNLOCKED(sc); + GPIOBUS_LOCK(sc); +} + +static void +gpiobus_unlock_bus(device_t busdev) +{ + struct gpiobus_softc *sc; + + sc = device_get_softc(busdev); + GPIOBUS_ASSERT_LOCKED(sc); + GPIOBUS_UNLOCK(sc); +} + +static void +gpiobus_acquire_bus(device_t busdev, device_t child) +{ + struct gpiobus_softc *sc; + + sc = device_get_softc(busdev); + GPIOBUS_ASSERT_LOCKED(sc); + + if (sc->sc_owner) + panic("rb_cpldbus: cannot serialize the access to device."); + sc->sc_owner = child; +} + +static void +gpiobus_release_bus(device_t busdev, device_t child) +{ + struct gpiobus_softc *sc; + + sc = device_get_softc(busdev); + GPIOBUS_ASSERT_LOCKED(sc); + + if (!sc->sc_owner) + panic("rb_cpldbus: releasing unowned bus."); + if (sc->sc_owner != child) + panic("rb_cpldbus: you don't own the bus. game over."); + + sc->sc_owner = NULL; +} + +static int +gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, + uint32_t flags) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags); +} + +static int +gpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin, + uint32_t *flags) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_GETFLAGS(sc->sc_dev, devi->pins[pin], flags); +} + +static int +gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, + uint32_t *caps) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps); +} + +static int +gpiobus_pin_set(device_t dev, device_t child, uint32_t pin, + unsigned int value) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_SET(sc->sc_dev, devi->pins[pin], value); +} + +static int +gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, + unsigned int *value) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value); +} + +static int +gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin) +{ + struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev); + struct gpiobus_ivar *devi = GPIOBUS_IVAR(child); + + if (pin >= devi->npins) + return (EINVAL); + + return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]); +} + +static device_method_t gpiobus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpiobus_probe), + DEVMETHOD(device_attach, gpiobus_attach), + DEVMETHOD(device_detach, gpiobus_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, gpiobus_suspend), + DEVMETHOD(device_resume, gpiobus_resume), + + /* Bus interface */ + DEVMETHOD(bus_add_child, gpiobus_add_child), + DEVMETHOD(bus_print_child, gpiobus_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, gpiobus_child_location_str), + DEVMETHOD(bus_hinted_child, gpiobus_hinted_child), + + /* GPIO protocol */ + DEVMETHOD(gpiobus_lock_bus, gpiobus_lock_bus), + DEVMETHOD(gpiobus_unlock_bus, gpiobus_unlock_bus), + DEVMETHOD(gpiobus_acquire_bus, gpiobus_acquire_bus), + DEVMETHOD(gpiobus_release_bus, gpiobus_release_bus), + DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags), + DEVMETHOD(gpiobus_pin_getcaps, gpiobus_pin_getcaps), + DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags), + DEVMETHOD(gpiobus_pin_get, gpiobus_pin_get), + DEVMETHOD(gpiobus_pin_set, gpiobus_pin_set), + DEVMETHOD(gpiobus_pin_toggle, gpiobus_pin_toggle), + + { 0, 0 } +}; + +static driver_t gpiobus_driver = { + "gpiobus", + gpiobus_methods, + sizeof(struct gpiobus_softc) +}; + +devclass_t gpiobus_devclass; + +DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0); +MODULE_VERSION(gpiobus, 1); diff --git a/sys/dev/gpio/gpiobus_if.m b/sys/dev/gpio/gpiobus_if.m new file mode 100644 index 00000000000..6bf1ad839b6 --- /dev/null +++ b/sys/dev/gpio/gpiobus_if.m @@ -0,0 +1,121 @@ +#- +# Copyright (c) 2009 Oleksandr Tymoshenko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include +#include + +INTERFACE gpiobus; + +# +# Lock the gpio bus +# +METHOD void lock_bus { + device_t busdev; +}; + +# +# Unlock the gpio bus +# +METHOD void unlock_bus { + device_t busdev; +}; + +# +# Dedicate the gpio bus control for a child +# +METHOD void acquire_bus { + device_t busdev; + device_t dev; +}; + +# +# Release the bus +# +METHOD void release_bus { + device_t busdev; + device_t dev; +}; + +# +# Set value of pin specifed by pin_num +# +METHOD int pin_set { + device_t dev; + device_t child; + uint32_t pin_num; + uint32_t pin_value; +}; + +# +# Get value of pin specifed by pin_num +# +METHOD int pin_get { + device_t dev; + device_t child; + uint32_t pin_num; + uint32_t *pin_value; +}; + +# +# Toggle value of pin specifed by pin_num +# +METHOD int pin_toggle { + device_t dev; + device_t child; + uint32_t pin_num; +}; + +# +# Get pin capabilities +# +METHOD int pin_getcaps { + device_t dev; + device_t child; + uint32_t pin_num; + uint32_t *caps; +}; + +# +# Get pin flags +# +METHOD int pin_getflags { + device_t dev; + device_t child; + uint32_t pin_num; + uint32_t *flags; +}; + +# +# Set current configuration and capabilities +# +METHOD int pin_setflags { + device_t dev; + device_t child; + uint32_t pin_num; + uint32_t flags; +}; diff --git a/sys/dev/gpio/gpiobusvar.h b/sys/dev/gpio/gpiobusvar.h new file mode 100644 index 00000000000..7a79aedaa5a --- /dev/null +++ b/sys/dev/gpio/gpiobusvar.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef __GPIOBUS_H__ +#define __GPIOBUS_H__ + +#include +#include +#include + +#define GPIOBUS_IVAR(d) (struct gpiobus_ivar *) device_get_ivars(d) +#define GPIOBUS_SOFTC(d) (struct gpiobus_softc *) device_get_softc(d) + +struct gpiobus_softc +{ + struct mtx sc_mtx; /* bus mutex */ + device_t sc_busdev; /* bus device */ + device_t sc_owner; /* bus owner */ + device_t sc_dev; /* driver device */ + int sc_npins; /* total pins on bus */ + int *sc_pins_mapped; /* mark mapped pins */ +}; + + +struct gpiobus_ivar +{ + uint32_t npins; /* pins total */ + uint32_t *pins; /* pins map */ +}; + +#endif /* __GPIOBUS_H__ */ diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c new file mode 100644 index 00000000000..e92326e196a --- /dev/null +++ b/sys/dev/gpio/gpioc.c @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "gpio_if.h" + +#undef GPIOC_DEBUG +#ifdef GPIOC_DEBUG +#define dprintf printf +#else +#define dprintf(x, arg...) +#endif + +static int gpioc_probe(device_t dev); +static int gpioc_attach(device_t dev); +static int gpioc_detach(device_t dev); + +static d_ioctl_t gpioc_ioctl; + +static struct cdevsw gpioc_cdevsw = { + .d_version = D_VERSION, + .d_ioctl = gpioc_ioctl, + .d_name = "gpioc", +#if __FreeBSD_version >= 800039 + .d_flags = D_PSEUDO | D_NEEDMINOR +#endif +}; + +struct gpioc_softc { + device_t sc_dev; /* gpiocX dev */ + device_t sc_pdev; /* gpioX dev */ + struct cdev *sc_ctl_dev; /* controller device */ + int sc_unit; +}; + +static int +gpioc_probe(device_t dev) +{ + device_set_desc(dev, "GPIO controller"); + return (0); +} + +static int +gpioc_attach(device_t dev) +{ + struct gpioc_softc *sc = device_get_softc(dev); + + sc->sc_dev = dev; + sc->sc_pdev = device_get_parent(dev); + sc->sc_unit = device_get_unit(dev); + sc->sc_ctl_dev = make_dev(&gpioc_cdevsw, sc->sc_unit, + UID_ROOT, GID_WHEEL, 0600, "gpioc%d", sc->sc_unit); + if (!sc->sc_ctl_dev) { + printf("Failed to create gpioc%d", sc->sc_unit); + return (ENXIO); + } + sc->sc_ctl_dev->si_drv1 = sc; + + return (0); +} + +static int +gpioc_detach(device_t dev) +{ + struct gpioc_softc *sc = device_get_softc(dev); + int err; + + if (sc->sc_ctl_dev); + destroy_dev(sc->sc_ctl_dev); + + if ((err = bus_generic_detach(dev)) != 0) + return (err); + + return (0); +} + +static int +gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, + struct thread *td) +{ + int max_pin, res; + struct gpioc_softc *sc = cdev->si_drv1; + struct gpio_pin pin; + struct gpio_req req; + + switch (cmd) { + case GPIOMAXPIN: + max_pin = -1; + res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin); + bcopy(&max_pin, arg, sizeof(max_pin)); + break; + case GPIOGETCONFIG: + bcopy(arg, &pin, sizeof(pin)); + dprintf("get config pin %d\n", pin.gp_pin); + res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin, + &pin.gp_flags); + /* Fail early */ + if (res) + break; + GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps); + GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name); + bcopy(&pin, arg, sizeof(pin)); + break; + case GPIOSETCONFIG: + bcopy(arg, &pin, sizeof(pin)); + dprintf("set config pin %d\n", pin.gp_pin); + res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin, + pin.gp_flags); + break; + case GPIOGET: + bcopy(arg, &req, sizeof(req)); + res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin, + &req.gp_value); + dprintf("read pin %d -> %d\n", + req.gp_pin, req.gp_value); + bcopy(&req, arg, sizeof(req)); + break; + case GPIOSET: + bcopy(arg, &req, sizeof(req)); + res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, + req.gp_value); + dprintf("write pin %d -> %d\n", + req.gp_pin, req.gp_value); + break; + case GPIOTOGGLE: + bcopy(arg, &req, sizeof(req)); + dprintf("toggle pin %d\n", + req.gp_pin); + res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin); + break; + default: + return (ENOTTY); + break; + } + + return (res); +} + +static device_method_t gpioc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpioc_probe), + DEVMETHOD(device_attach, gpioc_attach), + DEVMETHOD(device_detach, gpioc_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + { 0, 0 } +}; + +static driver_t gpioc_driver = { + "gpioc", + gpioc_methods, + sizeof(struct gpioc_softc) +}; + +devclass_t gpioc_devclass; + +DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0); +MODULE_VERSION(gpioc, 1); diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c new file mode 100644 index 00000000000..e9611dd7363 --- /dev/null +++ b/sys/dev/gpio/gpioiic.c @@ -0,0 +1,246 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * Copyright (c) 2010 Luiz Otavio O Souza + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "gpiobus_if.h" + +#include +#include + +#include "iicbb_if.h" + +#define SCL_PIN 0 /* gpiobus mapped pin 6 */ +#define SDA_PIN 1 /* gpiobus mapped pin 7 */ + +struct gpioiic_softc +{ + device_t sc_dev; + device_t sc_busdev; + struct mtx sc_mtx; + struct cdev *sc_leddev; +}; + +static int gpioiic_probe(device_t); +static int gpioiic_attach(device_t); + +/* iicbb interface */ +static void gpioiic_reset_bus(device_t); +static int gpioiic_callback(device_t, int, caddr_t); +static void gpioiic_setsda(device_t, int); +static void gpioiic_setscl(device_t, int); +static int gpioiic_getsda(device_t); +static int gpioiic_getscl(device_t); +static int gpioiic_reset(device_t, u_char, u_char, u_char *); + + +static int +gpioiic_probe(device_t dev) +{ + + device_set_desc(dev, "GPIO I2C bit-banging driver"); + return (0); +} + +static int +gpioiic_attach(device_t dev) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + device_t bitbang; + + sc->sc_dev = dev; + sc->sc_busdev = device_get_parent(dev); + + /* add generic bit-banging code */ + bitbang = device_add_child(dev, "iicbb", -1); + device_probe_and_attach(bitbang); + + return (0); +} + +/* + * Reset bus by setting SDA first and then SCL. + * Must always be called with gpio bus locked. + */ +static void +gpioiic_reset_bus(device_t dev) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN, + GPIO_PIN_INPUT); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN, + GPIO_PIN_INPUT); +} + +static int +gpioiic_callback(device_t dev, int index, caddr_t data) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + int error = 0; + + switch (index) { + case IIC_REQUEST_BUS: + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + break; + case IIC_RELEASE_BUS: + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + break; + default: + error = EINVAL; + } + + return(error); +} + +static void +gpioiic_setsda(device_t dev, int val) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + + GPIOBUS_LOCK_BUS(sc->sc_busdev); + if (val == 0) { + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SDA_PIN, 0); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN, + GPIO_PIN_OUTPUT); + } else { + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN, + GPIO_PIN_INPUT); + } + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); +} + +static void +gpioiic_setscl(device_t dev, int val) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + + GPIOBUS_LOCK_BUS(sc->sc_busdev); + if (val == 0) { + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, SCL_PIN, 0); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN, + GPIO_PIN_OUTPUT); + } else { + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN, + GPIO_PIN_INPUT); + } + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); +} + +static int +gpioiic_getscl(device_t dev) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + unsigned int val; + + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SCL_PIN, + GPIO_PIN_INPUT); + GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SCL_PIN, &val); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + + return ((int)val); +} + +static int +gpioiic_getsda(device_t dev) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + unsigned int val; + + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, SDA_PIN, + GPIO_PIN_INPUT); + GPIOBUS_PIN_GET(sc->sc_busdev, sc->sc_dev, SDA_PIN, &val); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + + return ((int)val); +} + +static int +gpioiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +{ + struct gpioiic_softc *sc = device_get_softc(dev); + + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev); + + gpioiic_reset_bus(sc->sc_dev); + + GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + + return (IIC_ENOADDR); +} + +static devclass_t gpioiic_devclass; + +static device_method_t gpioiic_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpioiic_probe), + DEVMETHOD(device_attach, gpioiic_attach), + DEVMETHOD(device_detach, bus_generic_detach), + + /* iicbb interface */ + DEVMETHOD(iicbb_callback, gpioiic_callback), + DEVMETHOD(iicbb_setsda, gpioiic_setsda), + DEVMETHOD(iicbb_setscl, gpioiic_setscl), + DEVMETHOD(iicbb_getsda, gpioiic_getsda), + DEVMETHOD(iicbb_getscl, gpioiic_getscl), + DEVMETHOD(iicbb_reset, gpioiic_reset), + + { 0, 0 } +}; + +static driver_t gpioiic_driver = { + "gpioiic", + gpioiic_methods, + sizeof(struct gpioiic_softc), +}; + +DRIVER_MODULE(gpioiic, gpiobus, gpioiic_driver, gpioiic_devclass, 0, 0); +DRIVER_MODULE(iicbb, gpioiic, iicbb_driver, iicbb_devclass, 0, 0); +MODULE_DEPEND(gpioiic, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); +MODULE_DEPEND(gpioiic, gpiobus, 1, 1, 1); diff --git a/sys/dev/gpio/gpioled.c b/sys/dev/gpio/gpioled.c new file mode 100644 index 00000000000..d96b8b77450 --- /dev/null +++ b/sys/dev/gpio/gpioled.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "gpiobus_if.h" + +/* + * Only one pin for led + */ +#define GPIOLED_PIN 0 + +#define GPIOLED_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define GPIOLED_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define GPIOLED_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "gpioled", MTX_DEF) +#define GPIOLED_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); + +struct gpioled_softc +{ + device_t sc_dev; + device_t sc_busdev; + struct mtx sc_mtx; + struct cdev *sc_leddev; +}; + +static void gpioled_control(void *, int); +static int gpioled_probe(device_t); +static int gpioled_attach(device_t); +static int gpioled_detach(device_t); + +static void +gpioled_control(void *priv, int onoff) +{ + struct gpioled_softc *sc = priv; + GPIOLED_LOCK(sc); + GPIOBUS_LOCK_BUS(sc->sc_busdev); + GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev); + GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN, + onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW); + GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev); + GPIOBUS_UNLOCK_BUS(sc->sc_busdev); + GPIOLED_UNLOCK(sc); +} + +static int +gpioled_probe(device_t dev) +{ + device_set_desc(dev, "GPIO led"); + return (0); +} + +static int +gpioled_attach(device_t dev) +{ + struct gpioled_softc *sc; + const char *name; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_busdev = device_get_parent(dev); + GPIOLED_LOCK_INIT(sc); + if (resource_string_value(device_get_name(dev), + device_get_unit(dev), "name", &name)) + name = NULL; + + sc->sc_leddev = led_create(gpioled_control, sc, name ? name : + device_get_nameunit(dev)); + + return (0); +} + +static int +gpioled_detach(device_t dev) +{ + struct gpioled_softc *sc; + + sc = device_get_softc(dev); + if (sc->sc_leddev) { + led_destroy(sc->sc_leddev); + sc->sc_leddev = NULL; + } + GPIOLED_LOCK_DESTROY(sc); + return (0); +} + +static devclass_t gpioled_devclass; + +static device_method_t gpioled_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, gpioled_probe), + DEVMETHOD(device_attach, gpioled_attach), + DEVMETHOD(device_detach, gpioled_detach), + + { 0, 0 } +}; + +static driver_t gpioled_driver = { + "gpioled", + gpioled_methods, + sizeof(struct gpioled_softc), +}; + +DRIVER_MODULE(gpioled, gpiobus, gpioled_driver, gpioled_devclass, 0, 0); diff --git a/sys/dev/hifn/hifn7751.c b/sys/dev/hifn/hifn7751.c index bd1173ee3e7..b0c53633fea 100644 --- a/sys/dev/hifn/hifn7751.c +++ b/sys/dev/hifn/hifn7751.c @@ -1372,45 +1372,45 @@ hifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *res { struct hifn_dma *dma = sc->sc_dma; - if (dma->cmdi == HIFN_D_CMD_RSIZE) { - dma->cmdi = 0; + if (sc->sc_cmdi == HIFN_D_CMD_RSIZE) { + sc->sc_cmdi = 0; dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } - *cmdp = dma->cmdi++; - dma->cmdk = dma->cmdi; + *cmdp = sc->sc_cmdi++; + sc->sc_cmdk = sc->sc_cmdi; - if (dma->srci == HIFN_D_SRC_RSIZE) { - dma->srci = 0; + if (sc->sc_srci == HIFN_D_SRC_RSIZE) { + sc->sc_srci = 0; dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } - *srcp = dma->srci++; - dma->srck = dma->srci; + *srcp = sc->sc_srci++; + sc->sc_srck = sc->sc_srci; - if (dma->dsti == HIFN_D_DST_RSIZE) { - dma->dsti = 0; + if (sc->sc_dsti == HIFN_D_DST_RSIZE) { + sc->sc_dsti = 0; dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } - *dstp = dma->dsti++; - dma->dstk = dma->dsti; + *dstp = sc->sc_dsti++; + sc->sc_dstk = sc->sc_dsti; - if (dma->resi == HIFN_D_RES_RSIZE) { - dma->resi = 0; + if (sc->sc_resi == HIFN_D_RES_RSIZE) { + sc->sc_resi = 0; dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } - *resp = dma->resi++; - dma->resk = dma->resi; + *resp = sc->sc_resi++; + sc->sc_resk = sc->sc_resi; } static int @@ -1563,9 +1563,9 @@ hifn_init_dma(struct hifn_softc *sc) dma->resr[HIFN_D_RES_RSIZE].p = htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); - dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; - dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; - dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; + sc->sc_cmdu = sc->sc_srcu = sc->sc_dstu = sc->sc_resu = 0; + sc->sc_cmdi = sc->sc_srci = sc->sc_dsti = sc->sc_resi = 0; + sc->sc_cmdk = sc->sc_srck = sc->sc_dstk = sc->sc_resk = 0; } /* @@ -1723,7 +1723,7 @@ hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) u_int32_t p, l; int idx, used = 0, i; - idx = dma->dsti; + idx = sc->sc_dsti; for (i = 0; i < dst->nsegs - 1; i++) { dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); dma->dstr[idx].l = htole32(HIFN_D_VALID | @@ -1764,8 +1764,8 @@ hifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) idx = hifn_dmamap_dstwrap(sc, idx); - dma->dsti = idx; - dma->dstu += used; + sc->sc_dsti = idx; + sc->sc_dstu += used; return (idx); } @@ -1792,7 +1792,7 @@ hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) int idx, i; u_int32_t last = 0; - idx = dma->srci; + idx = sc->sc_srci; for (i = 0; i < src->nsegs; i++) { if (i == src->nsegs - 1) last = HIFN_D_LAST; @@ -1805,8 +1805,8 @@ hifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) idx = hifn_dmamap_srcwrap(sc, idx); } - dma->srci = idx; - dma->srcu += src->nsegs; + sc->sc_srci = idx; + sc->sc_srcu += src->nsegs; return (idx); } @@ -1840,13 +1840,13 @@ hifn_crypto( * NB: check this first since it's easy. */ HIFN_LOCK(sc); - if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE || - (dma->resu + 1) > HIFN_D_RES_RSIZE) { + if ((sc->sc_cmdu + 1) > HIFN_D_CMD_RSIZE || + (sc->sc_resu + 1) > HIFN_D_RES_RSIZE) { #ifdef HIFN_DEBUG if (hifn_debug) { device_printf(sc->sc_dev, "cmd/result exhaustion, cmdu %u resu %u\n", - dma->cmdu, dma->resu); + sc->sc_cmdu, sc->sc_resu); } #endif hifnstats.hst_nomem_cr++; @@ -1916,14 +1916,14 @@ hifn_crypto( } if (m0 == NULL) { hifnstats.hst_nomem_mbuf++; - err = dma->cmdu ? ERESTART : ENOMEM; + err = sc->sc_cmdu ? ERESTART : ENOMEM; goto err_srcmap; } if (totlen >= MINCLSIZE) { MCLGET(m0, M_DONTWAIT); if ((m0->m_flags & M_EXT) == 0) { hifnstats.hst_nomem_mcl++; - err = dma->cmdu ? ERESTART : ENOMEM; + err = sc->sc_cmdu ? ERESTART : ENOMEM; m_freem(m0); goto err_srcmap; } @@ -1937,7 +1937,7 @@ hifn_crypto( MGET(m, M_DONTWAIT, MT_DATA); if (m == NULL) { hifnstats.hst_nomem_mbuf++; - err = dma->cmdu ? ERESTART : ENOMEM; + err = sc->sc_cmdu ? ERESTART : ENOMEM; m_freem(m0); goto err_srcmap; } @@ -1946,7 +1946,7 @@ hifn_crypto( MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { hifnstats.hst_nomem_mcl++; - err = dma->cmdu ? ERESTART : ENOMEM; + err = sc->sc_cmdu ? ERESTART : ENOMEM; mlast->m_next = m; m_freem(m0); goto err_srcmap; @@ -1994,7 +1994,7 @@ hifn_crypto( "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", READ_REG_1(sc, HIFN_1_DMA_CSR), READ_REG_1(sc, HIFN_1_DMA_IER), - dma->cmdu, dma->srcu, dma->dstu, dma->resu, + sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu, cmd->src_nsegs, cmd->dst_nsegs); } #endif @@ -2012,14 +2012,14 @@ hifn_crypto( /* * need N src, and N dst */ - if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || - (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { + if ((sc->sc_srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || + (sc->sc_dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { #ifdef HIFN_DEBUG if (hifn_debug) { device_printf(sc->sc_dev, "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", - dma->srcu, cmd->src_nsegs, - dma->dstu, cmd->dst_nsegs); + sc->sc_srcu, cmd->src_nsegs, + sc->sc_dstu, cmd->dst_nsegs); } #endif hifnstats.hst_nomem_sd++; @@ -2027,14 +2027,14 @@ hifn_crypto( goto err_dstmap; } - if (dma->cmdi == HIFN_D_CMD_RSIZE) { - dma->cmdi = 0; + if (sc->sc_cmdi == HIFN_D_CMD_RSIZE) { + sc->sc_cmdi = 0; dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); } - cmdi = dma->cmdi++; + cmdi = sc->sc_cmdi++; cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); @@ -2043,14 +2043,14 @@ hifn_crypto( HIFN_D_MASKDONEIRQ); HIFN_CMDR_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); - dma->cmdu++; + sc->sc_cmdu++; /* * We don't worry about missing an interrupt (which a "command wait" * interrupt salvages us from), unless there is more than one command * in the queue. */ - if (dma->cmdu > 1) { + if (sc->sc_cmdu > 1) { sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); } @@ -2068,17 +2068,17 @@ hifn_crypto( if (hifn_debug) printf("load res\n"); #endif - if (dma->resi == HIFN_D_RES_RSIZE) { - dma->resi = 0; + if (sc->sc_resi == HIFN_D_RES_RSIZE) { + sc->sc_resi = 0; dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } - resi = dma->resi++; - KASSERT(dma->hifn_commands[resi] == NULL, + resi = sc->sc_resi++; + KASSERT(sc->sc_hifn_commands[resi] == NULL, ("hifn_crypto: command slot %u busy", resi)); - dma->hifn_commands[resi] = cmd; + sc->sc_hifn_commands[resi] = cmd; HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { dma->resr[resi].l = htole32(HIFN_MAX_RESULT | @@ -2094,7 +2094,7 @@ hifn_crypto( } HIFN_RESR_SYNC(sc, resi, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - dma->resu++; + sc->sc_resu++; if (cmd->sloplen) cmd->slopidx = resi; @@ -2159,22 +2159,21 @@ hifn_tick(void* vsc) HIFN_LOCK(sc); if (sc->sc_active == 0) { - struct hifn_dma *dma = sc->sc_dma; u_int32_t r = 0; - if (dma->cmdu == 0 && sc->sc_c_busy) { + if (sc->sc_cmdu == 0 && sc->sc_c_busy) { sc->sc_c_busy = 0; r |= HIFN_DMACSR_C_CTRL_DIS; } - if (dma->srcu == 0 && sc->sc_s_busy) { + if (sc->sc_srcu == 0 && sc->sc_s_busy) { sc->sc_s_busy = 0; r |= HIFN_DMACSR_S_CTRL_DIS; } - if (dma->dstu == 0 && sc->sc_d_busy) { + if (sc->sc_dstu == 0 && sc->sc_d_busy) { sc->sc_d_busy = 0; r |= HIFN_DMACSR_D_CTRL_DIS; } - if (dma->resu == 0 && sc->sc_r_busy) { + if (sc->sc_resu == 0 && sc->sc_r_busy) { sc->sc_r_busy = 0; r |= HIFN_DMACSR_R_CTRL_DIS; } @@ -2209,9 +2208,9 @@ hifn_intr(void *arg) device_printf(sc->sc_dev, "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, - dma->cmdi, dma->srci, dma->dsti, dma->resi, - dma->cmdk, dma->srck, dma->dstk, dma->resk, - dma->cmdu, dma->srcu, dma->dstu, dma->resu); + sc->sc_cmdi, sc->sc_srci, sc->sc_dsti, sc->sc_resi, + sc->sc_cmdk, sc->sc_srck, sc->sc_dstk, sc->sc_resk, + sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu); } #endif @@ -2243,7 +2242,7 @@ hifn_intr(void *arg) return; } - if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { + if ((dmacsr & HIFN_DMACSR_C_WAIT) && (sc->sc_cmdu == 0)) { /* * If no slots to process and we receive a "waiting on * command" interrupt, we disable the "waiting on command" @@ -2254,7 +2253,7 @@ hifn_intr(void *arg) } /* clear the rings */ - i = dma->resk; u = dma->resu; + i = sc->sc_resk; u = sc->sc_resu; while (u != 0) { HIFN_RESR_SYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -2269,10 +2268,10 @@ hifn_intr(void *arg) u_int8_t *macbuf = NULL; HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); - cmd = dma->hifn_commands[i]; + cmd = sc->sc_hifn_commands[i]; KASSERT(cmd != NULL, ("hifn_intr: null command slot %u", i)); - dma->hifn_commands[i] = NULL; + sc->sc_hifn_commands[i] = NULL; if (cmd->base_masks & HIFN_BASE_CMD_MAC) { macbuf = dma->result_bufs[i]; @@ -2287,9 +2286,9 @@ hifn_intr(void *arg) if (++i == (HIFN_D_RES_RSIZE + 1)) i = 0; } - dma->resk = i; dma->resu = u; + sc->sc_resk = i; sc->sc_resu = u; - i = dma->srck; u = dma->srcu; + i = sc->sc_srck; u = sc->sc_srcu; while (u != 0) { if (i == HIFN_D_SRC_RSIZE) i = 0; @@ -2302,9 +2301,9 @@ hifn_intr(void *arg) } i++, u--; } - dma->srck = i; dma->srcu = u; + sc->sc_srck = i; sc->sc_srcu = u; - i = dma->cmdk; u = dma->cmdu; + i = sc->sc_cmdk; u = sc->sc_cmdu; while (u != 0) { HIFN_CMDR_SYNC(sc, i, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -2320,7 +2319,7 @@ hifn_intr(void *arg) if (++i == (HIFN_D_CMD_RSIZE + 1)) i = 0; } - dma->cmdk = i; dma->cmdu = u; + sc->sc_cmdk = i; sc->sc_cmdu = u; HIFN_UNLOCK(sc); @@ -2331,7 +2330,7 @@ hifn_intr(void *arg) device_printf(sc->sc_dev, "wakeup crypto (%x) u %d/%d/%d/%d\n", sc->sc_needwakeup, - dma->cmdu, dma->srcu, dma->dstu, dma->resu); + sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu); #endif sc->sc_needwakeup &= ~wakeup; crypto_unblock(sc->sc_cid, wakeup); @@ -2725,11 +2724,11 @@ hifn_abort(struct hifn_softc *sc) struct cryptop *crp; int i, u; - i = dma->resk; u = dma->resu; + i = sc->sc_resk; u = sc->sc_resu; while (u != 0) { - cmd = dma->hifn_commands[i]; + cmd = sc->sc_hifn_commands[i]; KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); - dma->hifn_commands[i] = NULL; + sc->sc_hifn_commands[i] = NULL; crp = cmd->crp; if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { @@ -2783,7 +2782,7 @@ hifn_abort(struct hifn_softc *sc) i = 0; u--; } - dma->resk = i; dma->resu = u; + sc->sc_resk = i; sc->sc_resu = u; hifn_reset_board(sc, 1); hifn_init_dma(sc); @@ -2831,7 +2830,7 @@ hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) (caddr_t)&dma->slop[cmd->slopidx]); } - i = dma->dstk; u = dma->dstu; + i = sc->sc_dstk; u = sc->sc_dstu; while (u != 0) { if (i == HIFN_D_DST_RSIZE) i = 0; @@ -2844,7 +2843,7 @@ hifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) } i++, u--; } - dma->dstk = i; dma->dstu = u; + sc->sc_dstk = i; sc->sc_dstu = u; hifnstats.hst_obytes += cmd->dst_mapsize; diff --git a/sys/dev/hifn/hifn7751var.h b/sys/dev/hifn/hifn7751var.h index 0874943d010..fcae4af554c 100644 --- a/sys/dev/hifn/hifn7751var.h +++ b/sys/dev/hifn/hifn7751var.h @@ -81,7 +81,8 @@ #define MAX_SCATTER 64 /* - * Data structure to hold all 4 rings and any other ring related data. + * Data structure to hold all 4 rings and any other ring related data + * that should reside in DMA. */ struct hifn_dma { /* @@ -93,22 +94,13 @@ struct hifn_dma { struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; - struct hifn_command *hifn_commands[HIFN_D_RES_RSIZE]; u_char command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; u_char result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; u_int32_t slop[HIFN_D_CMD_RSIZE]; - u_int64_t test_src, test_dst; +} ; - /* - * Our current positions for insertion and removal from the desriptor - * rings. - */ - int cmdi, srci, dsti, resi; - volatile int cmdu, srcu, dstu, resu; - int cmdk, srck, dstk, resk; -}; struct hifn_session { int hs_used; @@ -157,6 +149,15 @@ struct hifn_softc { bus_dma_segment_t sc_dmasegs[1]; bus_addr_t sc_dma_physaddr;/* physical address of sc_dma */ int sc_dmansegs; + struct hifn_command *sc_hifn_commands[HIFN_D_RES_RSIZE]; + /* + * Our current positions for insertion and removal from the desriptor + * rings. + */ + int sc_cmdi, sc_srci, sc_dsti, sc_resi; + volatile int sc_cmdu, sc_srcu, sc_dstu, sc_resu; + int sc_cmdk, sc_srck, sc_dstk, sc_resk; + int32_t sc_cid; int sc_maxses; int sc_nsessions; diff --git a/sys/dev/hme/if_hme.c b/sys/dev/hme/if_hme.c index 08cef669343..09e94e74960 100644 --- a/sys/dev/hme/if_hme.c +++ b/sys/dev/hme/if_hme.c @@ -315,9 +315,20 @@ hme_config(struct hme_softc *sc) hme_mifinit(sc); - if ((error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, hme_mediachange, - hme_mediastatus)) != 0) { - device_printf(sc->sc_dev, "phy probe failed: %d\n", error); + /* + * DP83840A used with HME chips don't advertise their media + * capabilities themselves properly so force writing the ANAR + * according to the BMSR in mii_phy_setmedia(). + */ + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, hme_mediachange, + hme_mediastatus, BMSR_DEFCAPMASK, HME_PHYAD_EXTERNAL, + MII_OFFSET_ANY, MIIF_FORCEANEG); + i = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, hme_mediachange, + hme_mediastatus, BMSR_DEFCAPMASK, HME_PHYAD_INTERNAL, + MII_OFFSET_ANY, MIIF_FORCEANEG); + if (error != 0 && i != 0) { + error = ENXIO; + device_printf(sc->sc_dev, "attaching PHYs failed\n"); goto fail_rxdesc; } sc->sc_mii = device_get_softc(sc->sc_miibus); @@ -1404,10 +1415,6 @@ hme_mii_readreg(device_t dev, int phy, int reg) int n; u_int32_t v; - /* We can at most have two PHYs. */ - if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL) - return (0); - sc = device_get_softc(dev); /* Select the desired PHY in the MIF configuration register */ v = HME_MIF_READ_4(sc, HME_MIFI_CFG); @@ -1445,10 +1452,6 @@ hme_mii_writereg(device_t dev, int phy, int reg, int val) int n; u_int32_t v; - /* We can at most have two PHYs. */ - if (phy != HME_PHYAD_EXTERNAL && phy != HME_PHYAD_INTERNAL) - return (0); - sc = device_get_softc(dev); /* Select the desired PHY in the MIF configuration register */ v = HME_MIF_READ_4(sc, HME_MIFI_CFG); diff --git a/sys/dev/hptrr/hptrr_osm_bsd.c b/sys/dev/hptrr/hptrr_osm_bsd.c index 6bc30c22b36..046979153f0 100644 --- a/sys/dev/hptrr/hptrr_osm_bsd.c +++ b/sys/dev/hptrr/hptrr_osm_bsd.c @@ -1178,7 +1178,7 @@ static void hpt_final_init(void *dummy) } make_dev(&hpt_cdevsw, DRIVER_MINOR, UID_ROOT, GID_OPERATOR, - S_IRUSR | S_IWUSR, driver_name); + S_IRUSR | S_IWUSR, "%s", driver_name); } #if defined(KLD_MODULE) && (__FreeBSD_version >= 503000) diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c index 7c4476d8f09..01bd482bbb7 100644 --- a/sys/dev/hwpmc/hwpmc_core.c +++ b/sys/dev/hwpmc/hwpmc_core.c @@ -2234,21 +2234,8 @@ pmc_core_initialize(struct pmc_mdep *md, int maxcpu) core_iaf_npmc = cpuid[CORE_CPUID_EDX] & 0x1F; core_iaf_width = (cpuid[CORE_CPUID_EDX] >> 5) & 0xFF; - if (core_iaf_npmc > 0) { - iaf_initialize(md, maxcpu, core_iaf_npmc, - core_iaf_width); - core_pmcmask |= ((1ULL << core_iaf_npmc) - 1) << - IAF_OFFSET; - } else { - /* - * Adjust the number of classes exported to - * user space. - */ - md->pmd_nclass--; - KASSERT(md->pmd_nclass == 2, - ("[core,%d] unexpected nclass %d", __LINE__, - md->pmd_nclass)); - } + iaf_initialize(md, maxcpu, core_iaf_npmc, core_iaf_width); + core_pmcmask |= ((1ULL << core_iaf_npmc) - 1) << IAF_OFFSET; } PMCDBG(MDP,INI,1,"core-init pmcmask=0x%jx iafri=%d", core_pmcmask, diff --git a/sys/dev/hwpmc/pmc_events.h b/sys/dev/hwpmc/pmc_events.h index df2d3efd7bf..9fcf92608d3 100644 --- a/sys/dev/hwpmc/pmc_events.h +++ b/sys/dev/hwpmc/pmc_events.h @@ -2243,11 +2243,11 @@ __PMC_EV_ALIAS("UOPS_RETIRED.MACRO_FUSED", IAP_EVENT_C2H_04H) \ __PMC_EV_ALIAS("MACHINE_CLEARS.CYCLES", IAP_EVENT_C3H_01H) \ __PMC_EV_ALIAS("MACHINE_CLEARS.MEM_ORDER", IAP_EVENT_C3H_02H) \ __PMC_EV_ALIAS("MACHINE_CLEARS.SMC", IAP_EVENT_C3H_04H) \ -__PMC_EV_ALIAS("BR_INST_RETIRED.ALL_BRANCHES", IAP_EVENT_C4H_00H) \ +__PMC_EV_ALIAS("BR_INST_RETIRED.ANY_P", IAP_EVENT_C4H_00H) \ __PMC_EV_ALIAS("BR_INST_RETIRED.CONDITIONAL", IAP_EVENT_C4H_01H) \ __PMC_EV_ALIAS("BR_INST_RETIRED.NEAR_CALL", IAP_EVENT_C4H_02H) \ __PMC_EV_ALIAS("BR_INST_RETIRED.ALL_BRANCHES", IAP_EVENT_C4H_04H) \ -__PMC_EV_ALIAS("BR_MISP_RETIRED.ALL_BRANCHES", IAP_EVENT_C5H_00H) \ +__PMC_EV_ALIAS("BR_MISP_RETIRED.ANY_P", IAP_EVENT_C5H_00H) \ __PMC_EV_ALIAS("BR_MISP_RETIRED.CONDITIONAL", IAP_EVENT_C5H_01H) \ __PMC_EV_ALIAS("BR_MISP_RETIRED.NEAR_CALL", IAP_EVENT_C5H_02H) \ __PMC_EV_ALIAS("BR_MISP_RETIRED.ALL_BRANCHES", IAP_EVENT_C5H_04H) \ diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c index 0843afe40cf..c90b7059f0c 100644 --- a/sys/dev/ichsmb/ichsmb_pci.c +++ b/sys/dev/ichsmb/ichsmb_pci.c @@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$"); #define ID_PCH 0x3b308086 #define ID_6300ESB 0x25a48086 #define ID_631xESB 0x269b8086 +#define ID_CPT 0x1c228086 #define PCIS_SERIALBUS_SMBUS_PROGIF 0x00 @@ -174,6 +175,9 @@ ichsmb_pci_probe(device_t dev) case ID_631xESB: device_set_desc(dev, "Intel 631xESB/6321ESB (ESB2) SMBus controller"); break; + case ID_CPT: + device_set_desc(dev, "Intel Cougar Point SMBus controller"); + break; default: return (ENXIO); } diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c index a3b112f06b2..727b96d3006 100644 --- a/sys/dev/ichwd/ichwd.c +++ b/sys/dev/ichwd/ichwd.c @@ -110,7 +110,53 @@ static struct ichwd_device ichwd_devices[] = { { DEVICEID_ICH10D, "Intel ICH10D watchdog timer", 10 }, { DEVICEID_ICH10DO, "Intel ICH10DO watchdog timer", 10 }, { DEVICEID_ICH10R, "Intel ICH10R watchdog timer", 10 }, + { DEVICEID_PCH, "Intel PCH watchdog timer", 10 }, + { DEVICEID_PCHM, "Intel PCH watchdog timer", 10 }, + { DEVICEID_P55, "Intel P55 watchdog timer", 10 }, + { DEVICEID_PM55, "Intel PM55 watchdog timer", 10 }, { DEVICEID_H55, "Intel H55 watchdog timer", 10 }, + { DEVICEID_QM57, "Intel QM57 watchdog timer", 10 }, + { DEVICEID_H57, "Intel H57 watchdog timer", 10 }, + { DEVICEID_HM55, "Intel HM55 watchdog timer", 10 }, + { DEVICEID_Q57, "Intel Q57 watchdog timer", 10 }, + { DEVICEID_HM57, "Intel HM57 watchdog timer", 10 }, + { DEVICEID_PCHMSFF, "Intel PCHMSFF watchdog timer", 10 }, + { DEVICEID_QS57, "Intel QS57 watchdog timer", 10 }, + { DEVICEID_3400, "Intel 3400 watchdog timer", 10 }, + { DEVICEID_3420, "Intel 3420 watchdog timer", 10 }, + { DEVICEID_3450, "Intel 3450 watchdog timer", 10 }, + { DEVICEID_CPT0, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT1, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT2, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT3, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT4, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT5, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT6, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT7, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT8, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT9, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT10, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT11, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT12, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT13, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT14, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT15, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT16, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT17, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT18, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT19, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT20, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT21, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT22, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT25, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT26, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT27, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT28, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT29, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT30, "Intel Cougar Point watchdog timer", 10 }, + { DEVICEID_CPT31, "Intel Cougar Point watchdog timer", 10 }, { 0, NULL, 0 }, }; diff --git a/sys/dev/ichwd/ichwd.h b/sys/dev/ichwd/ichwd.h index 9cc8f1b65d4..c0a11414468 100644 --- a/sys/dev/ichwd/ichwd.h +++ b/sys/dev/ichwd/ichwd.h @@ -64,6 +64,38 @@ struct ichwd_softc { }; #define VENDORID_INTEL 0x8086 +#define DEVICEID_CPT0 0x1c40 +#define DEVICEID_CPT1 0x1c41 +#define DEVICEID_CPT2 0x1c42 +#define DEVICEID_CPT3 0x1c43 +#define DEVICEID_CPT4 0x1c44 +#define DEVICEID_CPT5 0x1c45 +#define DEVICEID_CPT6 0x1c46 +#define DEVICEID_CPT7 0x1c47 +#define DEVICEID_CPT8 0x1c48 +#define DEVICEID_CPT9 0x1c49 +#define DEVICEID_CPT10 0x1c4a +#define DEVICEID_CPT11 0x1c4b +#define DEVICEID_CPT12 0x1c4c +#define DEVICEID_CPT13 0x1c4d +#define DEVICEID_CPT14 0x1c4e +#define DEVICEID_CPT15 0x1c4f +#define DEVICEID_CPT16 0x1c50 +#define DEVICEID_CPT17 0x1c51 +#define DEVICEID_CPT18 0x1c52 +#define DEVICEID_CPT19 0x1c53 +#define DEVICEID_CPT20 0x1c54 +#define DEVICEID_CPT21 0x1c55 +#define DEVICEID_CPT22 0x1c56 +#define DEVICEID_CPT23 0x1c57 +#define DEVICEID_CPT24 0x1c58 +#define DEVICEID_CPT25 0x1c59 +#define DEVICEID_CPT26 0x1c5a +#define DEVICEID_CPT27 0x1c5b +#define DEVICEID_CPT28 0x1c5c +#define DEVICEID_CPT29 0x1c5d +#define DEVICEID_CPT30 0x1c5e +#define DEVICEID_CPT31 0x1c5f #define DEVICEID_82801AA 0x2410 #define DEVICEID_82801AB 0x2420 #define DEVICEID_82801BA 0x2440 @@ -100,7 +132,21 @@ struct ichwd_softc { #define DEVICEID_ICH10D 0x3a1a #define DEVICEID_ICH10DO 0x3a14 #define DEVICEID_ICH10R 0x3a16 +#define DEVICEID_PCH 0x3b00 +#define DEVICEID_PCHM 0x3b01 +#define DEVICEID_P55 0x3b02 +#define DEVICEID_PM55 0x3b03 #define DEVICEID_H55 0x3b06 +#define DEVICEID_QM57 0x3b07 +#define DEVICEID_H57 0x3b08 +#define DEVICEID_HM55 0x3b09 +#define DEVICEID_Q57 0x3b0a +#define DEVICEID_HM57 0x3b0b +#define DEVICEID_PCHMSFF 0x3b0d +#define DEVICEID_QS57 0x3b0f +#define DEVICEID_3400 0x3b12 +#define DEVICEID_3420 0x3b14 +#define DEVICEID_3450 0x3b16 /* ICH LPC Interface Bridge Registers (ICH5 and older) */ #define ICH_GEN_STA 0xd4 diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c index 2ec9d0ed1f2..763ed740ec1 100644 --- a/sys/dev/if_ndis/if_ndis.c +++ b/sys/dev/if_ndis/if_ndis.c @@ -1644,10 +1644,6 @@ ndis_linksts_done(adapter) default: break; } - - /* Notify possible listners of interface change. */ - - rt_ifmsg(ifp); } static void @@ -2115,7 +2111,7 @@ ndis_set_cipher(sc, cipher) len = sizeof(arg); - if (cipher == WPA_CSE_WEP40 || WPA_CSE_WEP104) { + if (cipher == WPA_CSE_WEP40 || cipher == WPA_CSE_WEP104) { if (!(ic->ic_cryptocaps & IEEE80211_CRYPTO_WEP)) return (ENOTSUP); arg = NDIS_80211_WEPSTAT_ENC1ENABLED; diff --git a/sys/dev/if_ndis/if_ndis_usb.c b/sys/dev/if_ndis/if_ndis_usb.c index b872f9ac52a..9aa717089f1 100644 --- a/sys/dev/if_ndis/if_ndis_usb.c +++ b/sys/dev/if_ndis/if_ndis_usb.c @@ -107,6 +107,7 @@ static driver_t ndis_driver = { static devclass_t ndis_devclass; DRIVER_MODULE(ndis, uhub, ndis_driver, ndis_devclass, ndisdrv_modevent, 0); +MODULE_VERSION(ndis, 1); static int ndisusb_devcompare(interface_type bustype, struct ndis_usb_type *t, device_t dev) diff --git a/sys/dev/iicbus/ds1775.c b/sys/dev/iicbus/ds1775.c new file mode 100644 index 00000000000..f066f2a887e --- /dev/null +++ b/sys/dev/iicbus/ds1775.c @@ -0,0 +1,255 @@ +/*- + * Copyright (c) 2010 Andreas Tobler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define FCU_ZERO_C_TO_K 2732 + +/* Drivebay sensor: LM75/DS1775. */ +#define DS1775_TEMP 0x0 + +struct ds1775_sensor { + char location[32]; +}; + +/* Regular bus attachment functions */ +static int ds1775_probe(device_t); +static int ds1775_attach(device_t); + +/* Utility functions */ +static int ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS); +static void ds1775_start(void *xdev); +static int ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, + uint16_t *data); + +struct ds1775_softc { + device_t sc_dev; + struct intr_config_hook enum_hook; + uint32_t sc_addr; + struct ds1775_sensor *sc_sensors; + +}; +static device_method_t ds1775_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ds1775_probe), + DEVMETHOD(device_attach, ds1775_attach), + { 0, 0 }, +}; + +static driver_t ds1775_driver = { + "ds1775", + ds1775_methods, + sizeof(struct ds1775_softc) +}; + +static devclass_t ds1775_devclass; + +DRIVER_MODULE(ds1755, iicbus, ds1775_driver, ds1775_devclass, 0, 0); +MALLOC_DEFINE(M_DS1775, "ds1775", "Temp-Monitor DS1775"); + +static int +ds1775_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) +{ + uint8_t buf[4]; + + struct iic_msg msg[2] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_RD, 2, buf }, + }; + + if (iicbus_transfer(dev, msg, 2) != 0) { + device_printf(dev, "iicbus read failed\n"); + return (EIO); + } + + *data = *((uint16_t*)buf); + + return (0); +} + +static int +ds1775_probe(device_t dev) +{ + const char *name, *compatible; + struct ds1775_softc *sc; + + name = ofw_bus_get_name(dev); + compatible = ofw_bus_get_compat(dev); + + if (!name) + return (ENXIO); + + if (strcmp(name, "temp-monitor") != 0 || + strcmp(compatible, "ds1775") != 0) + return (ENXIO); + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_addr = iicbus_get_addr(dev); + + device_set_desc(dev, "Temp-Monitor DS1755"); + + return (0); +} + +static int +ds1775_attach(device_t dev) +{ + struct ds1775_softc *sc; + + sc = device_get_softc(dev); + + sc->enum_hook.ich_func = ds1775_start; + sc->enum_hook.ich_arg = dev; + + /* We have to wait until interrupts are enabled. I2C read and write + * only works if the interrupts are available. + * The unin/i2c is controlled by the htpic on unin. But this is not + * the master. The openpic on mac-io is controlling the htpic. + * This one gets attached after the mac-io probing and then the + * interrupts will be available. + */ + + if (config_intrhook_establish(&sc->enum_hook) != 0) + return (ENOMEM); + + return (0); +} + +static void +ds1775_start(void *xdev) +{ + phandle_t child; + struct ds1775_softc *sc; + struct ds1775_sensor *sens; + struct sysctl_oid *sensroot_oid; + struct sysctl_ctx_list *ctx; + int i; + char sysctl_name[40], sysctl_desc[40]; + const char *units; + + device_t dev = (device_t)xdev; + + sc = device_get_softc(dev); + + child = ofw_bus_get_node(dev); + + sc->sc_sensors = malloc (sizeof(struct ds1775_sensor), + M_DS1775, M_WAITOK | M_ZERO); + + sens = sc->sc_sensors; + + ctx = device_get_sysctl_ctx(dev); + sensroot_oid = device_get_sysctl_tree(dev); + + OF_getprop(child, "hwsensor-location", sens->location, + sizeof(sens->location)); + units = "C"; + + for (i = 0; i < strlen(sens->location); i++) { + sysctl_name[i] = tolower(sens->location[i]); + if (isspace(sysctl_name[i])) + sysctl_name[i] = '_'; + } + sysctl_name[i] = 0; + + sprintf(sysctl_desc,"%s (%s)", sens->location, units); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensroot_oid), OID_AUTO, + sysctl_name, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, + 0, ds1775_sensor_sysctl, "IK", sysctl_desc); + + config_intrhook_disestablish(&sc->enum_hook); +} + +static int +ds1775_sensor_read(device_t dev, struct ds1775_sensor *sens, int *temp) +{ + struct ds1775_softc *sc; + uint16_t buf[2]; + uint16_t read; + + sc = device_get_softc(dev); + + ds1775_read_2(sc->sc_dev, sc->sc_addr, DS1775_TEMP, buf); + + read = *((int16_t *)buf); + + /* The default mode of the ADC is 9 bit, the resolution is 0.5 C per + bit. The temperature is in tenth kelvin. + */ + *temp = ((int16_t)(read) >> 7) * 5; + + return (0); +} +static int +ds1775_sensor_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev; + struct ds1775_softc *sc; + struct ds1775_sensor *sens; + int value; + int error; + unsigned int temp; + + dev = arg1; + sc = device_get_softc(dev); + sens = &sc->sc_sensors[arg2]; + + error = ds1775_sensor_read(dev, sens, &value); + if (error != 0) + return (error); + + temp = value + FCU_ZERO_C_TO_K; + + error = sysctl_handle_int(oidp, &temp, 0, req); + + return (error); +} diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c index 5c16f207f1f..ca110c85746 100644 --- a/sys/dev/iicbus/iicbus.c +++ b/sys/dev/iicbus/iicbus.c @@ -188,7 +188,7 @@ iicbus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) } static device_t -iicbus_add_child(device_t dev, int order, const char *name, int unit) +iicbus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct iicbus_ivar *devi; diff --git a/sys/dev/iicbus/max6690.c b/sys/dev/iicbus/max6690.c new file mode 100644 index 00000000000..527c6433623 --- /dev/null +++ b/sys/dev/iicbus/max6690.c @@ -0,0 +1,335 @@ +/*- + * Copyright (c) 2010 Andreas Tobler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define FCU_ZERO_C_TO_K 2732 + +/* Inlet, Backside, U3 Heatsink sensor: MAX6690. */ + +#define MAX6690_INT_TEMP 0x0 +#define MAX6690_EXT_TEMP 0x1 +#define MAX6690_EEXT_TEMP 0x10 +#define MAX6690_IEXT_TEMP 0x11 +#define MAX6690_TEMP_MASK 0xe0 + +struct max6690_sensor { + int id; + char location[32]; +}; + +/* Regular bus attachment functions */ +static int max6690_probe(device_t); +static int max6690_attach(device_t); + +/* Utility functions */ +static int max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS); +static void max6690_start(void *xdev); +static int max6690_read_1(device_t dev, uint32_t addr, uint8_t reg, + uint8_t *data); + +struct max6690_softc { + device_t sc_dev; + struct intr_config_hook enum_hook; + uint32_t sc_addr; + struct max6690_sensor *sc_sensors; + int sc_nsensors; +}; +static device_method_t max6690_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, max6690_probe), + DEVMETHOD(device_attach, max6690_attach), + { 0, 0 }, +}; + +static driver_t max6690_driver = { + "max6690", + max6690_methods, + sizeof(struct max6690_softc) +}; + +static devclass_t max6690_devclass; + +DRIVER_MODULE(max6690, iicbus, max6690_driver, max6690_devclass, 0, 0); +MALLOC_DEFINE(M_MAX6690, "max6690", "Temp-Monitor MAX6690"); + +static int +max6690_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) +{ + uint8_t buf[4]; + + struct iic_msg msg[2] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_RD, 1, buf }, + }; + + if (iicbus_transfer(dev, msg, 2) != 0) { + device_printf(dev, "iicbus read failed\n"); + return (EIO); + } + + *data = *((uint8_t*)buf); + + return (0); +} + +static int +max6690_probe(device_t dev) +{ + const char *name, *compatible; + struct max6690_softc *sc; + + name = ofw_bus_get_name(dev); + compatible = ofw_bus_get_compat(dev); + + if (!name) + return (ENXIO); + + if (strcmp(name, "temp-monitor") != 0 || + strcmp(compatible, "max6690") != 0) + return (ENXIO); + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_addr = iicbus_get_addr(dev); + + device_set_desc(dev, "Temp-Monitor MAX6690"); + + return (0); +} + +/* + * This function returns the number of sensors. If we call it the second time + * and we have allocated memory for sc->sc_sensors, we fill in the properties. + */ +static int +max6690_fill_sensor_prop(device_t dev) +{ + phandle_t child; + struct max6690_softc *sc; + u_int id[8]; + char location[96]; + int i = 0, j, len = 0, prop_len, prev_len = 0; + + sc = device_get_softc(dev); + + child = ofw_bus_get_node(dev); + + /* Fill the sensor location property. */ + prop_len = OF_getprop(child, "hwsensor-location", location, + sizeof(location)); + while (len < prop_len) { + if (sc->sc_sensors != NULL) + strcpy(sc->sc_sensors[i].location, location + len); + prev_len = strlen(location + len) + 1; + len += prev_len; + i++; + } + if (sc->sc_sensors == NULL) + return (i); + + /* Fill the sensor id property. */ + prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id)); + for (j = 0; j < i; j++) + sc->sc_sensors[j].id = (id[j] & 0xf); + + return (i); +} +static int +max6690_attach(device_t dev) +{ + struct max6690_softc *sc; + + sc = device_get_softc(dev); + + sc->enum_hook.ich_func = max6690_start; + sc->enum_hook.ich_arg = dev; + + /* We have to wait until interrupts are enabled. I2C read and write + * only works if the interrupts are available. + * The unin/i2c is controlled by the htpic on unin. But this is not + * the master. The openpic on mac-io is controlling the htpic. + * This one gets attached after the mac-io probing and then the + * interrupts will be available. + */ + + if (config_intrhook_establish(&sc->enum_hook) != 0) + return (ENOMEM); + + return (0); +} + +static void +max6690_start(void *xdev) +{ + phandle_t child; + struct max6690_softc *sc; + struct sysctl_oid *oid, *sensroot_oid; + struct sysctl_ctx_list *ctx; + char sysctl_name[32]; + int i, j; + + device_t dev = (device_t)xdev; + + sc = device_get_softc(dev); + + sc->sc_nsensors = 0; + + child = ofw_bus_get_node(dev); + + /* Count the actual number of sensors. */ + sc->sc_nsensors = max6690_fill_sensor_prop(dev); + + device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors); + + if (sc->sc_nsensors == 0) + device_printf(dev, "WARNING: No MAX6690 sensors detected!\n"); + + sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct max6690_sensor), + M_MAX6690, M_WAITOK | M_ZERO); + + ctx = device_get_sysctl_ctx(dev); + sensroot_oid = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor", + CTLFLAG_RD, 0, "MAX6690 Sensor Information"); + + /* Now we can fill the properties into the allocated struct. */ + sc->sc_nsensors = max6690_fill_sensor_prop(dev); + + /* Add sysctls for the sensors. */ + for (i = 0; i < sc->sc_nsensors; i++) { + for (j = 0; j < strlen(sc->sc_sensors[i].location); j++) { + sysctl_name[j] = tolower(sc->sc_sensors[i].location[j]); + if (isspace(sysctl_name[j])) + sysctl_name[j] = '_'; + } + sysctl_name[j] = 0; + + oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), + OID_AUTO, + sysctl_name, CTLFLAG_RD, 0, + "Sensor Information"); + /* I use i to pass the sensor id. */ + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "temp", + CTLTYPE_INT | CTLFLAG_RD, dev, i % 2, + max6690_sensor_sysctl, "IK", + "Sensor Temp in °C"); + + } + /* Dump sensor location & ID. */ + if (bootverbose) { + device_printf(dev, "Sensors\n"); + for (i = 0; i < sc->sc_nsensors; i++) { + device_printf(dev, "Location : %s ID: %d\n", + sc->sc_sensors[i].location, + sc->sc_sensors[i].id); + } + } + + config_intrhook_disestablish(&sc->enum_hook); +} + +static int +max6690_sensor_read(device_t dev, struct max6690_sensor *sens, int *temp) +{ + uint8_t reg_int = 0, reg_ext = 0; + uint8_t integer; + uint8_t fraction; + struct max6690_softc *sc; + + sc = device_get_softc(dev); + + /* The internal sensor id's are even, the external ar odd. */ + if ((sens->id % 2) == 0) { + reg_int = MAX6690_INT_TEMP; + reg_ext = MAX6690_IEXT_TEMP; + } else { + reg_int = MAX6690_EXT_TEMP; + reg_ext = MAX6690_EEXT_TEMP; + } + + max6690_read_1(sc->sc_dev, sc->sc_addr, reg_int, &integer); + + max6690_read_1(sc->sc_dev, sc->sc_addr, reg_ext, &fraction); + + fraction &= MAX6690_TEMP_MASK; + + /* The temperature is in tenth kelvin, the fractional part resolution + is 0.125. + */ + *temp = (integer * 10) + (fraction >> 5) * 10 / 8; + + return (0); +} + +static int +max6690_sensor_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev; + struct max6690_softc *sc; + struct max6690_sensor *sens; + int value = 0; + int error; + unsigned int temp; + + dev = arg1; + sc = device_get_softc(dev); + sens = &sc->sc_sensors[arg2]; + + error = max6690_sensor_read(dev, sens, &value); + if (error != 0) + return (error); + + temp = value + FCU_ZERO_C_TO_K; + + error = sysctl_handle_int(oidp, &temp, 0, req); + + return (error); +} diff --git a/sys/dev/iscsi/initiator/iscsi.c b/sys/dev/iscsi/initiator/iscsi.c index 2eee8120d2b..5d7a5b7f720 100644 --- a/sys/dev/iscsi/initiator/iscsi.c +++ b/sys/dev/iscsi/initiator/iscsi.c @@ -295,12 +295,6 @@ iscsi_read(struct cdev *dev, struct uio *uio, int ioflag) sprintf(buf, "%d/%d /---- free -----/\n", sc->npdu_alloc, sc->npdu_max); i = 0; uiomove(buf, strlen(buf), uio); - TAILQ_FOREACH(pq, &sc->freepdu, pq_link) { - if(uio->uio_resid == 0) - return 0; - sprintf(buf, "%03d] %06x\n", i++, ntohl(pq->pdu.ipdu.bhs.itt)); - uiomove(buf, strlen(buf), uio); - } } else { int i = 0; @@ -704,15 +698,10 @@ iscsi_shutdown(void *v) static void free_pdus(struct isc_softc *sc) { - pduq_t *pq; debug_called(8); if(sc->pdu_zone != NULL) { - TAILQ_FOREACH(pq, &sc->freepdu, pq_link) { - TAILQ_REMOVE(&sc->freepdu, pq, pq_link); - uma_zfree(sc->pdu_zone, pq); - } uma_zdestroy(sc->pdu_zone); sc->pdu_zone = NULL; } @@ -730,7 +719,6 @@ iscsi_start(void) isc->dev = make_dev(&iscsi_cdevsw, max_sessions, UID_ROOT, GID_WHEEL, 0600, "iscsi"); isc->dev->si_drv1 = isc; mtx_init(&isc->isc_mtx, "iscsi", NULL, MTX_DEF); - mtx_init(&isc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF); TAILQ_INIT(&isc->isc_sess); /* @@ -744,7 +732,6 @@ iscsi_start(void) // XXX: should fail... } uma_zone_set_max(isc->pdu_zone, max_pdus); - TAILQ_INIT(&isc->freepdu); isc->unit = new_unrhdr(0, max_sessions-1, NULL); sx_init(&isc->unit_sx, "iscsi sx"); @@ -818,7 +805,6 @@ iscsi_stop(void) ic_destroy(sp); } mtx_destroy(&isc->isc_mtx); - mtx_destroy(&isc->pdu_mtx); sx_destroy(&isc->unit_sx); free_pdus(isc); diff --git a/sys/dev/iscsi/initiator/iscsivar.h b/sys/dev/iscsi/initiator/iscsivar.h index a6eae21ee03..0a56f800e84 100644 --- a/sys/dev/iscsi/initiator/iscsivar.h +++ b/sys/dev/iscsi/initiator/iscsivar.h @@ -203,10 +203,7 @@ struct isc_softc { struct unrhdr *unit; struct sx unit_sx; - struct mtx pdu_mtx; uma_zone_t pdu_zone; // pool of free pdu's - TAILQ_HEAD(,pduq) freepdu; - #ifdef ISCSI_INITIATOR_DEBUG int npdu_alloc, npdu_max; // for instrumentation #endif @@ -303,25 +300,15 @@ pdu_alloc(struct isc_softc *isc, int wait) { pduq_t *pq; - mtx_lock(&isc->pdu_mtx); - if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) { - mtx_unlock(&isc->pdu_mtx); - pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); - } - else { - TAILQ_REMOVE(&isc->freepdu, pq, pq_link); - mtx_unlock(&isc->pdu_mtx); - } + pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); if(pq == NULL) { debug(7, "out of mem"); return NULL; } #ifdef ISCSI_INITIATOR_DEBUG - mtx_lock(&isc->pdu_mtx); isc->npdu_alloc++; if(isc->npdu_alloc > isc->npdu_max) isc->npdu_max = isc->npdu_alloc; - mtx_unlock(&isc->pdu_mtx); #endif memset(pq, 0, sizeof(pduq_t)); @@ -337,12 +324,10 @@ pdu_free(struct isc_softc *isc, pduq_t *pq) if(pq->buf != NULL) free(pq->buf, M_ISCSIBUF); #endif - mtx_lock(&isc->pdu_mtx); - TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link); #ifdef ISCSI_INITIATOR_DEBUG isc->npdu_alloc--; #endif - mtx_unlock(&isc->pdu_mtx); + uma_zfree(isc->pdu_zone, pq); } static __inline void diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c index 4b765ef16e9..de2bfb13cbb 100644 --- a/sys/dev/iwi/if_iwi.c +++ b/sys/dev/iwi/if_iwi.c @@ -180,6 +180,7 @@ static void iwi_release_fw_dma(struct iwi_softc *sc); static int iwi_config(struct iwi_softc *); static int iwi_get_firmware(struct iwi_softc *, enum ieee80211_opmode); static void iwi_put_firmware(struct iwi_softc *); +static void iwi_monitor_scan(void *, int); static int iwi_scanchan(struct iwi_softc *, unsigned long, int); static void iwi_scan_start(struct ieee80211com *); static void iwi_scan_end(struct ieee80211com *); @@ -292,6 +293,7 @@ iwi_attach(device_t dev) TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc); TASK_INIT(&sc->sc_disassoctask, 0, iwi_disassoc, sc); TASK_INIT(&sc->sc_wmetask, 0, iwi_update_wme, sc); + TASK_INIT(&sc->sc_monitortask, 0, iwi_monitor_scan, sc); callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_rftimer, &sc->sc_mtx, 0); @@ -460,6 +462,7 @@ iwi_detach(device_t dev) ieee80211_draintask(ic, &sc->sc_radiofftask); ieee80211_draintask(ic, &sc->sc_restarttask); ieee80211_draintask(ic, &sc->sc_disassoctask); + ieee80211_draintask(ic, &sc->sc_monitortask); iwi_stop(sc); @@ -988,7 +991,8 @@ iwi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * This is all totally bogus and needs to be redone. */ iwi_auth_and_assoc(sc, vap); - } + } else if (vap->iv_opmode == IEEE80211_M_MONITOR) + ieee80211_runtask(ic, &sc->sc_monitortask); break; case IEEE80211_S_ASSOC: /* @@ -1364,7 +1368,7 @@ iwi_checkforqos(struct ieee80211vap *vap, ni = vap->iv_bss; ni->ni_capinfo = capinfo; - ni->ni_associd = associd; + ni->ni_associd = associd & 0x3fff; if (wme != NULL) ni->ni_flags |= IEEE80211_NODE_QOS; else @@ -1407,6 +1411,18 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) IWI_STATE_END(sc, IWI_FW_SCANNING); + /* + * Monitor mode works by doing a passive scan to set + * the channel and enable rx. Because we don't want + * to abort a scan lest the firmware crash we scan + * for a short period of time and automatically restart + * the scan when notified the sweep has completed. + */ + if (vap->iv_opmode == IEEE80211_M_MONITOR) { + ieee80211_runtask(ic, &sc->sc_monitortask); + break; + } + if (scan->status == IWI_SCAN_COMPLETED) { /* NB: don't need to defer, net80211 does it for us */ ieee80211_scan_next(vap); @@ -1467,7 +1483,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif) IWI_STATE_END(sc, IWI_FW_ASSOCIATING); iwi_checkforqos(vap, (const struct ieee80211_frame *)(assoc+1), - le16toh(notif->len) - sizeof(*assoc)); + le16toh(notif->len) - sizeof(*assoc) - 1); ieee80211_new_state(vap, IEEE80211_S_RUN, -1); break; case IWI_ASSOC_INIT: @@ -2557,6 +2573,11 @@ iwi_config(struct iwi_softc *sc) config.answer_pbreq = (ic->ic_opmode == IEEE80211_M_IBSS) ? 1 : 0; config.disable_unicast_decryption = 1; config.disable_multicast_decryption = 1; + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + config.allow_invalid_frames = 1; + config.allow_beacon_and_probe_resp = 1; + config.allow_mgt = 1; + } DPRINTF(("Configuring adapter\n")); error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config); if (error != 0) @@ -2642,6 +2663,17 @@ scan_band(const struct ieee80211_channel *c) return IEEE80211_IS_CHAN_5GHZ(c) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ; } +static void +iwi_monitor_scan(void *arg, int npending) +{ + struct iwi_softc *sc = arg; + IWI_LOCK_DECL; + + IWI_LOCK(sc); + (void) iwi_scanchan(sc, 2000, 0); + IWI_UNLOCK(sc); +} + /* * Start a scan on the current channel or all channels. */ diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h index 7a11d888bcf..17336772c72 100644 --- a/sys/dev/iwi/if_iwivar.h +++ b/sys/dev/iwi/if_iwivar.h @@ -193,6 +193,7 @@ struct iwi_softc { struct task sc_restarttask; /* restart adapter processing */ struct task sc_disassoctask; struct task sc_wmetask; /* set wme parameters */ + struct task sc_monitortask; unsigned int sc_softled : 1, /* enable LED gpio status */ sc_ledstate: 1, /* LED on/off state */ diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index be617fc17d5..e5fa6d65b23 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -135,8 +135,6 @@ static void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *, static void iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); #endif -static void iwn5000_rx_calib_results(struct iwn_softc *, - struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *, struct iwn_rx_data *); static void iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *, @@ -220,8 +218,14 @@ static void iwn5000_ampdu_tx_start(struct iwn_softc *, struct ieee80211_node *, uint8_t, uint16_t); static void iwn5000_ampdu_tx_stop(struct iwn_softc *, uint8_t, uint16_t); #endif -static int iwn5000_query_calibration(struct iwn_softc *); -static int iwn5000_send_calibration(struct iwn_softc *); +static int iwn5000_send_calib_results(struct iwn_softc *); +static int iwn5000_save_calib_result(struct iwn_softc *, + struct iwn_phy_calib *, int, int); +static void iwn5000_free_calib_results(struct iwn_softc *); +static int iwn5000_chrystal_calib(struct iwn_softc *); +static int iwn5000_send_calib_query(struct iwn_softc *); +static int iwn5000_rx_calib_result(struct iwn_softc *, + struct iwn_rx_desc *, struct iwn_rx_data *); static int iwn5000_send_wimax_coex(struct iwn_softc *); static int iwn4965_post_alive(struct iwn_softc *); static int iwn5000_post_alive(struct iwn_softc *); @@ -705,6 +709,9 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn5000fw"; sc->txchainmask = IWN_ANT_B; sc->rxchainmask = IWN_ANT_AB; + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | + IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_5150: sc->sc_hal = &iwn5000_hal; @@ -712,6 +719,8 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn5150fw"; sc->txchainmask = IWN_ANT_A; sc->rxchainmask = IWN_ANT_AB; + sc->calib_init = IWN_CALIB_DC | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_5300: case IWN_HW_REV_TYPE_5350: @@ -720,6 +729,9 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn5000fw"; sc->txchainmask = IWN_ANT_ABC; sc->rxchainmask = IWN_ANT_ABC; + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | + IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_1000: sc->sc_hal = &iwn5000_hal; @@ -727,6 +739,9 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn1000fw"; sc->txchainmask = IWN_ANT_A; sc->rxchainmask = IWN_ANT_AB; + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_TX_IQ_PERIODIC | + IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_6000: sc->sc_hal = &iwn5000_hal; @@ -744,6 +759,8 @@ iwn_hal_attach(struct iwn_softc *sc) sc->rxchainmask = IWN_ANT_ABC; break; } + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_6050: sc->sc_hal = &iwn5000_hal; @@ -751,6 +768,8 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn6050fw"; sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_AB; + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_DC | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; case IWN_HW_REV_TYPE_6005: sc->sc_hal = &iwn5000_hal; @@ -758,6 +777,8 @@ iwn_hal_attach(struct iwn_softc *sc) sc->fwname = "iwn6005fw"; sc->txchainmask = IWN_ANT_AB; sc->rxchainmask = IWN_ANT_AB; + sc->calib_init = IWN_CALIB_XTAL | IWN_CALIB_LO | + IWN_CALIB_TX_IQ | IWN_CALIB_BASE_BAND; break; default: device_printf(sc->sc_dev, "adapter type %d not supported\n", @@ -842,6 +863,8 @@ iwn_cleanup(device_t dev) ieee80211_ifdetach(ic); } + iwn5000_free_calib_results(sc); + /* Free DMA resources. */ iwn_free_rx_ring(sc, &sc->rxq); if (sc->sc_hal != NULL) @@ -1697,12 +1720,6 @@ iwn5000_read_eeprom(struct iwn_softc *sc) sc->temp_off = temp - (volt / -5); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "temp=%d volt=%d offset=%dK\n", temp, volt, sc->temp_off); - } else { - /* Read crystal calibration. */ - iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, - &sc->eeprom_crystal, sizeof (uint32_t)); - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "crystal calibration 0x%08x\n", - le32toh(sc->eeprom_crystal)); } } @@ -2195,64 +2212,6 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc, } #endif -/* - * Process a CALIBRATION_RESULT notification sent by the initialization - * firmware on response to a CMD_CALIB_CONFIG command (5000 only.) - */ -static void -iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, - struct iwn_rx_data *data) -{ - struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); - int len, idx = -1; - - /* Runtime firmware should not send such a notification. */ - if (sc->sc_flags & IWN_FLAG_CALIB_DONE) - return; - - bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); - len = (le32toh(desc->len) & 0x3fff) - 4; - - switch (calib->code) { - case IWN5000_PHY_CALIB_DC: - if (sc->hw_type == IWN_HW_REV_TYPE_5150 || - sc->hw_type == IWN_HW_REV_TYPE_6050) - idx = 0; - break; - case IWN5000_PHY_CALIB_LO: - idx = 1; - break; - case IWN5000_PHY_CALIB_TX_IQ: - idx = 2; - break; - case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: - if (sc->hw_type < IWN_HW_REV_TYPE_6000 && - sc->hw_type != IWN_HW_REV_TYPE_5150) - idx = 3; - break; - case IWN5000_PHY_CALIB_BASE_BAND: - idx = 4; - break; - } - if (idx == -1) /* Ignore other results. */ - return; - - /* Save calibration result. */ - if (sc->calibcmd[idx].buf != NULL) - free(sc->calibcmd[idx].buf, M_DEVBUF); - sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT); - if (sc->calibcmd[idx].buf == NULL) { - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "not enough memory for calibration result %d\n", - calib->code); - return; - } - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "saving calibration result code=%d len=%d\n", calib->code, len); - sc->calibcmd[idx].len = len; - memcpy(sc->calibcmd[idx].buf, calib, len); -} - /* * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification. * The latter is sent by the firmware after each received beacon. @@ -2608,7 +2567,7 @@ iwn_notif_intr(struct iwn_softc *sc) break; } case IWN5000_CALIBRATION_RESULT: - iwn5000_rx_calib_results(sc, desc, data); + iwn5000_rx_calib_result(sc, desc, data); break; case IWN5000_CALIBRATION_DONE: @@ -5239,22 +5198,140 @@ iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn) #endif /* - * Query calibration tables from the initialization firmware. We do this - * only once at first boot. Called from a process context. + * Send calibration results to the runtime firmware. These results were + * obtained on first boot from the initialization firmware, or by reading + * the EEPROM for crystal calibration. */ static int -iwn5000_query_calibration(struct iwn_softc *sc) +iwn5000_send_calib_results(struct iwn_softc *sc) { + struct iwn_calib_info *calib_result; + int idx, error; + + for (idx = 0; idx < IWN_CALIB_NUM; idx++) { + calib_result = &sc->calib_results[idx]; + + /* No support for this type of calibration. */ + if ((sc->calib_init & (1 << idx)) == 0) + continue; + + /* No calibration result available. */ + if (calib_result->buf == NULL) + continue; + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "%s: send calibration result idx=%d, len=%d\n", + __func__, idx, calib_result->len); + + error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, calib_result->buf, + calib_result->len, 0); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not send calibration result " + "idx=%d, error=%d\n", + __func__, idx, error); + return error; + } + } + return 0; +} + +/* + * Save calibration result at the given index. The index determines + * in which order the results are sent to the runtime firmware. + */ +static int +iwn5000_save_calib_result(struct iwn_softc *sc, struct iwn_phy_calib *calib, + int len, int idx) +{ + struct iwn_calib_info *calib_result = &sc->calib_results[idx]; + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, + "%s: saving calibration result code=%d, idx=%d, len=%d\n", + __func__, calib->code, idx, len); + + if (calib_result->buf != NULL) + free(calib_result->buf, M_DEVBUF); + + calib_result->buf = malloc(len, M_DEVBUF, M_NOWAIT); + if (calib_result->buf == NULL) { + device_printf(sc->sc_dev, + "%s: not enough memory for calibration result " + "code=%d, len=%d\n", __func__, calib->code, len); + return ENOMEM; + } + + calib_result->len = len; + memcpy(calib_result->buf, calib, len); + return 0; +} + +static void +iwn5000_free_calib_results(struct iwn_softc *sc) +{ + struct iwn_calib_info *calib_result; + int idx; + + for (idx = 0; idx < IWN_CALIB_NUM; idx++) { + calib_result = &sc->calib_results[idx]; + + if (calib_result->buf != NULL) + free(calib_result->buf, M_DEVBUF); + + calib_result->buf = NULL; + calib_result->len = 0; + } +} + +/* + * Obtain the crystal calibration result from the EEPROM. + */ +static int +iwn5000_chrystal_calib(struct iwn_softc *sc) +{ + struct iwn5000_phy_calib_crystal cmd; + uint32_t base, crystal; + uint16_t val; + + /* Read crystal calibration. */ + iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); + base = le16toh(val); + iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL, &crystal, + sizeof(uint32_t)); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: crystal calibration=0x%08x\n", + __func__, le32toh(crystal)); + + memset(&cmd, 0, sizeof cmd); + cmd.code = IWN5000_PHY_CALIB_CRYSTAL; + cmd.ngroups = 1; + cmd.isvalid = 1; + cmd.cap_pin[0] = le32toh(crystal) & 0xff; + cmd.cap_pin[1] = (le32toh(crystal) >> 16) & 0xff; + + return iwn5000_save_calib_result(sc, (struct iwn_phy_calib *)&cmd, + sizeof cmd, IWN_CALIB_IDX_XTAL); +} + +/* + * Query calibration results from the initialization firmware. We do this + * only once at first boot. + */ +static int +iwn5000_send_calib_query(struct iwn_softc *sc) +{ +#define CALIB_INIT_CFG 0xffffffff; struct iwn5000_calib_config cmd; int error; memset(&cmd, 0, sizeof cmd); - cmd.ucode.once.enable = 0xffffffff; - cmd.ucode.once.start = 0xffffffff; - cmd.ucode.once.send = 0xffffffff; - cmd.ucode.flags = 0xffffffff; - DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n", + cmd.ucode.once.enable = CALIB_INIT_CFG; + cmd.ucode.once.start = CALIB_INIT_CFG; + cmd.ucode.once.send = CALIB_INIT_CFG; + cmd.ucode.flags = CALIB_INIT_CFG; + + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: query calibration results\n", __func__); + error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); if (error != 0) return error; @@ -5262,34 +5339,56 @@ iwn5000_query_calibration(struct iwn_softc *sc) /* Wait at most two seconds for calibration to complete. */ if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) error = msleep(sc, &sc->sc_mtx, PCATCH, "iwninit", 2 * hz); + return error; +#undef CALIB_INIT_CFG } /* - * Send calibration results to the runtime firmware. These results were - * obtained on first boot from the initialization firmware. + * Process a CALIBRATION_RESULT notification sent by the initialization + * firmware on response to a CMD_CALIB_CONFIG command. */ static int -iwn5000_send_calibration(struct iwn_softc *sc) +iwn5000_rx_calib_result(struct iwn_softc *sc, struct iwn_rx_desc *desc, + struct iwn_rx_data *data) { - int idx, error; +#define FRAME_SIZE_MASK 0x3fff + struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1); + int len, idx; - for (idx = 0; idx < 5; idx++) { - if (sc->calibcmd[idx].buf == NULL) - continue; /* No results available. */ + bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); + len = (le32toh(desc->len) & FRAME_SIZE_MASK); + + /* Remove length field itself. */ + len -= 4; + + /* + * Determine the order in which the results will be send to the + * runtime firmware. + */ + switch (calib->code) { + case IWN5000_PHY_CALIB_DC: + idx = IWN_CALIB_IDX_DC; + break; + case IWN5000_PHY_CALIB_LO: + idx = IWN_CALIB_IDX_LO; + break; + case IWN5000_PHY_CALIB_TX_IQ: + idx = IWN_CALIB_IDX_TX_IQ; + break; + case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: + idx = IWN_CALIB_IDX_TX_IQ_PERIODIC; + break; + case IWN5000_PHY_CALIB_BASE_BAND: + idx = IWN_CALIB_IDX_BASE_BAND; + break; + default: DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "send calibration result idx=%d len=%d\n", - idx, sc->calibcmd[idx].len); - error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf, - sc->calibcmd[idx].len, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: could not send calibration result, error %d\n", - __func__, error); - return error; - } + "%s: unknown calibration code=%d\n", __func__, calib->code); + return EINVAL; } - return 0; + return iwn5000_save_calib_result(sc, calib, len, idx); +#undef FRAME_SIZE_MASK } static int @@ -5435,36 +5534,40 @@ iwn5000_post_alive(struct iwn_softc *sc) __func__, error); return error; } - if (sc->hw_type != IWN_HW_REV_TYPE_5150) { - struct iwn5000_phy_calib_crystal cmd; - /* Perform crystal calibration. */ - memset(&cmd, 0, sizeof cmd); - cmd.code = IWN5000_PHY_CALIB_CRYSTAL; - cmd.ngroups = 1; - cmd.isvalid = 1; - cmd.cap_pin[0] = le32toh(sc->eeprom_crystal) & 0xff; - cmd.cap_pin[1] = (le32toh(sc->eeprom_crystal) >> 16) & 0xff; - DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "sending crystal calibration %d, %d\n", - cmd.cap_pin[0], cmd.cap_pin[1]); - error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: crystal calibration failed, error %d\n", - __func__, error); - return error; - } - } if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) { - /* Query calibration from the initialization firmware. */ - error = iwn5000_query_calibration(sc); + /* + * Start calibration by setting and sending the chrystal + * calibration first, this must be done before we are able + * to query the other calibration results. + */ + error = iwn5000_chrystal_calib(sc); if (error != 0) { device_printf(sc->sc_dev, - "%s: could not query calibration, error %d\n", + "%s: could not set chrystal calibration, " + "error=%d\n", __func__, error); + return error; + } + error = iwn5000_send_calib_results(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not send chrystal calibration, " + "error=%d\n", __func__, error); + return error; + } + + /* + * Query other calibration results from the initialization + * firmware. + */ + error = iwn5000_send_calib_query(sc); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not query calibration, error=%d\n", __func__, error); return error; } + /* * We have the calibration results now, reboot with the * runtime firmware (call ourselves recursively!) @@ -5472,8 +5575,11 @@ iwn5000_post_alive(struct iwn_softc *sc) iwn_hw_stop(sc); error = iwn_hw_init(sc); } else { - /* Send calibration results to runtime firmware. */ - error = iwn5000_send_calibration(sc); + /* + * Send calibration results obtained from the initialization + * firmware to the runtime firmware. + */ + error = iwn5000_send_calib_results(sc); } return error; } diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h index 90a8d953f9c..f8b45b6218c 100644 --- a/sys/dev/iwn/if_iwnvar.h +++ b/sys/dev/iwn/if_iwnvar.h @@ -263,9 +263,23 @@ struct iwn_softc { int calib_cnt; struct iwn_calib_state calib; + u_int calib_init; +#define IWN_CALIB_XTAL (1 << IWN_CALIB_IDX_XTAL) +#define IWN_CALIB_DC (1 << IWN_CALIB_IDX_DC) +#define IWN_CALIB_LO (1 << IWN_CALIB_IDX_LO) +#define IWN_CALIB_TX_IQ (1 << IWN_CALIB_IDX_TX_IQ) +#define IWN_CALIB_TX_IQ_PERIODIC (1 << IWN_CALIB_IDX_TX_IQ_PERIODIC) +#define IWN_CALIB_BASE_BAND (1 << IWN_CALIB_IDX_BASE_BAND) +#define IWN_CALIB_NUM 6 + struct iwn_calib_info calib_results[IWN_CALIB_NUM]; +#define IWN_CALIB_IDX_XTAL 0 +#define IWN_CALIB_IDX_DC 1 +#define IWN_CALIB_IDX_LO 2 +#define IWN_CALIB_IDX_TX_IQ 3 +#define IWN_CALIB_IDX_TX_IQ_PERIODIC 4 +#define IWN_CALIB_IDX_BASE_BAND 5 struct iwn_fw_info fw; - struct iwn_calib_info calibcmd[5]; uint32_t errptr; struct iwn_rx_stat last_rx_stat; @@ -284,7 +298,6 @@ struct iwn_softc { uint16_t rfcfg; uint8_t calib_ver; char eeprom_domain[4]; - uint32_t eeprom_crystal; int16_t eeprom_voltage; int8_t maxpwr2GHz; int8_t maxpwr5GHz; diff --git a/sys/dev/ixgb/if_ixgb.c b/sys/dev/ixgb/if_ixgb.c index 990f791dfbd..e5cddb31b37 100644 --- a/sys/dev/ixgb/if_ixgb.c +++ b/sys/dev/ixgb/if_ixgb.c @@ -108,7 +108,7 @@ static int ixgb_allocate_pci_resources(struct adapter *); static void ixgb_free_pci_resources(struct adapter *); static void ixgb_local_timer(void *); static int ixgb_hardware_init(struct adapter *); -static void ixgb_setup_interface(device_t, struct adapter *); +static int ixgb_setup_interface(device_t, struct adapter *); static int ixgb_setup_transmit_structures(struct adapter *); static void ixgb_initialize_transmit_unit(struct adapter *); static int ixgb_setup_receive_structures(struct adapter *); @@ -324,6 +324,15 @@ ixgb_attach(device_t dev) } adapter->rx_desc_base = (struct ixgb_rx_desc *) adapter->rxdma.dma_vaddr; + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(u_int8_t) * IXGB_ETH_LENGTH_OF_ADDRESS * + MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_hw_init; + } + /* Initialize the hardware */ if (ixgb_hardware_init(adapter)) { device_printf(dev, "Unable to initialize the hardware\n"); @@ -331,7 +340,8 @@ ixgb_attach(device_t dev) goto err_hw_init; } /* Setup OS specific network interface */ - ixgb_setup_interface(dev, adapter); + if (ixgb_setup_interface(dev, adapter) != 0) + goto err_hw_init; /* Initialize statistics */ ixgb_clear_hw_cntrs(&adapter->hw); @@ -346,8 +356,11 @@ err_rx_desc: ixgb_dma_free(adapter, &adapter->txdma); err_tx_desc: err_pci: + if (adapter->ifp != NULL) + if_free(adapter->ifp); ixgb_free_pci_resources(adapter); sysctl_ctx_free(&adapter->sysctl_ctx); + free(adapter->mta, M_DEVBUF); return (error); } @@ -409,6 +422,7 @@ ixgb_detach(device_t dev) adapter->next->prev = adapter->prev; if (adapter->prev != NULL) adapter->prev->next = adapter->next; + free(adapter->mta, M_DEVBUF); IXGB_LOCK_DESTROY(adapter); return (0); @@ -1066,13 +1080,17 @@ static void ixgb_set_multi(struct adapter * adapter) { u_int32_t reg_rctl = 0; - u_int8_t mta[MAX_NUM_MULTICAST_ADDRESSES * IXGB_ETH_LENGTH_OF_ADDRESS]; + u_int8_t *mta; struct ifmultiaddr *ifma; int mcnt = 0; struct ifnet *ifp = adapter->ifp; IOCTL_DEBUGOUT("ixgb_set_multi: begin"); + mta = adapter->mta; + bzero(mta, sizeof(u_int8_t) * IXGB_ETH_LENGTH_OF_ADDRESS * + MAX_NUM_MULTICAST_ADDRESSES); + if_maddr_rlock(ifp); #if __FreeBSD_version < 500000 LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { @@ -1319,15 +1337,17 @@ ixgb_hardware_init(struct adapter * adapter) * Setup networking device structure and register an interface. * **********************************************************************/ -static void +static int ixgb_setup_interface(device_t dev, struct adapter * adapter) { struct ifnet *ifp; INIT_DEBUGOUT("ixgb_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - panic("%s: can not if_alloc()\n", device_get_nameunit(dev)); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } #if __FreeBSD_version >= 502000 if_initname(ifp, device_get_name(dev), device_get_unit(dev)); #else @@ -1379,7 +1399,7 @@ ixgb_setup_interface(device_t dev, struct adapter * adapter) ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - return; + return (0); } /******************************************************************** diff --git a/sys/dev/ixgb/if_ixgb.h b/sys/dev/ixgb/if_ixgb.h index 9e5355a25dd..4e88db79a86 100644 --- a/sys/dev/ixgb/if_ixgb.h +++ b/sys/dev/ixgb/if_ixgb.h @@ -344,6 +344,8 @@ struct adapter { struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; + /* Multicast array memory */ + u_int8_t *mta; /* Misc stats maintained by the driver */ unsigned long dropped_pkts; unsigned long mbuf_alloc_failed; diff --git a/sys/dev/ixgbe/ixgbe.c b/sys/dev/ixgbe/ixgbe.c index c514dc34f13..37b98df20ed 100644 --- a/sys/dev/ixgbe/ixgbe.c +++ b/sys/dev/ixgbe/ixgbe.c @@ -119,7 +119,7 @@ static int ixgbe_allocate_queues(struct adapter *); static int ixgbe_setup_msix(struct adapter *); static void ixgbe_free_pci_resources(struct adapter *); static void ixgbe_local_timer(void *); -static void ixgbe_setup_interface(device_t, struct adapter *); +static int ixgbe_setup_interface(device_t, struct adapter *); static void ixgbe_config_link(struct adapter *); static int ixgbe_allocate_transmit_buffers(struct tx_ring *); @@ -524,6 +524,15 @@ ixgbe_attach(device_t dev) goto err_out; } + /* Allocate multicast array memory. */ + adapter->mta = malloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * + MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); + if (adapter->mta == NULL) { + device_printf(dev, "Can not allocate multicast setup array\n"); + error = ENOMEM; + goto err_late; + } + /* Initialize the shared code */ error = ixgbe_init_shared_code(hw); if (error == IXGBE_ERR_SFP_NOT_PRESENT) { @@ -586,7 +595,8 @@ ixgbe_attach(device_t dev) goto err_late; /* Setup OS specific network interface */ - ixgbe_setup_interface(dev, adapter); + if (ixgbe_setup_interface(dev, adapter) != 0) + goto err_late; /* Sysctl for limiting the amount of work done in the taskqueue */ ixgbe_add_rx_process_limit(adapter, "rx_processing_limit", @@ -632,7 +642,10 @@ err_late: ixgbe_free_transmit_structures(adapter); ixgbe_free_receive_structures(adapter); err_out: + if (adapter->ifp != NULL) + if_free(adapter->ifp); ixgbe_free_pci_resources(adapter); + free(adapter->mta, M_DEVBUF); return (error); } @@ -703,6 +716,7 @@ ixgbe_detach(device_t dev) ixgbe_free_transmit_structures(adapter); ixgbe_free_receive_structures(adapter); + free(adapter->mta, M_DEVBUF); IXGBE_CORE_LOCK_DESTROY(adapter); return (0); @@ -1805,7 +1819,7 @@ static void ixgbe_set_multi(struct adapter *adapter) { u32 fctrl; - u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; + u8 *mta; u8 *update_ptr; struct ifmultiaddr *ifma; int mcnt = 0; @@ -1813,6 +1827,10 @@ ixgbe_set_multi(struct adapter *adapter) IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); + mta = adapter->mta; + bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * + MAX_NUM_MULTICAST_ADDRESSES); + fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); if (ifp->if_flags & IFF_PROMISC) @@ -2357,7 +2375,7 @@ mem: * Setup networking device structure and register an interface. * **********************************************************************/ -static void +static int ixgbe_setup_interface(device_t dev, struct adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; @@ -2366,8 +2384,10 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter) INIT_DEBUGOUT("ixgbe_setup_interface: begin"); ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) - panic("%s: can not if_alloc()\n", device_get_nameunit(dev)); + if (ifp == NULL) { + device_printf(dev, "can not allocate ifnet structure\n"); + return (-1); + } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_baudrate = 1000000000; @@ -2415,7 +2435,7 @@ ixgbe_setup_interface(device_t dev, struct adapter *adapter) ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - return; + return (0); } static void diff --git a/sys/dev/ixgbe/ixgbe.h b/sys/dev/ixgbe/ixgbe.h index 6aa32e4a391..abfdfa10e6d 100644 --- a/sys/dev/ixgbe/ixgbe.h +++ b/sys/dev/ixgbe/ixgbe.h @@ -421,6 +421,8 @@ struct adapter { u64 que_mask; u32 rx_process_limit; + /* Multicast array memory */ + u8 *mta; /* Misc stats maintained by the driver */ unsigned long dropped_pkts; unsigned long mbuf_defrag_failed; diff --git a/sys/dev/jme/if_jme.c b/sys/dev/jme/if_jme.c index 4bfffa33445..89c908fca48 100644 --- a/sys/dev/jme/if_jme.c +++ b/sys/dev/jme/if_jme.c @@ -224,13 +224,8 @@ jme_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); /* For FPGA version, PHY address 0 should be ignored. */ - if ((sc->jme_flags & JME_FLAG_FPGA) != 0) { - if (phy == 0) - return (0); - } else { - if (sc->jme_phyaddr != phy) - return (0); - } + if ((sc->jme_flags & JME_FLAG_FPGA) != 0 && phy == 0) + return (0); CSR_WRITE_4(sc, JME_SMI, SMI_OP_READ | SMI_OP_EXECUTE | SMI_PHY_ADDR(phy) | SMI_REG_ADDR(reg)); @@ -260,13 +255,8 @@ jme_miibus_writereg(device_t dev, int phy, int reg, int val) sc = device_get_softc(dev); /* For FPGA version, PHY address 0 should be ignored. */ - if ((sc->jme_flags & JME_FLAG_FPGA) != 0) { - if (phy == 0) - return (0); - } else { - if (sc->jme_phyaddr != phy) - return (0); - } + if ((sc->jme_flags & JME_FLAG_FPGA) != 0 && phy == 0) + return (0); CSR_WRITE_4(sc, JME_SMI, SMI_OP_WRITE | SMI_OP_EXECUTE | ((val << SMI_DATA_SHIFT) & SMI_DATA_MASK) | @@ -743,9 +733,11 @@ jme_attach(device_t dev) ifp->if_capenable = ifp->if_capabilities; /* Set up MII bus. */ - if ((error = mii_phy_probe(dev, &sc->jme_miibus, jme_mediachange, - jme_mediastatus)) != 0) { - device_printf(dev, "no PHY found!\n"); + error = mii_attach(dev, &sc->jme_miibus, ifp, jme_mediachange, + jme_mediastatus, BMSR_DEFCAPMASK, sc->jme_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1657,11 +1649,12 @@ jme_encap(struct jme_softc *sc, struct mbuf **m_head) *m_head = NULL; return (ENOBUFS); } - tcp = (struct tcphdr *)(mtod(m, char *) + poff); /* * Reset IP checksum and recompute TCP pseudo * checksum that NDIS specification requires. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); + tcp = (struct tcphdr *)(mtod(m, char *) + poff); ip->ip_sum = 0; if (poff + (tcp->th_off << 2) == m->m_pkthdr.len) { tcp->th_sum = in_pseudo(ip->ip_src.s_addr, diff --git a/sys/dev/kbd/kbd.c b/sys/dev/kbd/kbd.c index 0813676d01d..21818cb2d04 100644 --- a/sys/dev/kbd/kbd.c +++ b/sys/dev/kbd/kbd.c @@ -224,7 +224,7 @@ kbd_register(keyboard_t *kbd) strcpy(ki.kb_name, kbd->kb_name); ki.kb_unit = kbd->kb_unit; - kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); + (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); } return (index); @@ -241,7 +241,7 @@ kbd_register(keyboard_t *kbd) strcpy(ki.kb_name, kbd->kb_name); ki.kb_unit = kbd->kb_unit; - kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); + (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); } return (index); @@ -1148,7 +1148,7 @@ genkbd_diag(keyboard_t *kbd, int level) (s) |= l ## DOWN; \ (s) ^= l ## ED; \ i = (s) & LOCK_MASK; \ - kbdd_ioctl((k), KDSETLED, (caddr_t)&i); \ + (void)kbdd_ioctl((k), KDSETLED, (caddr_t)&i); \ } static u_int @@ -1308,7 +1308,7 @@ genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, #else state &= ~CLKED; i = state & LOCK_MASK; - kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); + (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); #endif break; case SLK: @@ -1344,7 +1344,7 @@ genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, #else state |= CLKED; i = state & LOCK_MASK; - kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); + (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); #endif break; case SLK: diff --git a/sys/dev/kbdmux/kbdmux.c b/sys/dev/kbdmux/kbdmux.c index 990c8c36412..64d5c244090 100644 --- a/sys/dev/kbdmux/kbdmux.c +++ b/sys/dev/kbdmux/kbdmux.c @@ -1115,7 +1115,7 @@ kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) /* KDSETLED on all slave keyboards */ SLIST_FOREACH(k, &state->ks_kbds, next) - kbdd_ioctl(k->kbd, KDSETLED, arg); + (void)kbdd_ioctl(k->kbd, KDSETLED, arg); KBDMUX_UNLOCK(state); break; @@ -1146,7 +1146,7 @@ kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) /* KDSKBSTATE on all slave keyboards */ SLIST_FOREACH(k, &state->ks_kbds, next) - kbdd_ioctl(k->kbd, KDSKBSTATE, arg); + (void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg); KBDMUX_UNLOCK(state); @@ -1192,7 +1192,7 @@ kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) /* perform command on all slave keyboards */ SLIST_FOREACH(k, &state->ks_kbds, next) - kbdd_ioctl(k->kbd, cmd, arg); + (void)kbdd_ioctl(k->kbd, cmd, arg); KBDMUX_UNLOCK(state); break; @@ -1205,7 +1205,7 @@ kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) /* perform command on all slave keyboards */ SLIST_FOREACH(k, &state->ks_kbds, next) - kbdd_ioctl(k->kbd, cmd, arg); + (void)kbdd_ioctl(k->kbd, cmd, arg); KBDMUX_UNLOCK(state); /* FALLTHROUGH */ diff --git a/sys/dev/led/led.c b/sys/dev/led/led.c index fdd0fa2d006..521006c9dd8 100644 --- a/sys/dev/led/led.c +++ b/sys/dev/led/led.c @@ -220,15 +220,11 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) free(s2, M_DEVBUF); return (EINVAL); } - sbuf_finish(sb); + error = sbuf_finish(sb); free(s2, M_DEVBUF); - if (sbuf_overflowed(sb)) { + if (error != 0 || sbuf_len(sb) == 0) { sbuf_delete(sb); - return (ENOMEM); - } - if (sbuf_len(sb) == 0) { - sbuf_delete(sb); - return (0); + return (error); } return (led_state(dev, sb, 0)); diff --git a/sys/dev/lge/if_lge.c b/sys/dev/lge/if_lge.c index b870bf0c8ba..ab488dfb908 100644 --- a/sys/dev/lge/if_lge.c +++ b/sys/dev/lge/if_lge.c @@ -557,10 +557,10 @@ lge_attach(dev) /* * Do MII setup. */ - if (mii_phy_probe(dev, &sc->lge_miibus, - lge_ifmedia_upd, lge_ifmedia_sts)) { - device_printf(dev, "MII without any PHY!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->lge_miibus, ifp, lge_ifmedia_upd, + lge_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/malo/if_malo_pci.c b/sys/dev/malo/if_malo_pci.c index fbad5ab4c17..65aac7ca63c 100644 --- a/sys/dev/malo/if_malo_pci.c +++ b/sys/dev/malo/if_malo_pci.c @@ -371,4 +371,4 @@ static devclass_t malo_devclass; DRIVER_MODULE(malo, pci, malo_pci_driver, malo_devclass, 0, 0); MODULE_VERSION(malo, 1); MODULE_DEPEND(malo, wlan, 1, 1, 1); /* 802.11 media layer */ -MODULE_DEPEND(malo, malofw_fw, 1, 1, 1); +MODULE_DEPEND(malo, firmware, 1, 1, 1); diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index 47aa751500c..6c3484eb496 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -909,18 +909,26 @@ mdcreate_vnode(struct md_s *sc, struct md_ioctl *mdio, struct thread *td) { struct vattr vattr; struct nameidata nd; + char *fname; int error, flags, vfslocked; - error = copyinstr(mdio->md_file, sc->file, sizeof(sc->file), NULL); - if (error != 0) - return (error); - flags = FREAD|FWRITE; /* - * If the user specified that this is a read only device, unset the - * FWRITE mask before trying to open the backing store. + * Kernel-originated requests must have the filename appended + * to the mdio structure to protect against malicious software. */ - if ((mdio->md_options & MD_READONLY) != 0) - flags &= ~FWRITE; + fname = mdio->md_file; + if ((void *)fname != (void *)(mdio + 1)) { + error = copyinstr(fname, sc->file, sizeof(sc->file), NULL); + if (error != 0) + return (error); + } else + strlcpy(sc->file, fname, sizeof(sc->file)); + + /* + * If the user specified that this is a read only device, don't + * set the FWRITE mask before trying to open the backing store. + */ + flags = FREAD | ((mdio->md_options & MD_READONLY) ? 0 : FWRITE); NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, sc->file, td); error = vn_open(&nd, &flags, 0, NULL); if (error != 0) diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h index 17ab4b3b5cf..e08a16dd471 100644 --- a/sys/dev/mfi/mfireg.h +++ b/sys/dev/mfi/mfireg.h @@ -975,7 +975,9 @@ enum mfi_pd_state { MFI_PD_STATE_OFFLINE = 0x10, MFI_PD_STATE_FAILED = 0x11, MFI_PD_STATE_REBUILD = 0x14, - MFI_PD_STATE_ONLINE = 0x18 + MFI_PD_STATE_ONLINE = 0x18, + MFI_PD_STATE_COPYBACK = 0x20, + MFI_PD_STATE_SYSTEM = 0x40 }; union mfi_ld_ref { diff --git a/sys/dev/mge/if_mge.c b/sys/dev/mge/if_mge.c index c710521c6ba..824f8a21a61 100644 --- a/sys/dev/mge/if_mge.c +++ b/sys/dev/mge/if_mge.c @@ -629,7 +629,7 @@ mge_attach(device_t dev) struct mii_softc *miisc; struct ifnet *ifp; uint8_t hwaddr[ETHER_ADDR_LEN]; - int i, error ; + int i, error, phy; sc = device_get_softc(dev); sc->dev = dev; @@ -642,7 +642,7 @@ mge_attach(device_t dev) mge_ver_params(sc); /* Get phy address from fdt */ - if (fdt_get_phyaddr(sc->node, &sc->phyaddr) != 0) + if (fdt_get_phyaddr(sc->node, &phy) != 0) return (ENXIO); /* Initialize mutexes */ @@ -706,10 +706,11 @@ mge_attach(device_t dev) ether_ifattach(ifp, hwaddr); callout_init(&sc->wd_callout, 0); - /* Probe PHY(s) */ - error = mii_phy_probe(dev, &sc->miibus, mge_ifmedia_upd, mge_ifmedia_sts); + /* Attach PHY(s) */ + error = mii_attach(dev, &sc->miibus, ifp, mge_ifmedia_upd, + mge_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); if (error) { - device_printf(dev, "MII failed to find PHY\n"); + device_printf(dev, "attaching PHYs failed\n"); mge_detach(dev); return (error); } @@ -1293,9 +1294,6 @@ mge_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (sc->phyaddr != phy) - return (0); - MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff & (MGE_SMI_READ | (reg << 21) | (phy << 16))); @@ -1317,9 +1315,6 @@ mge_miibus_writereg(device_t dev, int phy, int reg, int value) sc = device_get_softc(dev); - if (sc->phyaddr != phy) - return (0); - MGE_WRITE(sc_mge0, MGE_REG_SMI, 0x1fffffff & (MGE_SMI_WRITE | (reg << 21) | (phy << 16) | (value & 0xffff))); diff --git a/sys/dev/mge/if_mgevar.h b/sys/dev/mge/if_mgevar.h index e21b590f43e..5f96fa76090 100644 --- a/sys/dev/mge/if_mgevar.h +++ b/sys/dev/mge/if_mgevar.h @@ -103,8 +103,6 @@ struct mge_softc { uint32_t mge_tx_tok_cnt; uint16_t mge_mtu; int mge_ver; - - int phyaddr; }; diff --git a/sys/dev/mii/acphy.c b/sys/dev/mii/acphy.c index 4f3e9f169c9..7013dbfaa6e 100644 --- a/sys/dev/mii/acphy.c +++ b/sys/dev/mii/acphy.c @@ -14,13 +14,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -46,11 +39,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -141,20 +129,18 @@ acphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = acphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - acphy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -179,22 +165,8 @@ acphy_attach(device_t dev) static int acphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; - /* - * If we're not selected, then do nothing, just isolate and power - * down, if changing media. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - if (cmd == MII_MEDIACHG) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO | BMCR_PDOWN); - } - - return (0); - } - switch (cmd) { case MII_POLLSTAT: break; @@ -274,6 +246,8 @@ acphy_status(struct mii_softc *sc) if (diag & AC_DIAG_DUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/amphy.c b/sys/dev/mii/amphy.c index 3c06561fd9e..010fe9066a8 100644 --- a/sys/dev/mii/amphy.c +++ b/sys/dev/mii/amphy.c @@ -106,16 +106,15 @@ amphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = amphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) #if 0 @@ -125,8 +124,7 @@ amphy_attach(device_t dev) mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -138,29 +136,12 @@ amphy_attach(device_t dev) static int amphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -171,11 +152,6 @@ amphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -231,13 +207,13 @@ amphy_status(struct mii_softc *sc) if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T|IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else mii->mii_media_active |= IFM_NONE; return; @@ -250,11 +226,11 @@ amphy_status(struct mii_softc *sc) if (par & DSCSR_100FDX) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (par & DSCSR_100HDX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (par & DSCSR_10FDX) mii->mii_media_active |= IFM_10_T|IFM_HDX; else if (par & DSCSR_10HDX) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/atphy.c b/sys/dev/mii/atphy.c index f370c80ed95..41cd72cc4af 100644 --- a/sys/dev/mii/atphy.c +++ b/sys/dev/mii/atphy.c @@ -110,16 +110,14 @@ atphy_attach(device_t dev) sc = &asc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = atphy_service; sc->mii_pdata = mii; - sc->mii_anegticks = MII_ANEGTICKS_GIGE; - - mii->mii_instance++; asc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); asc->mii_model = MII_MODEL(ma->mii_id2); @@ -138,7 +136,7 @@ atphy_attach(device_t dev) printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); - return(0); + return (0); } static int @@ -149,24 +147,9 @@ atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - bmcr = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -224,12 +207,6 @@ done: break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ diff --git a/sys/dev/mii/axphy.c b/sys/dev/mii/axphy.c index 21ac6f0c3e4..3349d3f5f0d 100644 --- a/sys/dev/mii/axphy.c +++ b/sys/dev/mii/axphy.c @@ -45,8 +45,6 @@ __FBSDID("$FreeBSD$"); #include #include "miidevs.h" -#include - #include "miibus_if.h" static int axphy_probe(device_t dev); @@ -96,15 +94,16 @@ axphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = axphy_service; sc->mii_pdata = mii; + sc->mii_flags |= MIIF_NOISOLATE; - mii->mii_instance++; mii_phy_reset(sc); @@ -122,22 +121,12 @@ axphy_attach(device_t dev) static int axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -148,8 +137,6 @@ axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -201,6 +188,8 @@ axphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_10_T; if (scr & SCR_FDX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; #endif } else mii->mii_media_active = ife->ifm_media; diff --git a/sys/dev/mii/bmtphy.c b/sys/dev/mii/bmtphy.c index 221725761d8..63d1df1fb26 100644 --- a/sys/dev/mii/bmtphy.c +++ b/sys/dev/mii/bmtphy.c @@ -14,13 +14,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -46,11 +39,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -156,20 +144,18 @@ bmtphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = bmtphy_service; sc->mii_pdata = mii; mii_phy_reset(sc); - mii->mii_instance++; - - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -182,31 +168,12 @@ bmtphy_attach(device_t dev) static int bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife; - int reg; - - ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -217,11 +184,6 @@ bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -282,6 +244,8 @@ bmtphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_10_T; if (aux_csr & AUX_CSR_FDX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index a733597fe76..9f915df1b8f 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -140,7 +140,7 @@ static const struct mii_phydesc brgphys[] = { MII_PHY_DESC(xxBROADCOM_ALT1, BCM5784), MII_PHY_DESC(xxBROADCOM_ALT1, BCM5709C), MII_PHY_DESC(xxBROADCOM_ALT1, BCM5761), - MII_PHY_DESC(xxBROADCOM_ALT1, BCM5709S), + MII_PHY_DESC(xxBROADCOM_ALT1, BCM5709S), MII_PHY_DESC(BROADCOM2, BCM5906), MII_PHY_END }; @@ -187,17 +187,22 @@ brgphy_attach(device_t dev) sc = &bsc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); /* Initialize mii_softc structure */ - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = brgphy_service; sc->mii_pdata = mii; - sc->mii_anegticks = MII_ANEGTICKS_GIGE; + + /* + * At least some variants wedge when isolating, at least some also + * don't support loopback. + */ sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; - mii->mii_instance++; + sc->mii_anegticks = MII_ANEGTICKS_GIGE; /* Initialize brgphy_softc structure */ bsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); @@ -242,11 +247,12 @@ brgphy_attach(device_t dev) bsc->serdes_flags |= BRGPHY_5708S; sc->mii_flags |= MIIF_HAVEFIBER; break; - case MII_MODEL_xxBROADCOM_ALT1_BCM5709S: - bsc->serdes_flags |= BRGPHY_5709S; - sc->mii_flags |= MIIF_HAVEFIBER; - break; - } break; + case MII_MODEL_xxBROADCOM_ALT1_BCM5709S: + bsc->serdes_flags |= BRGPHY_5709S; + sc->mii_flags |= MIIF_HAVEFIBER; + break; + } + break; default: device_printf(dev, "Unrecognized OUI for PHY!\n"); } @@ -282,9 +288,6 @@ brgphy_attach(device_t dev) #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) - /* Create an instance of Ethernet media. */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO); - /* Add the supported media types */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), @@ -344,26 +347,12 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int error = 0; int val; switch (cmd) { case MII_POLLSTAT: - /* If we're not polling our PHY instance, just return. */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - goto brgphy_service_exit; break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - PHY_WRITE(sc, MII_BMCR, - PHY_READ(sc, MII_BMCR) | BMCR_ISO); - goto brgphy_service_exit; - } - /* If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; @@ -384,18 +373,13 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) mii->mii_ifp->if_flags & IFF_LINK0); break; default: - error = EINVAL; - goto brgphy_service_exit; + return (EINVAL); } break; case MII_TICK: - /* Bail if we're not currently selected. */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - goto brgphy_service_exit; - /* Bail if the interface isn't up. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) - goto brgphy_service_exit; + return (0); /* Bail if autoneg isn't in process. */ @@ -464,8 +448,7 @@ brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) } } mii_phy_update(sc, cmd); -brgphy_service_exit: - return (error); + return (0); } @@ -637,7 +620,7 @@ brgphy_status(struct mii_softc *sc) PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); - /* Check for MRBE auto-negotiated speed results. */ + /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; @@ -649,39 +632,39 @@ brgphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_2500_SX; break; } - /* Check for MRBE auto-negotiated duplex results. */ + /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; - } else if (bsc->serdes_flags & BRGPHY_5709S) { + } else if (bsc->serdes_flags & BRGPHY_5709S) { - /* Select GP Status Block of the AN MMD, get autoneg results. */ - PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); + /* Select GP Status Block of the AN MMD, get autoneg results. */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); - /* Restore IEEE0 block (assumed in all brgphy(4) code). */ - PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); + /* Restore IEEE0 block (assumed in all brgphy(4) code). */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); - /* Check for MRBE auto-negotiated speed results. */ - switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { - case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: - mii->mii_media_active |= IFM_10_FL; break; - case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: - mii->mii_media_active |= IFM_100_FX; break; - case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: - mii->mii_media_active |= IFM_1000_SX; break; - case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: - mii->mii_media_active |= IFM_2500_SX; break; + /* Check for MRBE auto-negotiated speed results. */ + switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { + case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: + mii->mii_media_active |= IFM_10_FL; break; + case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: + mii->mii_media_active |= IFM_100_FX; break; + case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: + mii->mii_media_active |= IFM_1000_SX; break; + case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: + mii->mii_media_active |= IFM_2500_SX; break; } - /* Check for MRBE auto-negotiated duplex results. */ + /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; - } + } } @@ -1043,26 +1026,26 @@ brgphy_reset(struct mii_softc *sc) /* Handle any bge (NetXtreme/NetLink) workarounds. */ if (bge_sc) { /* Fix up various bugs */ - if (bge_sc->bge_flags & BGE_FLAG_5704_A0_BUG) + if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) brgphy_fixup_5704_a0_bug(sc); - if (bge_sc->bge_flags & BGE_FLAG_ADC_BUG) + if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) brgphy_fixup_adc_bug(sc); - if (bge_sc->bge_flags & BGE_FLAG_ADJUST_TRIM) + if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) brgphy_fixup_adjust_trim(sc); - if (bge_sc->bge_flags & BGE_FLAG_BER_BUG) + if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) brgphy_fixup_ber_bug(sc); - if (bge_sc->bge_flags & BGE_FLAG_CRC_BUG) + if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) brgphy_fixup_crc_bug(sc); - if (bge_sc->bge_flags & BGE_FLAG_JITTER_BUG) + if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) brgphy_fixup_jitter_bug(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); - if (bge_sc->bge_flags & BGE_FLAG_WIRESPEED) + if (bge_sc->bge_phy_flags & BGE_PHY_WIRESPEED) brgphy_ethernet_wirespeed(sc); /* Enable Link LED on Dell boxes */ - if (bge_sc->bge_flags & BGE_FLAG_NO_3LED) { + if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & ~BRGPHY_PHY_EXTCTL_3_LED); @@ -1127,50 +1110,50 @@ brgphy_reset(struct mii_softc *sc) } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { - /* Select the SerDes Digital block of the AN MMD. */ - PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); + /* Select the SerDes Digital block of the AN MMD. */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); val = PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1); val &= ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET; val |= BRGPHY_SD_DIG_1000X_CTL1_FIBER; PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, val); - /* Select the Over 1G block of the AN MMD. */ + /* Select the Over 1G block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_OVER_1G); - /* Enable autoneg "Next Page" to advertise 2.5G support. */ - val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1); + /* Enable autoneg "Next Page" to advertise 2.5G support. */ + val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1); if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) val |= BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; else val &= ~BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, val); - /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */ + /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); - /* Enable MRBE speed autoneg. */ - val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP); + /* Enable MRBE speed autoneg. */ + val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP); val |= BRGPHY_MRBE_MSG_PG5_NP_MBRE | BRGPHY_MRBE_MSG_PG5_NP_T2; PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, val); - /* Select the Clause 73 User B0 block of the AN MMD. */ - PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0); + /* Select the Clause 73 User B0 block of the AN MMD. */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0); - /* Enable MRBE speed autoneg. */ + /* Enable MRBE speed autoneg. */ PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); - /* Restore IEEE0 block (assumed in all brgphy(4) code). */ - PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); + /* Restore IEEE0 block (assumed in all brgphy(4) code). */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) { if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) || (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)) brgphy_fixup_disable_early_dac(sc); - + brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } else { @@ -1181,4 +1164,3 @@ brgphy_reset(struct mii_softc *sc) } } - diff --git a/sys/dev/mii/brgphyreg.h b/sys/dev/mii/brgphyreg.h index 883269e2f66..3f5ee5df8d7 100644 --- a/sys/dev/mii/brgphyreg.h +++ b/sys/dev/mii/brgphyreg.h @@ -39,21 +39,21 @@ * Broadcom BCM5400 registers */ -#define BRGPHY_MII_BMCR 0x00 -#define BRGPHY_BMCR_RESET 0x8000 -#define BRGPHY_BMCR_LOOP 0x4000 -#define BRGPHY_BMCR_SPD0 0x2000 /* Speed select, lower bit */ -#define BRGPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ -#define BRGPHY_BMCR_PDOWN 0x0800 /* Power down */ -#define BRGPHY_BMCR_ISO 0x0400 /* Isolate */ +#define BRGPHY_MII_BMCR 0x00 +#define BRGPHY_BMCR_RESET 0x8000 +#define BRGPHY_BMCR_LOOP 0x4000 +#define BRGPHY_BMCR_SPD0 0x2000 /* Speed select, lower bit */ +#define BRGPHY_BMCR_AUTOEN 0x1000 /* Autoneg enabled */ +#define BRGPHY_BMCR_PDOWN 0x0800 /* Power down */ +#define BRGPHY_BMCR_ISO 0x0400 /* Isolate */ #define BRGPHY_BMCR_STARTNEG 0x0200 /* Restart autoneg */ -#define BRGPHY_BMCR_FDX 0x0100 /* Duplex mode */ -#define BRGPHY_BMCR_CTEST 0x0080 /* Collision test enable */ -#define BRGPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */ +#define BRGPHY_BMCR_FDX 0x0100 /* Duplex mode */ +#define BRGPHY_BMCR_CTEST 0x0080 /* Collision test enable */ +#define BRGPHY_BMCR_SPD1 0x0040 /* Speed select, upper bit */ -#define BRGPHY_S1000 BRGPHY_BMCR_SPD1 /* 1000mbps */ -#define BRGPHY_S100 BRGPHY_BMCR_SPD0 /* 100mpbs */ -#define BRGPHY_S10 0 /* 10mbps */ +#define BRGPHY_S1000 BRGPHY_BMCR_SPD1 /* 1000mbps */ +#define BRGPHY_S100 BRGPHY_BMCR_SPD0 /* 100mpbs */ +#define BRGPHY_S10 0 /* 10mbps */ #define BRGPHY_MII_BMSR 0x01 #define BRGPHY_BMSR_EXTSTS 0x0100 /* Extended status present */ @@ -262,153 +262,153 @@ #define BRGPHY_IMR_LNK_CHG 0x0002 /* Link status change */ #define BRGPHY_IMR_CRCERR 0x0001 /* CRC error */ -/*******************************************************/ -/* Begin: Shared SerDes PHY register definitions */ -/*******************************************************/ - -/* SerDes autoneg is different from copper */ -#define BRGPHY_SERDES_ANAR 0x04 -#define BRGPHY_SERDES_ANAR_FDX 0x0020 -#define BRGPHY_SERDES_ANAR_HDX 0x0040 -#define BRGPHY_SERDES_ANAR_NO_PAUSE (0x0 << 7) -#define BRGPHY_SERDES_ANAR_SYM_PAUSE (0x1 << 7) -#define BRGPHY_SERDES_ANAR_ASYM_PAUSE (0x2 << 7) -#define BRGPHY_SERDES_ANAR_BOTH_PAUSE (0x3 << 7) - -#define BRGPHY_SERDES_ANLPAR 0x05 -#define BRGPHY_SERDES_ANLPAR_FDX 0x0020 -#define BRGPHY_SERDES_ANLPAR_HDX 0x0040 -#define BRGPHY_SERDES_ANLPAR_NO_PAUSE (0x0 << 7) -#define BRGPHY_SERDES_ANLPAR_SYM_PAUSE (0x1 << 7) -#define BRGPHY_SERDES_ANLPAR_ASYM_PAUSE (0x2 << 7) -#define BRGPHY_SERDES_ANLPAR_BOTH_PAUSE (0x3 << 7) - -/*******************************************************/ -/* End: Shared SerDes PHY register definitions */ -/*******************************************************/ - -/*******************************************************/ -/* Begin: PHY register values for the 5706 PHY */ -/*******************************************************/ - -/* - * Shadow register 0x1C, bit 15 is write enable, - * bits 14-10 select function (0x00 to 0x1F). - */ -#define BRGPHY_MII_SHADOW_1C 0x1C -#define BRGPHY_SHADOW_1C_WRITE_EN 0x8000 -#define BRGPHY_SHADOW_1C_SELECT_MASK 0x7C00 - +/*******************************************************/ +/* Begin: Shared SerDes PHY register definitions */ +/*******************************************************/ + +/* SerDes autoneg is different from copper */ +#define BRGPHY_SERDES_ANAR 0x04 +#define BRGPHY_SERDES_ANAR_FDX 0x0020 +#define BRGPHY_SERDES_ANAR_HDX 0x0040 +#define BRGPHY_SERDES_ANAR_NO_PAUSE (0x0 << 7) +#define BRGPHY_SERDES_ANAR_SYM_PAUSE (0x1 << 7) +#define BRGPHY_SERDES_ANAR_ASYM_PAUSE (0x2 << 7) +#define BRGPHY_SERDES_ANAR_BOTH_PAUSE (0x3 << 7) + +#define BRGPHY_SERDES_ANLPAR 0x05 +#define BRGPHY_SERDES_ANLPAR_FDX 0x0020 +#define BRGPHY_SERDES_ANLPAR_HDX 0x0040 +#define BRGPHY_SERDES_ANLPAR_NO_PAUSE (0x0 << 7) +#define BRGPHY_SERDES_ANLPAR_SYM_PAUSE (0x1 << 7) +#define BRGPHY_SERDES_ANLPAR_ASYM_PAUSE (0x2 << 7) +#define BRGPHY_SERDES_ANLPAR_BOTH_PAUSE (0x3 << 7) + +/*******************************************************/ +/* End: Shared SerDes PHY register definitions */ +/*******************************************************/ + +/*******************************************************/ +/* Begin: PHY register values for the 5706 PHY */ +/*******************************************************/ + +/* + * Shadow register 0x1C, bit 15 is write enable, + * bits 14-10 select function (0x00 to 0x1F). + */ +#define BRGPHY_MII_SHADOW_1C 0x1C +#define BRGPHY_SHADOW_1C_WRITE_EN 0x8000 +#define BRGPHY_SHADOW_1C_SELECT_MASK 0x7C00 + /* Shadow 0x1C Mode Control Register (select value 0x1F) */ -#define BRGPHY_SHADOW_1C_MODE_CTRL (0x1F << 10) +#define BRGPHY_SHADOW_1C_MODE_CTRL (0x1F << 10) /* When set, Regs 0-0x0F are 1000X, else 1000T */ -#define BRGPHY_SHADOW_1C_ENA_1000X 0x0001 +#define BRGPHY_SHADOW_1C_ENA_1000X 0x0001 -#define BRGPHY_MII_TEST1 0x1E -#define BRGPHY_TEST1_TRIM_EN 0x0010 -#define BRGPHY_TEST1_CRC_EN 0x8000 +#define BRGPHY_MII_TEST1 0x1E +#define BRGPHY_TEST1_TRIM_EN 0x0010 +#define BRGPHY_TEST1_CRC_EN 0x8000 -#define BRGPHY_MII_TEST2 0x1F - -/*******************************************************/ -/* End: PHY register values for the 5706 PHY */ -/*******************************************************/ - -/*******************************************************/ -/* Begin: PHY register values for the 5708S SerDes PHY */ -/*******************************************************/ - -/* Autoneg Next Page Transmit 1 Regiser */ -#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1 0x0B -#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G 0x0001 - -/* Use the BLOCK_ADDR register to select the page for registers 0x10 to 0x1E */ -#define BRGPHY_5708S_BLOCK_ADDR 0x1f -#define BRGPHY_5708S_DIG_PG0 0x0000 -#define BRGPHY_5708S_DIG3_PG2 0x0002 -#define BRGPHY_5708S_TX_MISC_PG5 0x0005 - -/* 5708S SerDes "Digital" Registers (page 0) */ -#define BRGPHY_5708S_PG0_1000X_CTL1 0x10 -#define BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN 0x0010 -#define BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE 0x0001 - -#define BRGPHY_5708S_PG0_1000X_STAT1 0x14 -#define BRGPHY_5708S_PG0_1000X_STAT1_LINK 0x0002 -#define BRGPHY_5708S_PG0_1000X_STAT1_FDX 0x0004 -#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK 0x0018 -#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10 (0x0 << 3) -#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100 (0x1 << 3) -#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G (0x2 << 3) -#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G (0x3 << 3) - - -#define BRGPHY_5708S_PG0_1000X_CTL2 0x11 -#define BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN 0x0001 - -/* 5708S SerDes "Digital 3" Registers (page 2) */ -#define BRGPHY_5708S_PG2_DIGCTL_3_0 0x10 -#define BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE 0x0001 - -/* 5708S SerDes "TX Misc" Registers (page 5) */ -#define BRGPHY_5708S_PG5_2500STATUS1 0x10 -#define BRGPHY_5708S_PG5_TXACTL1 0x15 -#define BRGPHY_5708S_PG5_TXACTL3 0x17 +#define BRGPHY_MII_TEST2 0x1F + +/*******************************************************/ +/* End: PHY register values for the 5706 PHY */ +/*******************************************************/ + +/*******************************************************/ +/* Begin: PHY register values for the 5708S SerDes PHY */ +/*******************************************************/ + +/* Autoneg Next Page Transmit 1 Regiser */ +#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1 0x0B +#define BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G 0x0001 + +/* Use the BLOCK_ADDR register to select the page for registers 0x10 to 0x1E */ +#define BRGPHY_5708S_BLOCK_ADDR 0x1f +#define BRGPHY_5708S_DIG_PG0 0x0000 +#define BRGPHY_5708S_DIG3_PG2 0x0002 +#define BRGPHY_5708S_TX_MISC_PG5 0x0005 + +/* 5708S SerDes "Digital" Registers (page 0) */ +#define BRGPHY_5708S_PG0_1000X_CTL1 0x10 +#define BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN 0x0010 +#define BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE 0x0001 + +#define BRGPHY_5708S_PG0_1000X_STAT1 0x14 +#define BRGPHY_5708S_PG0_1000X_STAT1_LINK 0x0002 +#define BRGPHY_5708S_PG0_1000X_STAT1_FDX 0x0004 +#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK 0x0018 +#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10 (0x0 << 3) +#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100 (0x1 << 3) +#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G (0x2 << 3) +#define BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G (0x3 << 3) + + +#define BRGPHY_5708S_PG0_1000X_CTL2 0x11 +#define BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN 0x0001 + +/* 5708S SerDes "Digital 3" Registers (page 2) */ +#define BRGPHY_5708S_PG2_DIGCTL_3_0 0x10 +#define BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE 0x0001 + +/* 5708S SerDes "TX Misc" Registers (page 5) */ +#define BRGPHY_5708S_PG5_2500STATUS1 0x10 +#define BRGPHY_5708S_PG5_TXACTL1 0x15 +#define BRGPHY_5708S_PG5_TXACTL3 0x17 + +/*******************************************************/ +/* End: PHY register values for the 5708S SerDes PHY */ +/*******************************************************/ -/*******************************************************/ -/* End: PHY register values for the 5708S SerDes PHY */ -/*******************************************************/ - /*******************************************************/ /* Begin: PHY register values for the 5709S SerDes PHY */ /*******************************************************/ /* 5709S SerDes "General Purpose Status" Registers */ -#define BRGPHY_BLOCK_ADDR_GP_STATUS 0x8120 -#define BRGPHY_GP_STATUS_TOP_ANEG_STATUS 0x1B -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK 0x3F00 -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10 0x0000 -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100 0x0100 -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G 0x0200 -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G 0x0300 -#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1GKX 0x0D00 -#define BRGPHY_GP_STATUS_TOP_ANEG_FDX 0x0008 -#define BRGPHY_GP_STATUS_TOP_ANEG_LINK_UP 0x0004 -#define BRGPHY_GP_STATUS_TOP_ANEG_CL73_COMP 0x0001 +#define BRGPHY_BLOCK_ADDR_GP_STATUS 0x8120 +#define BRGPHY_GP_STATUS_TOP_ANEG_STATUS 0x1B +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK 0x3F00 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10 0x0000 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100 0x0100 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G 0x0200 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G 0x0300 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1GKX 0x0D00 +#define BRGPHY_GP_STATUS_TOP_ANEG_FDX 0x0008 +#define BRGPHY_GP_STATUS_TOP_ANEG_LINK_UP 0x0004 +#define BRGPHY_GP_STATUS_TOP_ANEG_CL73_COMP 0x0001 /* 5709S SerDes "SerDes Digital" Registers */ -#define BRGPHY_BLOCK_ADDR_SERDES_DIG 0x8300 -#define BRGPHY_SERDES_DIG_1000X_CTL1 0x0010 -#define BRGPHY_SD_DIG_1000X_CTL1_AUTODET 0x0010 -#define BRGPHY_SD_DIG_1000X_CTL1_FIBER 0x0001 +#define BRGPHY_BLOCK_ADDR_SERDES_DIG 0x8300 +#define BRGPHY_SERDES_DIG_1000X_CTL1 0x0010 +#define BRGPHY_SD_DIG_1000X_CTL1_AUTODET 0x0010 +#define BRGPHY_SD_DIG_1000X_CTL1_FIBER 0x0001 /* 5709S SerDes "Over 1G" Registers */ -#define BRGPHY_BLOCK_ADDR_OVER_1G 0x8320 -#define BRGPHY_OVER_1G_UNFORMAT_PG1 0x19 +#define BRGPHY_BLOCK_ADDR_OVER_1G 0x8320 +#define BRGPHY_OVER_1G_UNFORMAT_PG1 0x19 /* 5709S SerDes "Multi-Rate Backplane Ethernet" Registers */ -#define BRGPHY_BLOCK_ADDR_MRBE 0x8350 -#define BRGPHY_MRBE_MSG_PG5_NP 0x10 -#define BRGPHY_MRBE_MSG_PG5_NP_MBRE 0x0001 -#define BRGPHY_MRBE_MSG_PG5_NP_T2 0x0001 +#define BRGPHY_BLOCK_ADDR_MRBE 0x8350 +#define BRGPHY_MRBE_MSG_PG5_NP 0x10 +#define BRGPHY_MRBE_MSG_PG5_NP_MBRE 0x0001 +#define BRGPHY_MRBE_MSG_PG5_NP_T2 0x0002 /* 5709S SerDes "IEEE Clause 73 User B0" Registers */ -#define BRGPHY_BLOCK_ADDR_CL73_USER_B0 0x8370 -#define BRGPHY_CL73_USER_B0_MBRE_CTL1 0x12 +#define BRGPHY_BLOCK_ADDR_CL73_USER_B0 0x8370 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1 0x12 #define BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP 0x2000 #define BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR 0x4000 -#define BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG 0x8000 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG 0x8000 /* 5709S SerDes "IEEE Clause 73 User B0" Registers */ -#define BRGPHY_BLOCK_ADDR_ADDR_EXT 0xFFD0 +#define BRGPHY_BLOCK_ADDR_ADDR_EXT 0xFFD0 /* 5709S SerDes "Combo IEEE 0" Registers */ -#define BRGPHY_BLOCK_ADDR_COMBO_IEEE0 0xFFE0 +#define BRGPHY_BLOCK_ADDR_COMBO_IEEE0 0xFFE0 -#define BRGPHY_ADDR_EXT 0x1E -#define BRGPHY_BLOCK_ADDR 0x1F +#define BRGPHY_ADDR_EXT 0x1E +#define BRGPHY_BLOCK_ADDR 0x1F -#define BRGPHY_ADDR_EXT_AN_MMD 0x3800 +#define BRGPHY_ADDR_EXT_AN_MMD 0x3800 /*******************************************************/ /* End: PHY register values for the 5709S SerDes PHY */ diff --git a/sys/dev/mii/ciphy.c b/sys/dev/mii/ciphy.c index 22f0818215e..cb94f85acc8 100644 --- a/sys/dev/mii/ciphy.c +++ b/sys/dev/mii/ciphy.c @@ -57,9 +57,7 @@ __FBSDID("$FreeBSD$"); #include "miibus_if.h" #include -/* -#include -*/ + static int ciphy_probe(device_t); static int ciphy_attach(device_t); @@ -115,21 +113,20 @@ ciphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = ciphy_service; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE; - mii->mii_instance++; ciphy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); @@ -148,24 +145,9 @@ ciphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -238,12 +220,6 @@ setit: break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ diff --git a/sys/dev/mii/e1000phy.c b/sys/dev/mii/e1000phy.c index 4e68ec68507..e763c21c472 100644 --- a/sys/dev/mii/e1000phy.c +++ b/sys/dev/mii/e1000phy.c @@ -59,9 +59,6 @@ __FBSDID("$FreeBSD$"); #include "miidevs.h" #include -/* XXX */ -#include -#include #include "miibus_if.h" @@ -71,7 +68,6 @@ static int e1000phy_attach(device_t); struct e1000phy_softc { struct mii_softc mii_sc; int mii_model; - struct msk_mii_data *mmd; }; static device_method_t e1000phy_methods[] = { @@ -141,25 +137,20 @@ e1000phy_attach(device_t dev) sc = &esc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = e1000phy_service; sc->mii_pdata = mii; - mii->mii_instance++; esc->mii_model = MII_MODEL(ma->mii_id2); ifp = sc->mii_pdata->mii_ifp; - if (strcmp(ifp->if_dname, "msk") == 0) { - /* XXX */ - esc->mmd = device_get_ivars( - device_get_parent(device_get_parent(dev))); - if (esc->mmd != NULL && - (esc->mmd->mii_flags & MIIF_HAVEFIBER) != 0) - sc->mii_flags |= MIIF_HAVEFIBER; - } + if (strcmp(ifp->if_dname, "msk") == 0 && + (sc->mii_flags & MIIF_MACPRIV0) != 0) + sc->mii_flags |= MIIF_PHYPRIV0; switch (esc->mii_model) { case MII_MODEL_MARVELL_E1011: @@ -215,7 +206,7 @@ e1000phy_reset(struct mii_softc *sc) reg &= ~E1000_SCR_MODE_MASK; reg |= E1000_SCR_MODE_1000BX; PHY_WRITE(sc, E1000_SCR, reg); - if (esc->mmd != NULL && esc->mmd->pmd == 'P') { + if ((sc->mii_flags & MIIF_MACPRIV0) != 0) { /* Set SIGDET polarity low for SFP module. */ PHY_WRITE(sc, E1000_EADR, 1); reg = PHY_READ(sc, E1000_SCR); @@ -322,24 +313,9 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, E1000_CR); - PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -416,12 +392,6 @@ e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) done: break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ diff --git a/sys/dev/mii/exphy.c b/sys/dev/mii/exphy.c index c4ab68ba3e6..a5b03dcd271 100644 --- a/sys/dev/mii/exphy.c +++ b/sys/dev/mii/exphy.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -147,25 +135,18 @@ exphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); - - /* - * The 3Com PHY can never be isolated, so never allow non-zero - * instances! - */ - if (mii->mii_instance != 0) { - device_printf(dev, "ignoring this PHY, non-zero instance\n"); - return (ENXIO); - } - + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = exphy_service; sc->mii_pdata = mii; - mii->mii_instance++; + /* + * The 3Com PHY can never be isolated. + */ sc->mii_flags |= MIIF_NOISOLATE; #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -175,8 +156,7 @@ exphy_attach(device_t dev) exphy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -188,13 +168,6 @@ exphy_attach(device_t dev) static int exphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - - /* - * We can't isolate the 3Com PHY, so it has to be the only one! - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - panic("exphy_service: can't isolate 3Com PHY"); switch (cmd) { case MII_POLLSTAT: diff --git a/sys/dev/mii/gentbi.c b/sys/dev/mii/gentbi.c index 10e780a3b70..ee08efed758 100644 --- a/sys/dev/mii/gentbi.c +++ b/sys/dev/mii/gentbi.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -67,7 +55,7 @@ */ /* - * Driver for generic ten-bit (1000BASE-SX) interfaces, built in to + * Driver for generic ten-bit (1000BASE-SX) interfaces, built into * many Gigabit Ethernet chips. * * All we have to do here is correctly report speed and duplex. @@ -170,7 +158,7 @@ gentbi_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); if (bootverbose) @@ -178,13 +166,12 @@ gentbi_attach(device_t dev) MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = gentbi_service; sc->mii_pdata = mii; - mii->mii_instance++; - mii_phy_reset(sc); /* @@ -207,29 +194,12 @@ gentbi_attach(device_t dev) static int gentbi_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -240,12 +210,6 @@ gentbi_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -300,11 +264,12 @@ gentbi_status(struct mii_softc *sc) * see if we're doing full-duplex. */ mii->mii_media_active |= IFM_1000_SX; - anlpar = PHY_READ(sc, MII_ANLPAR); if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0 && (anlpar & ANLPAR_X_FD) != 0) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/icsphy.c b/sys/dev/mii/icsphy.c index 9c1c3511924..849a14b3c5d 100644 --- a/sys/dev/mii/icsphy.c +++ b/sys/dev/mii/icsphy.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -150,17 +138,16 @@ icsphy_attach(device_t dev) sc = &isc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = icsphy_service; sc->mii_pdata = mii; - sc->mii_anegticks = MII_ANEGTICKS; - sc->mii_flags |= MIIF_NOISOLATE; - mii->mii_instance++; + sc->mii_flags |= MIIF_NOISOLATE; ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), @@ -182,20 +169,6 @@ icsphy_attach(device_t dev) static int icsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; - - /* - * If we're not selected, then do nothing, just isolate, if - * changing media. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - if (cmd == MII_MEDIACHG) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - } - return (0); - } switch (cmd) { case MII_POLLSTAT: diff --git a/sys/dev/mii/inphy.c b/sys/dev/mii/inphy.c index 44c3a4d86b8..6830b5adacb 100644 --- a/sys/dev/mii/inphy.c +++ b/sys/dev/mii/inphy.c @@ -104,14 +104,14 @@ inphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = inphy_service; sc->mii_pdata = mii; - mii->mii_instance++; ifmedia_add(&mii->mii_media, IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), @@ -132,22 +132,12 @@ inphy_attach(device_t dev) static int inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -158,8 +148,6 @@ inphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -210,6 +198,8 @@ inphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_10_T; if (scr & SCR_FDX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/ip1000phy.c b/sys/dev/mii/ip1000phy.c index 9b406d77895..b60fab6fc78 100644 --- a/sys/dev/mii/ip1000phy.c +++ b/sys/dev/mii/ip1000phy.c @@ -111,19 +111,23 @@ ip1000phy_attach(device_t dev) sc = &isc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = ip1000phy_service; sc->mii_pdata = mii; - sc->mii_flags |= MIIF_NOISOLATE; - mii->mii_instance++; + sc->mii_flags |= MIIF_NOISOLATE; isc->model = MII_MODEL(ma->mii_id2); isc->revision = MII_REV(ma->mii_id2); + if (isc->model == MII_MODEL_ICPLUS_IP1000A && + strcmp(mii->mii_ifp->if_dname, "stge") == 0 && + (sc->mii_flags & MIIF_MACPRIV0) != 0) + sc->mii_flags |= MIIF_PHYPRIV0; sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) @@ -135,7 +139,7 @@ ip1000phy_attach(device_t dev) printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); - return(0); + return (0); } static int @@ -146,25 +150,9 @@ ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, IP1000PHY_MII_BMCR); - PHY_WRITE(sc, IP1000PHY_MII_BMCR, - reg | IP1000PHY_BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -236,11 +224,6 @@ done: break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); /* * Is the interface even up? */ @@ -434,12 +417,8 @@ ip1000phy_load_dspcode(struct mii_softc *sc) static void ip1000phy_reset(struct mii_softc *sc) { - struct ip1000phy_softc *isc; - struct stge_softc *stge_sc; - struct mii_data *mii; uint32_t reg; - isc = (struct ip1000phy_softc *)sc; mii_phy_reset(sc); /* clear autoneg/full-duplex as we don't want it after reset */ @@ -447,15 +426,6 @@ ip1000phy_reset(struct mii_softc *sc) reg &= ~(IP1000PHY_BMCR_AUTOEN | IP1000PHY_BMCR_FDX); PHY_WRITE(sc, MII_BMCR, reg); - mii = sc->mii_pdata; - /* - * XXX There should be more general way to pass PHY specific - * data via mii interface. - */ - if (isc->model == MII_MODEL_ICPLUS_IP1000A && - strcmp(mii->mii_ifp->if_dname, "stge") == 0) { - stge_sc = mii->mii_ifp->if_softc; - if (stge_sc->sc_rev >= 0x40 && stge_sc->sc_rev <= 0x4e) - ip1000phy_load_dspcode(sc); - } + if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) + ip1000phy_load_dspcode(sc); } diff --git a/sys/dev/mii/jmphy.c b/sys/dev/mii/jmphy.c index f66510a7e47..0b04d80dd06 100644 --- a/sys/dev/mii/jmphy.c +++ b/sys/dev/mii/jmphy.c @@ -109,16 +109,15 @@ jmphy_attach(device_t dev) sc = &jsc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = jmphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - jsc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2); jsc->mii_model = MII_MODEL(ma->mii_id2); jsc->mii_rev = MII_REV(ma->mii_id2); @@ -136,35 +135,19 @@ jmphy_attach(device_t dev) printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); - return(0); + return (0); } static int jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - uint16_t bmcr; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - bmcr = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -176,12 +159,6 @@ jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ diff --git a/sys/dev/mii/lxtphy.c b/sys/dev/mii/lxtphy.c index d506042f0e3..44b40ff9cc4 100644 --- a/sys/dev/mii/lxtphy.c +++ b/sys/dev/mii/lxtphy.c @@ -17,13 +17,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -49,11 +42,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -139,36 +127,24 @@ lxtphy_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - const char *nic; sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = lxtphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); - /* - * On Apple BMAC controllers, we end up in a weird state - * of partially-completed autonegotiation on boot. So - * force autonegotation to try again. - */ - nic = device_get_name(device_get_parent(sc->mii_dev)); - if (strcmp(nic, "bm") == 0) - sc->mii_flags |= MIIF_FORCEANEG | MIIF_NOISOLATE; - #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst), MII_MEDIA_100_TX); @@ -189,28 +165,12 @@ static int lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -226,11 +186,6 @@ lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -286,6 +241,8 @@ lxtphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_10_T; if (csr & CSR_DUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/mii.c b/sys/dev/mii/mii.c index efb768e1ae9..79378f5e203 100644 --- a/sys/dev/mii/mii.c +++ b/sys/dev/mii/mii.c @@ -58,6 +58,8 @@ MODULE_VERSION(miibus, 1); #include "miibus_if.h" static int miibus_print_child(device_t dev, device_t child); +static int miibus_read_ivar(device_t dev, device_t child, int which, + uintptr_t *result); static int miibus_child_location_str(device_t bus, device_t child, char *buf, size_t buflen); static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, @@ -77,6 +79,7 @@ static device_method_t miibus_methods[] = { /* bus interface */ DEVMETHOD(bus_print_child, miibus_print_child), + DEVMETHOD(bus_read_ivar, miibus_read_ivar), DEVMETHOD(bus_driver_added, bus_generic_driver_added), DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, miibus_child_location_str), @@ -100,87 +103,52 @@ driver_t miibus_driver = { }; struct miibus_ivars { + struct ifnet *ifp; ifm_change_cb_t ifmedia_upd; ifm_stat_cb_t ifmedia_sts; + int mii_flags; }; -/* - * Helper function used by network interface drivers, attaches PHYs - * to the network interface driver parent. - */ int miibus_probe(device_t dev) { - struct mii_attach_args ma, *args; - struct mii_data *mii; - device_t child = NULL, parent; - int bmsr, capmask = 0xFFFFFFFF; - - mii = device_get_softc(dev); - parent = device_get_parent(dev); - LIST_INIT(&mii->mii_phys); - - for (ma.mii_phyno = 0; ma.mii_phyno < MII_NPHY; ma.mii_phyno++) { - /* - * Check to see if there is a PHY at this address. Note, - * many braindead PHYs report 0/0 in their ID registers, - * so we test for media in the BMSR. - */ - bmsr = MIIBUS_READREG(parent, ma.mii_phyno, MII_BMSR); - if (bmsr == 0 || bmsr == 0xffff || - (bmsr & (BMSR_EXTSTAT|BMSR_MEDIAMASK)) == 0) { - /* Assume no PHY at this address. */ - continue; - } - - /* - * Extract the IDs. Braindead PHYs will be handled by - * the `ukphy' driver, as we have no ID information to - * match on. - */ - ma.mii_id1 = MIIBUS_READREG(parent, ma.mii_phyno, - MII_PHYIDR1); - ma.mii_id2 = MIIBUS_READREG(parent, ma.mii_phyno, - MII_PHYIDR2); - - ma.mii_data = mii; - ma.mii_capmask = capmask; - - args = malloc(sizeof(struct mii_attach_args), - M_DEVBUF, M_NOWAIT); - bcopy((char *)&ma, (char *)args, sizeof(ma)); - child = device_add_child(dev, NULL, -1); - device_set_ivars(child, args); - } - - if (child == NULL) - return(ENXIO); device_set_desc(dev, "MII bus"); - return(0); + return (BUS_PROBE_SPECIFIC); } int miibus_attach(device_t dev) { struct miibus_ivars *ivars; + struct mii_attach_args *ma; struct mii_data *mii; + device_t *children; + int i, nchildren; mii = device_get_softc(dev); - /* - * Note that each NIC's softc must start with an ifnet pointer. - * XXX: EVIL HACK! - */ - mii->mii_ifp = *(struct ifnet**)device_get_softc(device_get_parent(dev)); - mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE; - mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE; + nchildren = 0; + if (device_get_children(dev, &children, &nchildren) == 0) { + for (i = 0; i < nchildren; i++) { + ma = device_get_ivars(children[i]); + ma->mii_data = mii; + } + free(children, M_TEMP); + } + if (nchildren == 0) { + device_printf(dev, "cannot get children"); + return (ENXIO); + } ivars = device_get_ivars(dev); ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd, ivars->ifmedia_sts); - bus_generic_attach(dev); + mii->mii_ifp = ivars->ifp; + mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE; + mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE; + LIST_INIT(&mii->mii_phys); - return(0); + return (bus_generic_attach(dev)); } int @@ -193,7 +161,7 @@ miibus_detach(device_t dev) ifmedia_removeall(&mii->mii_media); mii->mii_ifp = NULL; - return(0); + return (0); } static int @@ -211,22 +179,47 @@ miibus_print_child(device_t dev, device_t child) } static int -miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, - size_t buflen) +miibus_read_ivar(device_t dev, device_t child __unused, int which, + uintptr_t *result) { - struct mii_attach_args *maa = device_get_ivars(child); - snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x", - MII_OUI(maa->mii_id1, maa->mii_id2), - MII_MODEL(maa->mii_id2), MII_REV(maa->mii_id2)); + struct miibus_ivars *ivars; + + /* + * NB: this uses the instance variables of the miibus rather than + * its PHY children. + */ + ivars = device_get_ivars(dev); + switch (which) { + case MIIBUS_IVAR_FLAGS: + *result = ivars->mii_flags; + break; + default: + return (ENOENT); + } return (0); } static int -miibus_child_location_str(device_t bus, device_t child, char *buf, +miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf, size_t buflen) { - struct mii_attach_args *maa = device_get_ivars(child); - snprintf(buf, buflen, "phyno=%d", maa->mii_phyno); + struct mii_attach_args *ma; + + ma = device_get_ivars(child); + snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x", + MII_OUI(ma->mii_id1, ma->mii_id2), + MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); + return (0); +} + +static int +miibus_child_location_str(device_t bus __unused, device_t child, char *buf, + size_t buflen) +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(child); + snprintf(buf, buflen, "phyno=%d", ma->mii_phyno); return (0); } @@ -236,7 +229,7 @@ miibus_readreg(device_t dev, int phy, int reg) device_t parent; parent = device_get_parent(dev); - return(MIIBUS_READREG(parent, phy, reg)); + return (MIIBUS_READREG(parent, phy, reg)); } static int @@ -245,7 +238,7 @@ miibus_writereg(device_t dev, int phy, int reg, int data) device_t parent; parent = device_get_parent(dev); - return(MIIBUS_WRITEREG(parent, phy, reg, data)); + return (MIIBUS_WRITEREG(parent, phy, reg, data)); } static void @@ -259,7 +252,6 @@ miibus_statchg(device_t dev) mii = device_get_softc(dev); mii->mii_ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active); - return; } static void @@ -297,49 +289,169 @@ miibus_mediainit(device_t dev) mii = device_get_softc(dev); LIST_FOREACH(m, &mii->mii_media.ifm_list, ifm_list) { media = m->ifm_media; - if (media == (IFM_ETHER|IFM_AUTO)) + if (media == (IFM_ETHER | IFM_AUTO)) break; } ifmedia_set(&mii->mii_media, media); - - return; } +/* + * Helper function used by network interface drivers, attaches the miibus and + * the PHYs to the network interface driver parent. + */ int -mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd, - ifm_stat_cb_t ifmedia_sts) +mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp, + ifm_change_cb_t ifmedia_upd, ifm_stat_cb_t ifmedia_sts, int capmask, + int phyloc, int offloc, int flags) { - struct miibus_ivars *ivars; - int bmsr, i; + struct miibus_ivars *ivars; + struct mii_attach_args ma, *args; + device_t *children, phy; + int bmsr, first, i, nchildren, offset, phymax, phymin, rv; - ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT); - if (ivars == NULL) - return (ENOMEM); - ivars->ifmedia_upd = ifmedia_upd; - ivars->ifmedia_sts = ifmedia_sts; - *child = device_add_child(dev, "miibus", -1); - device_set_ivars(*child, ivars); - - for (i = 0; i < MII_NPHY; i++) { - bmsr = MIIBUS_READREG(dev, i, MII_BMSR); - if (bmsr == 0 || bmsr == 0xffff || - (bmsr & (BMSR_EXTSTAT|BMSR_MEDIAMASK)) == 0) { - /* Assume no PHY at this address. */ - continue; - } else - break; + if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) { + printf("%s: phyloc and offloc specified", __func__); + return (EINVAL); } - if (i == MII_NPHY) { - device_delete_child(dev, *child); - *child = NULL; - return(ENXIO); + if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) { + printf("%s: ivalid offloc %d", __func__, offloc); + return (EINVAL); } - bus_generic_attach(dev); + if (phyloc == MII_PHY_ANY) { + phymin = 0; + phymax = MII_NPHY - 1; + } else { + if (phyloc < 0 || phyloc >= MII_NPHY) { + printf("%s: ivalid phyloc %d", __func__, phyloc); + return (EINVAL); + } + phymin = phymax = phyloc; + } - return(0); + first = 0; + if (*miibus == NULL) { + first = 1; + ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT); + if (ivars == NULL) + return (ENOMEM); + ivars->ifp = ifp; + ivars->ifmedia_upd = ifmedia_upd; + ivars->ifmedia_sts = ifmedia_sts; + ivars->mii_flags = flags; + *miibus = device_add_child(dev, "miibus", -1); + if (*miibus == NULL) { + rv = ENXIO; + goto fail; + } + device_set_ivars(*miibus, ivars); + } else { + ivars = device_get_ivars(*miibus); + if (ivars->ifp != ifp || ivars->ifmedia_upd != ifmedia_upd || + ivars->ifmedia_sts != ifmedia_sts || + ivars->mii_flags != flags) { + printf("%s: non-matching invariant", __func__); + return (EINVAL); + } + /* + * Assignment of the attach arguments mii_data for the first + * pass is done in miibus_attach(), i.e. once the miibus softc + * has been allocated. + */ + ma.mii_data = device_get_softc(*miibus); + } + + ma.mii_capmask = capmask; + + phy = NULL; + offset = 0; + for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) { + /* + * Make sure we haven't already configured a PHY at this + * address. This allows mii_attach() to be called + * multiple times. + */ + if (device_get_children(*miibus, &children, &nchildren) == 0) { + for (i = 0; i < nchildren; i++) { + args = device_get_ivars(children[i]); + if (args->mii_phyno == ma.mii_phyno) { + /* + * Yes, there is already something + * configured at this address. + */ + free(children, M_TEMP); + goto skip; + } + } + free(children, M_TEMP); + } + + /* + * Check to see if there is a PHY at this address. Note, + * many braindead PHYs report 0/0 in their ID registers, + * so we test for media in the BMSR. + */ + bmsr = MIIBUS_READREG(dev, ma.mii_phyno, MII_BMSR); + if (bmsr == 0 || bmsr == 0xffff || + (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) { + /* Assume no PHY at this address. */ + continue; + } + + /* + * There is a PHY at this address. If we were given an + * `offset' locator, skip this PHY if it doesn't match. + */ + if (offloc != MII_OFFSET_ANY && offloc != offset) + goto skip; + + /* + * Extract the IDs. Braindead PHYs will be handled by + * the `ukphy' driver, as we have no ID information to + * match on. + */ + ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1); + ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2); + + args = malloc(sizeof(struct mii_attach_args), M_DEVBUF, + M_NOWAIT); + if (args == NULL) + goto skip; + bcopy((char *)&ma, (char *)args, sizeof(ma)); + phy = device_add_child(*miibus, NULL, -1); + if (phy == NULL) { + free(args, M_DEVBUF); + goto skip; + } + device_set_ivars(phy, args); + skip: + offset++; + } + + if (first != 0) { + if (phy == NULL) { + rv = ENXIO; + goto fail; + } + rv = bus_generic_attach(dev); + if (rv != 0) + goto fail; + } + rv = bus_generic_attach(*miibus); + if (rv != 0) + goto fail; + + return (0); + + fail: + if (*miibus != NULL) + device_delete_child(dev, *miibus); + free(ivars, M_DEVBUF); + if (first != 0) + *miibus = NULL; + return (rv); } /* @@ -349,12 +461,28 @@ int mii_mediachg(struct mii_data *mii) { struct mii_softc *child; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int rv; mii->mii_media_status = 0; mii->mii_media_active = IFM_NONE; LIST_FOREACH(child, &mii->mii_phys, mii_list) { + /* + * If the media indicates a different PHY instance, + * isolate this one. + */ + if (IFM_INST(ife->ifm_media) != child->mii_inst) { + if ((child->mii_flags & MIIF_NOISOLATE) != 0) { + device_printf(child->mii_dev, "%s: " + "can't handle non-zero PHY instance %d\n", + __func__, child->mii_inst); + continue; + } + PHY_WRITE(child, MII_BMCR, PHY_READ(child, MII_BMCR) | + BMCR_ISO); + continue; + } rv = (*child->mii_service)(child, mii, MII_MEDIACHG); if (rv) return (rv); @@ -369,9 +497,17 @@ void mii_tick(struct mii_data *mii) { struct mii_softc *child; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - LIST_FOREACH(child, &mii->mii_phys, mii_list) - (void) (*child->mii_service)(child, mii, MII_TICK); + LIST_FOREACH(child, &mii->mii_phys, mii_list) { + /* + * If this PHY instance isn't currently selected, just skip + * it. + */ + if (IFM_INST(ife->ifm_media) != child->mii_inst) + continue; + (void)(*child->mii_service)(child, mii, MII_TICK); + } } /* @@ -381,12 +517,19 @@ void mii_pollstat(struct mii_data *mii) { struct mii_softc *child; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; mii->mii_media_status = 0; mii->mii_media_active = IFM_NONE; - LIST_FOREACH(child, &mii->mii_phys, mii_list) - (void) (*child->mii_service)(child, mii, MII_POLLSTAT); + LIST_FOREACH(child, &mii->mii_phys, mii_list) { + /* + * If we're not polling this PHY instance, just skip it. + */ + if (IFM_INST(ife->ifm_media) != child->mii_inst) + continue; + (void)(*child->mii_service)(child, mii, MII_POLLSTAT); + } } /* diff --git a/sys/dev/mii/mii.h b/sys/dev/mii/mii.h index 0f1a4426e6f..b7e0a056bb6 100644 --- a/sys/dev/mii/mii.h +++ b/sys/dev/mii/mii.h @@ -1,5 +1,5 @@ /* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */ - + /*- * Copyright (c) 1997 Manuel Bouyer. All rights reserved. * @@ -14,11 +14,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -52,7 +47,7 @@ #define MII_COMMAND_WRITE 0x01 #define MII_COMMAND_ACK 0x02 -#define MII_BMCR 0x00 /* Basic mode control register (rw) */ +#define MII_BMCR 0x00 /* Basic mode control register (rw) */ #define BMCR_RESET 0x8000 /* reset */ #define BMCR_LOOP 0x4000 /* loopback */ #define BMCR_SPEED0 0x2000 /* speed selection (LSB) */ @@ -87,6 +82,8 @@ #define BMSR_JABBER 0x0002 /* Jabber detected */ #define BMSR_EXTCAP 0x0001 /* Extended capability */ +#define BMSR_DEFCAPMASK 0xffffffff + /* * Note that the EXTSTAT bit indicates that there is extended status * info available in register 15, but 802.3 section 22.2.4.3 also diff --git a/sys/dev/mii/mii_physubr.c b/sys/dev/mii/mii_physubr.c index c8b9ecede55..015d53ce11e 100644 --- a/sys/dev/mii/mii_physubr.c +++ b/sys/dev/mii/mii_physubr.c @@ -56,7 +56,7 @@ __FBSDID("$FreeBSD$"); /* * Media to register setting conversion table. Order matters. */ -const struct mii_media mii_media_table[MII_NMEDIA] = { +static const struct mii_media mii_media_table[MII_NMEDIA] = { /* None */ { BMCR_ISO, ANAR_CSMA, 0, }, @@ -286,100 +286,6 @@ mii_phy_update(struct mii_softc *sc, int cmd) } } -/* - * Given an ifmedia word, return the corresponding ANAR value. - */ -int -mii_anar(int media) -{ - int rv; - - switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) { - case IFM_ETHER|IFM_10_T: - rv = ANAR_10|ANAR_CSMA; - break; - case IFM_ETHER|IFM_10_T|IFM_FDX: - rv = ANAR_10_FD|ANAR_CSMA; - break; - case IFM_ETHER|IFM_100_TX: - rv = ANAR_TX|ANAR_CSMA; - break; - case IFM_ETHER|IFM_100_TX|IFM_FDX: - rv = ANAR_TX_FD|ANAR_CSMA; - break; - case IFM_ETHER|IFM_100_T4: - rv = ANAR_T4|ANAR_CSMA; - break; - default: - rv = 0; - break; - } - - return (rv); -} - -/* - * Initialize generic PHY media based on BMSR, called when a PHY is - * attached. We expect to be set up to print a comma-separated list - * of media names. Does not print a newline. - */ -void -mii_add_media(struct mii_softc *sc) -{ - const char *sep = ""; - struct mii_data *mii; - - mii = device_get_softc(sc->mii_dev); - if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) { - printf("no media present"); - return; - } - -#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#define PRINT(s) printf("%s%s", sep, s); sep = ", " - - if (sc->mii_capabilities & BMSR_10THDX) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 0); - PRINT("10baseT"); - } - if (sc->mii_capabilities & BMSR_10TFDX) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), - BMCR_FDX); - PRINT("10baseT-FDX"); - } - if (sc->mii_capabilities & BMSR_100TXHDX) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), - BMCR_S100); - PRINT("100baseTX"); - } - if (sc->mii_capabilities & BMSR_100TXFDX) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), - BMCR_S100|BMCR_FDX); - PRINT("100baseTX-FDX"); - } - if (sc->mii_capabilities & BMSR_100T4) { - /* - * XXX How do you enable 100baseT4? I assume we set - * XXX BMCR_S100 and then assume the PHYs will take - * XXX watever action is necessary to switch themselves - * XXX into T4 mode. - */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), - BMCR_S100); - PRINT("100baseT4"); - } - if (sc->mii_capabilities & BMSR_ANEG) { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), - BMCR_AUTOEN); - PRINT("auto"); - } - - - -#undef ADD -#undef PRINT -} - /* * Initialize generic PHY media based on BMSR, called when a PHY is * attached. We expect to be set up to print a comma-separated list diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h index 6b5a1217270..15a3f3f470d 100644 --- a/sys/dev/mii/miivar.h +++ b/sys/dev/mii/miivar.h @@ -102,7 +102,7 @@ typedef int (*mii_downcall_t)(struct mii_softc *, struct mii_data *, int); */ struct mii_softc { device_t mii_dev; /* generic device glue */ - + LIST_ENTRY(mii_softc) mii_list; /* entry on parent's PHY list */ int mii_phy; /* our MII address */ @@ -122,16 +122,22 @@ struct mii_softc { typedef struct mii_softc mii_softc_t; /* mii_flags */ -#define MIIF_INITDONE 0x0001 /* has been initialized (mii_data) */ -#define MIIF_NOISOLATE 0x0002 /* do not isolate the PHY */ -#define MIIF_NOLOOP 0x0004 /* no loopback capability */ -#define MIIF_AUTOTSLEEP 0x0010 /* use tsleep(), not callout() */ -#define MIIF_HAVEFIBER 0x0020 /* from parent: has fiber interface */ -#define MIIF_HAVE_GTCR 0x0040 /* has 100base-T2/1000base-T CR */ -#define MIIF_IS_1000X 0x0080 /* is a 1000BASE-X device */ -#define MIIF_DOPAUSE 0x0100 /* advertise PAUSE capability */ -#define MIIF_IS_HPNA 0x0200 /* is a HomePNA device */ -#define MIIF_FORCEANEG 0x0400 /* force auto-negotiation */ +#define MIIF_INITDONE 0x00000001 /* has been initialized (mii_data) */ +#define MIIF_NOISOLATE 0x00000002 /* do not isolate the PHY */ +#define MIIF_NOLOOP 0x00000004 /* no loopback capability */ +#define MIIF_AUTOTSLEEP 0x00000010 /* use tsleep(), not callout() */ +#define MIIF_HAVEFIBER 0x00000020 /* from parent: has fiber interface */ +#define MIIF_HAVE_GTCR 0x00000040 /* has 100base-T2/1000base-T CR */ +#define MIIF_IS_1000X 0x00000080 /* is a 1000BASE-X device */ +#define MIIF_DOPAUSE 0x00000100 /* advertise PAUSE capability */ +#define MIIF_IS_HPNA 0x00000200 /* is a HomePNA device */ +#define MIIF_FORCEANEG 0x00000400 /* force auto-negotiation */ +#define MIIF_MACPRIV0 0x01000000 /* private to the MAC driver */ +#define MIIF_MACPRIV1 0x02000000 /* private to the MAC driver */ +#define MIIF_MACPRIV2 0x04000000 /* private to the MAC driver */ +#define MIIF_PHYPRIV0 0x10000000 /* private to the PHY driver */ +#define MIIF_PHYPRIV1 0x20000000 /* private to the PHY driver */ +#define MIIF_PHYPRIV2 0x40000000 /* private to the PHY driver */ /* Default mii_anegticks values */ #define MII_ANEGTICKS 5 @@ -139,6 +145,14 @@ typedef struct mii_softc mii_softc_t; #define MIIF_INHERIT_MASK (MIIF_NOISOLATE|MIIF_NOLOOP|MIIF_AUTOTSLEEP) +/* + * Special `locators' passed to mii_attach(). If one of these is not + * an `any' value, we look for *that* PHY and configure it. If both + * are not `any', that is an error, and mii_attach() will panic. + */ +#define MII_OFFSET_ANY -1 +#define MII_PHY_ANY -1 + /* * Used to attach a PHY to a parent. */ @@ -192,6 +206,18 @@ struct mii_media { #define PHY_WRITE(p, r, v) \ MIIBUS_WRITEREG((p)->mii_dev, (p)->mii_phy, (r), (v)) +enum miibus_device_ivars { + MIIBUS_IVAR_FLAGS +}; + +/* + * Simplified accessors for miibus + */ +#define MIIBUS_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(miibus, var, MIIBUS, ivar, type) + +MIIBUS_ACCESSOR(flags, FLAGS, int) + extern devclass_t miibus_devclass; extern driver_t miibus_driver; @@ -199,13 +225,12 @@ int miibus_probe(device_t); int miibus_attach(device_t); int miibus_detach(device_t); -int mii_anar(int); +int mii_attach(device_t, device_t *, struct ifnet *, ifm_change_cb_t, + ifm_stat_cb_t, int, int, int, int); void mii_down(struct mii_data *); int mii_mediachg(struct mii_data *); void mii_tick(struct mii_data *); void mii_pollstat(struct mii_data *); -int mii_phy_probe(device_t, device_t *, ifm_change_cb_t, ifm_stat_cb_t); -void mii_add_media(struct mii_softc *); void mii_phy_add_media(struct mii_softc *); int mii_phy_auto(struct mii_softc *); diff --git a/sys/dev/mii/mlphy.c b/sys/dev/mii/mlphy.c index a99d2421896..ccfcd79545f 100644 --- a/sys/dev/mii/mlphy.c +++ b/sys/dev/mii/mlphy.c @@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$"); struct mlphy_softc { struct mii_softc ml_mii; + device_t ml_dev; int ml_state; int ml_linked; }; @@ -96,6 +97,7 @@ static driver_t mlphy_driver = { DRIVER_MODULE(mlphy, miibus, mlphy_driver, mlphy_devclass, 0, 0); +static struct mii_softc *mlphy_find_other(struct mlphy_softc *); static int mlphy_service(struct mii_softc *, struct mii_data *, int); static void mlphy_reset(struct mii_softc *); static void mlphy_status(struct mii_softc *); @@ -105,10 +107,8 @@ mlphy_probe(dev) device_t dev; { struct mii_attach_args *ma; - device_t parent; ma = device_get_ivars(dev); - parent = device_get_parent(device_get_parent(dev)); /* * Micro Linear PHY reports oui == 0 model == 0 @@ -122,7 +122,8 @@ mlphy_probe(dev) * encountered the 6692 on an Olicom card with a ThunderLAN * controller chip. */ - if (strcmp(device_get_name(parent), "tl") != 0) + if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), + "tl") != 0) return (ENXIO); device_set_desc(dev, "Micro Linear 6692 media interface"); @@ -141,36 +142,30 @@ mlphy_attach(dev) msc = device_get_softc(dev); sc = &msc->ml_mii; + msc->ml_dev = dev; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = mlphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#if 0 /* See above. */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), - BMCR_ISO); -#endif ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), - BMCR_LOOP|BMCR_S100); + MII_MEDIA_100_TX); - sc->mii_flags &= ~MIIF_NOISOLATE; mii_phy_reset(sc); - sc->mii_flags |= MIIF_NOISOLATE; - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + /* Let the companion PHY (if any) only handle the media we don't. */ ma->mii_capmask = ~sc->mii_capabilities; device_printf(dev, " "); - mii_add_media(sc); + mii_phy_add_media(sc); printf("\n"); #undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); @@ -178,20 +173,21 @@ mlphy_attach(dev) } static struct mii_softc * -mlphy_find_other(device_t mii) +mlphy_find_other(struct mlphy_softc *msc) { device_t *devlist; struct mii_softc *retval; int i, devs; retval = NULL; - if (device_get_children(mii, &devlist, &devs)) + if (device_get_children(msc->ml_mii.mii_dev, &devlist, &devs) != 0) return (NULL); - for (i = 0; i < devs; i++) - if (strcmp(device_get_name(devlist[i]), "mlphy")) { + for (i = 0; i < devs; i++) { + if (devlist[i] != msc->ml_dev) { retval = device_get_softc(devlist[i]); break; } + } free(devlist, M_TEMP); return (retval); } @@ -212,28 +208,13 @@ mlphy_service(xsc, mii, cmd) * See if there's another PHY on this bus with us. * If so, we may need it for 10Mbps modes. */ - other = mlphy_find_other(msc->ml_mii.mii_dev); + other = mlphy_find_other(msc); switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -252,7 +233,7 @@ mlphy_service(xsc, mii, cmd) mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } - (void) mii_phy_auto(sc); + (void)mii_phy_auto(sc); msc->ml_linked = 0; return (0); case IFM_10_T: @@ -269,8 +250,7 @@ mlphy_service(xsc, mii, cmd) mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, ife->ifm_data); } - PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media)); - PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + mii_phy_setmedia(sc); msc->ml_state = 0; break; case IFM_100_TX: @@ -285,28 +265,16 @@ mlphy_service(xsc, mii, cmd) mii_phy_reset(other); PHY_WRITE(other, MII_BMCR, BMCR_ISO); } - PHY_WRITE(sc, MII_ANAR, mii_anar(ife->ifm_media)); - PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + mii_phy_setmedia(sc); msc->ml_state = 0; break; - case IFM_100_T4: - /* - * XXX Not supported as a manual setting right now. - */ - return (EINVAL); default: - break; + return (EINVAL); } break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ @@ -368,7 +336,8 @@ mlphy_service(xsc, mii, cmd) if (msc->ml_state == ML_STATE_AUTO_OTHER) { other_inst = other->mii_inst; other->mii_inst = sc->mii_inst; - (void) (*other->mii_service)(other, mii, MII_POLLSTAT); + if (IFM_INST(ife->ifm_media) == other->mii_inst) + (void)(*other->mii_service)(other, mii, MII_POLLSTAT); other->mii_inst = other_inst; sc->mii_media_active = other->mii_media_active; sc->mii_media_status = other->mii_media_status; @@ -409,7 +378,7 @@ mlphy_status(sc) struct mii_softc *other = NULL; /* See if there's another PHY on the bus with us. */ - other = mlphy_find_other(msc->ml_mii.mii_dev); + other = mlphy_find_other(msc); if (other == NULL) return; diff --git a/sys/dev/mii/nsgphy.c b/sys/dev/mii/nsgphy.c index 77ee0f8ff45..b3df8a205f8 100644 --- a/sys/dev/mii/nsgphy.c +++ b/sys/dev/mii/nsgphy.c @@ -126,16 +126,15 @@ nsgphy_attach(device_t dev) device_printf(dev, "\n", MII_REV(ma->mii_id2)); device_printf(dev, " "); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = nsgphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - mii_phy_reset(sc); /* @@ -157,29 +156,12 @@ nsgphy_attach(device_t dev) static int nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -190,12 +172,6 @@ nsgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; diff --git a/sys/dev/mii/nsphy.c b/sys/dev/mii/nsphy.c index eaaa6d1fc69..af805cac2d3 100644 --- a/sys/dev/mii/nsphy.c +++ b/sys/dev/mii/nsphy.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -142,56 +130,42 @@ nsphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = nsphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - nic = device_get_name(device_get_parent(sc->mii_dev)); /* - * Am79C971 and i82557 wedge when isolating all of their - * (external) PHYs. + * Am79C971 wedge when isolating all of their external PHYs. */ - if (strcmp(nic, "fxp") == 0 || strcmp(nic, "pcn") == 0) + if (strcmp(nic, "pcn") == 0) sc->mii_flags |= MIIF_NOISOLATE; - /* - * DP83840A used with HME chips don't advertise their media - * capabilities themselves properly so force writing the ANAR - * according to the BMSR in mii_phy_setmedia(). - */ - if (strcmp(nic, "hme") == 0) - sc->mii_flags |= MIIF_FORCEANEG; +#if 1 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) /* - * In order for MII loopback to work Am79C971 and greater PCnet - * chips additionally need to be placed into external loopback - * mode which pcn(4) doesn't do so far. + * XXX IFM_LOOP should be handled by mii_phy_add_media() based + * on MIIF_NOLOOP. */ - if (strcmp(nic, "pcn") != 0) -#if 1 + if ((sc->mii_flags & MIIF_NOLOOP) == 0) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), MII_MEDIA_100_TX); -#else - if (strcmp(nic, "pcn") == 0) - sc->mii_flags |= MIIF_NOLOOP; + #endif nsphy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); -#undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); return (0); @@ -200,29 +174,13 @@ nsphy_attach(device_t dev) static int nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -269,11 +227,6 @@ nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -334,13 +287,13 @@ nsphy_status(struct mii_softc *sc) if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T|IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else mii->mii_media_active |= IFM_NONE; return; @@ -356,10 +309,7 @@ nsphy_status(struct mii_softc *sc) mii->mii_media_active |= IFM_10_T; else mii->mii_media_active |= IFM_100_TX; -#if 0 - if (par & PAR_FDX) - mii->mii_media_active |= IFM_FDX; -#endif + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/nsphyter.c b/sys/dev/mii/nsphyter.c index 934321ea6ef..5489504d4d6 100644 --- a/sys/dev/mii/nsphyter.c +++ b/sys/dev/mii/nsphyter.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -142,36 +130,31 @@ nsphyter_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - const char *nic; sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = nsphyter_service; sc->mii_pdata = mii; - mii->mii_instance++; +#if 1 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) - nic = device_get_name(device_get_parent(sc->mii_dev)); /* - * In order for MII loopback to work Am79C971 and greater PCnet - * chips additionally need to be placed into external loopback - * mode which pcn(4) doesn't do so far. + * XXX IFM_LOOP should be handled by mii_phy_add_media() based + * on MIIF_NOLOOP. */ - if (strcmp(nic, "pcn") != 0) -#if 1 + if ((sc->mii_flags & MIIF_NOLOOP) == 0) ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), MII_MEDIA_100_TX); -#else - if (strcmp(nic, "pcn") == 0) - sc->mii_flags |= MIIF_NOLOOP; + #endif nsphyter_reset(sc); @@ -181,8 +164,6 @@ nsphyter_attach(device_t dev) mii_phy_add_media(sc); printf("\n"); -#undef ADD - MIIBUS_MEDIAINIT(sc->mii_dev); return (0); } @@ -190,29 +171,12 @@ nsphyter_attach(device_t dev) static int nsphyter_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -223,11 +187,6 @@ nsphyter_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; diff --git a/sys/dev/mii/pnaphy.c b/sys/dev/mii/pnaphy.c index d37ffafa0d0..159575bdf6a 100644 --- a/sys/dev/mii/pnaphy.c +++ b/sys/dev/mii/pnaphy.c @@ -102,47 +102,29 @@ pnaphy_attach(device_t dev) struct mii_softc *sc; struct mii_attach_args *ma; struct mii_data *mii; - const char *sep = ""; sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = pnaphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - - sc->mii_flags |= MIIF_NOISOLATE; - -#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#define PRINT(s) printf("%s%s", sep, s); sep = ", " + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP | MIIF_IS_HPNA; mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); - if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) - printf("no media present"); - else { - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, sc->mii_inst), 0); - PRINT("HomePNA"); - } - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), - BMCR_ISO); - + mii_phy_add_media(sc); printf("\n"); -#undef ADD -#undef PRINT - MIIBUS_MEDIAINIT(sc->mii_dev); - return (0); } @@ -150,28 +132,12 @@ static int pnaphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -179,27 +145,15 @@ pnaphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; switch (IFM_SUBTYPE(ife->ifm_media)) { - case IFM_AUTO: - case IFM_10_T: - case IFM_100_TX: - case IFM_100_T4: - return (EINVAL); + case IFM_HPNA_1: + mii_phy_setmedia(sc); + break; default: - /* - * BMCR data is stored in the ifmedia entry. - */ - PHY_WRITE(sc, MII_ANAR, - mii_anar(ife->ifm_media)); - PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + return (EINVAL); } break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -208,7 +162,7 @@ pnaphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* Update the media status. */ ukphy_status(sc); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) - mii->mii_media_active = IFM_ETHER|IFM_HPNA_1; + mii->mii_media_active = IFM_ETHER | IFM_HPNA_1; /* Callback if something changed. */ mii_phy_update(sc, cmd); diff --git a/sys/dev/mii/qsphy.c b/sys/dev/mii/qsphy.c index 2bed7b382d9..19fc77d5cd3 100644 --- a/sys/dev/mii/qsphy.c +++ b/sys/dev/mii/qsphy.c @@ -17,13 +17,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -49,11 +42,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -142,20 +130,18 @@ qsphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = qsphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - qsphy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -167,21 +153,6 @@ qsphy_attach(device_t dev) static int qsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; - - /* - * If we're not selected, then do nothing, just isolate, if - * changing media. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - if (cmd == MII_MEDIACHG) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - } - - return (0); - } switch (cmd) { case MII_POLLSTAT: @@ -245,19 +216,19 @@ qsphy_status(struct mii_softc *sc) pctl = PHY_READ(sc, MII_QSPHY_PCTL); switch (pctl & PCTL_OPMASK) { case PCTL_10_T: - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; break; case PCTL_10_T_FDX: mii->mii_media_active |= IFM_10_T|IFM_FDX; break; case PCTL_100_TX: - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; break; case PCTL_100_TX_FDX: mii->mii_media_active |= IFM_100_TX|IFM_FDX; break; case PCTL_100_T4: - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; break; case PCTL_AN: mii->mii_media_active |= IFM_NONE; diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index 52d07d5ac4e..d1e0e51954e 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -119,16 +119,15 @@ rgephy_attach(device_t dev) sc = &rsc->mii_sc; ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = rgephy_service; sc->mii_pdata = mii; - mii->mii_instance++; - rsc->mii_model = MII_MODEL(ma->mii_id2); rsc->mii_revision = MII_REV(ma->mii_id2); @@ -137,7 +136,7 @@ rgephy_attach(device_t dev) #if 0 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), - BMCR_LOOP|BMCR_S100); + MII_MEDIA_100_TX); #endif sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; @@ -171,24 +170,9 @@ rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -270,12 +254,6 @@ setit: break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c index fbbdfd044b3..eeaaaab6145 100644 --- a/sys/dev/mii/rlphy.c +++ b/sys/dev/mii/rlphy.c @@ -129,7 +129,7 @@ rlphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; /* * Check whether we're the RTL8201L PHY and remember so the status @@ -139,23 +139,17 @@ rlphy_attach(device_t dev) if (mii_phy_dev_probe(dev, rlphys, 0) == 0) rsc->sc_is_RTL8201L++; - /* - * The RealTek PHY can never be isolated, so never allow non-zero - * instances! - */ - if (mii->mii_instance != 0) { - device_printf(dev, "ignoring this PHY, non-zero instance\n"); - return (ENXIO); - } - LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = rlphy_service; sc->mii_pdata = mii; - mii->mii_instance++; + /* + * The RealTek PHY can never be isolated. + */ sc->mii_flags |= MIIF_NOISOLATE; #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) @@ -165,8 +159,7 @@ rlphy_attach(device_t dev) mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -178,13 +171,6 @@ rlphy_attach(device_t dev) static int rlphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - - /* - * We can't isolate the RealTek PHY, so it has to be the only one! - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - panic("rlphy_service: can't isolate RealTek PHY"); switch (cmd) { case MII_POLLSTAT: @@ -264,13 +250,13 @@ rlphy_status(struct mii_softc *phy) if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T|IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else mii->mii_media_active |= IFM_NONE; return; @@ -314,6 +300,7 @@ rlphy_status(struct mii_softc *phy) else mii->mii_media_active |= IFM_100_TX; } + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/rlswitch.c b/sys/dev/mii/rlswitch.c index 95e1e7f46db..0c1b62f7458 100644 --- a/sys/dev/mii/rlswitch.c +++ b/sys/dev/mii/rlswitch.c @@ -117,37 +117,25 @@ rlswitch_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); - - /* - * We handle all pseudo PHY in a single instance, so never allow - * non-zero * instances! - */ - if (mii->mii_instance != 0) { - device_printf(dev, "ignoring this PHY, non-zero instance\n"); - return (ENXIO); - } - + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = rlswitch_service; sc->mii_pdata = mii; - mii->mii_instance++; + /* + * We handle all pseudo PHYs in a single instance. + */ sc->mii_flags |= MIIF_NOISOLATE; #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) -#if 0 /* See above. */ - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), - BMCR_ISO); -#endif - #if 0 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), - BMCR_LOOP|BMCR_S100); + MII_MEDIA_100_TX); #endif sc->mii_capabilities = BMSR_100TXFDX & ma->mii_capmask; diff --git a/sys/dev/mii/ruephy.c b/sys/dev/mii/ruephy.c index a1b43bcda77..fc2a6b942f1 100644 --- a/sys/dev/mii/ruephy.c +++ b/sys/dev/mii/ruephy.c @@ -108,34 +108,23 @@ ruephy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); - - /* - * The RealTek PHY can never be isolated, so never allow non-zero - * instances! - */ - if (mii->mii_instance != 0) { - device_printf(dev, "ignoring this PHY, non-zero instance\n"); - return (ENXIO); - } - + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = ruephy_service; sc->mii_pdata = mii; - mii->mii_instance++; /* - * Apparently, we can't neither isolate nor do loopback on this PHY. + * Apparently, we can neither isolate nor do loopback on this PHY. */ sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; ruephy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -150,13 +139,6 @@ ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; - /* - * We can't isolate the RealTek RTL8150 PHY, - * so it has to be the only one! - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - panic("ruephy_service: can't isolate RealTek RTL8150 PHY"); - switch (cmd) { case MII_POLLSTAT: break; @@ -194,10 +176,8 @@ ruephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (reg & RUEPHY_MSR_LINK) break; - /* - * Only retry autonegotiation every 5 seconds. - */ - if (++sc->mii_ticks <= MII_ANEGTICKS) + /* Only retry autonegotiation every mii_anegticks seconds. */ + if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; @@ -265,6 +245,8 @@ ruephy_status(struct mii_softc *phy) if (msr & RUEPHY_MSR_DUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } diff --git a/sys/dev/mii/smcphy.c b/sys/dev/mii/smcphy.c index 36771e50cf2..f442858eaa5 100644 --- a/sys/dev/mii/smcphy.c +++ b/sys/dev/mii/smcphy.c @@ -76,20 +76,16 @@ static driver_t smcphy_driver = { DRIVER_MODULE(smcphy, miibus, smcphy_driver, smcphy_devclass, 0, 0); +static const struct mii_phydesc smcphys[] = { + MII_PHY_DESC(SMSC, LAN83C183), + MII_PHY_END +}; + static int smcphy_probe(device_t dev) { - struct mii_attach_args *ma; - ma = device_get_ivars(dev); - - if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_SMSC || - MII_MODEL(ma->mii_id2) != MII_MODEL_SMSC_LAN83C183) - return (ENXIO); - - device_set_desc(dev, MII_STR_SMSC_LAN83C183); - - return (0); + return (mii_phy_dev_probe(dev, smcphys, BUS_PROBE_DEFAULT)); } static int @@ -102,17 +98,16 @@ smcphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = smcphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - - sc->mii_flags |= MIIF_NOISOLATE; + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; if (smcphy_reset(sc) != 0) { device_printf(dev, "reset failed\n"); @@ -123,7 +118,7 @@ smcphy_attach(device_t dev) sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); - mii_add_media(sc); + mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); @@ -142,24 +137,9 @@ smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -179,13 +159,6 @@ smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - return (0); - } - if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { return (0); } diff --git a/sys/dev/mii/tdkphy.c b/sys/dev/mii/tdkphy.c index e05f2c05548..df08c5efe9f 100644 --- a/sys/dev/mii/tdkphy.c +++ b/sys/dev/mii/tdkphy.c @@ -108,7 +108,7 @@ tdkphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); if (bootverbose) @@ -116,13 +116,12 @@ tdkphy_attach(device_t dev) MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = tdkphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - /* * Apparently, we can't do loopback on this PHY. */ @@ -130,8 +129,7 @@ tdkphy_attach(device_t dev) mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; device_printf(dev, " "); mii_phy_add_media(sc); printf("\n"); @@ -143,29 +141,12 @@ tdkphy_attach(device_t dev) static int tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -176,11 +157,6 @@ tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; @@ -242,13 +218,13 @@ tdkphy_status(struct mii_softc *phy) if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T|IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else { /* * ANLPAR isn't set, which leaves two possibilities: @@ -259,10 +235,12 @@ tdkphy_status(struct mii_softc *phy) */ diag = PHY_READ(phy, MII_DIAG); if (diag & DIAG_NEGFAIL) /* assume 10baseT if no neg */ - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else { if (diag & DIAG_DUPLEX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; if (diag & DIAG_RATE_100) mii->mii_media_active |= IFM_100_TX; else diff --git a/sys/dev/mii/tlphy.c b/sys/dev/mii/tlphy.c index 9872cb30519..d23cfb3973d 100644 --- a/sys/dev/mii/tlphy.c +++ b/sys/dev/mii/tlphy.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -136,6 +124,9 @@ static int tlphy_probe(device_t dev) { + if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), + "tl") != 0) + return (ENXIO); return (mii_phy_dev_probe(dev, tlphys, BUS_PROBE_DEFAULT)); } @@ -156,16 +147,23 @@ tlphy_attach(device_t dev) mii = device_get_softc(sc->sc_mii.mii_dev); LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list); + sc->sc_mii.mii_flags = miibus_get_flags(dev); sc->sc_mii.mii_inst = mii->mii_instance; sc->sc_mii.mii_phy = ma->mii_phyno; sc->sc_mii.mii_service = tlphy_service; sc->sc_mii.mii_pdata = mii; - capmask = 0xFFFFFFFF; + /* + * Note that if we're on a device that also supports 100baseTX, + * we are not going to want to use the built-in 10baseT port, + * since there will be another PHY on the MII wired up to the + * UTP connector. + */ + capmask = BMSR_DEFCAPMASK; if (mii->mii_instance && device_get_children(sc->sc_mii.mii_dev, &devlist, &devs) == 0) { for (i = 0; i < devs; i++) { - if (strcmp(device_get_name(devlist[i]), "tlphy")) { + if (devlist[i] != dev) { other = device_get_softc(devlist[i]); capmask &= ~other->mii_capabilities; break; @@ -176,42 +174,38 @@ tlphy_attach(device_t dev) mii->mii_instance++; - sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE; mii_phy_reset(&sc->sc_mii); - sc->sc_mii.mii_flags |= MIIF_NOISOLATE; - /* - * Note that if we're on a device that also supports 100baseTX, - * we are not going to want to use the built-in 10baseT port, - * since there will be another PHY on the MII wired up to the - * UTP connector. The parent indicates this to us by specifying - * the TLPHY_MEDIA_NO_10_T bit. - */ sc->sc_mii.mii_capabilities = - PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/; + PHY_READ(&sc->sc_mii, MII_BMSR) & capmask; #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst), - BMCR_ISO); - - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP, - sc->sc_mii.mii_inst), BMCR_LOOP); + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP, sc->sc_mii.mii_inst), + MII_MEDIA_100_TX); #define PRINT(s) printf("%s%s", sep, s); sep = ", " - device_printf(dev, " "); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0); - PRINT("10base2/BNC"); - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0); - PRINT("10base5/AUI"); - - if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) { - printf("%s", sep); - mii_add_media(&sc->sc_mii); + if ((sc->sc_mii.mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && + (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) != 0) + device_printf(dev, " "); + if ((sc->sc_mii.mii_flags & MIIF_MACPRIV0) != 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), + 0); + PRINT("10base2/BNC"); } - - printf("\n"); + if ((sc->sc_mii.mii_flags & MIIF_MACPRIV1) != 0) { + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), + 0); + PRINT("10base5/AUI"); + } + if ((sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) != 0) { + printf("%s", sep); + mii_phy_add_media(&sc->sc_mii); + } + if ((sc->sc_mii.mii_flags & (MIIF_MACPRIV0 | MIIF_MACPRIV1)) != 0 && + (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) != 0) + printf("\n"); #undef ADD #undef PRINT MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev); @@ -230,24 +224,9 @@ tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) { - reg = PHY_READ(&sc->sc_mii, MII_BMCR); - PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -261,7 +240,7 @@ tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) * an autonegotiation cycle, so there's no such * thing as "already in auto mode". */ - (void) tlphy_auto(sc); + (void)tlphy_auto(sc); break; case IFM_10_2: case IFM_10_5: @@ -272,19 +251,11 @@ tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) default: PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); DELAY(100000); - PHY_WRITE(&sc->sc_mii, MII_ANAR, - mii_anar(ife->ifm_media)); - PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data); + mii_phy_setmedia(&sc->sc_mii); } break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) - return (0); - /* * Is the interface even up? */ @@ -317,7 +288,7 @@ tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) sc->sc_mii.mii_ticks = 0; mii_phy_reset(&sc->sc_mii); - tlphy_auto(sc); + (void)tlphy_auto(sc); return (0); } @@ -368,6 +339,8 @@ tlphy_status(struct tlphy_softc *sc) */ if (bmcr & BMCR_FDX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; mii->mii_media_active |= IFM_10_T; } diff --git a/sys/dev/mii/tlphyreg.h b/sys/dev/mii/tlphyreg.h index a016f4cc691..717d7c102f8 100644 --- a/sys/dev/mii/tlphyreg.h +++ b/sys/dev/mii/tlphyreg.h @@ -11,11 +11,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES diff --git a/sys/dev/mii/truephy.c b/sys/dev/mii/truephy.c index 069b2a0638b..bb99df283f4 100644 --- a/sys/dev/mii/truephy.c +++ b/sys/dev/mii/truephy.c @@ -147,21 +147,18 @@ truephy_attach(device_t dev) ma = device_get_ivars(dev); sc->mii_phy = ma->mii_phyno; - if (sc->mii_anegticks == 0) - sc->mii_anegticks = MII_ANEGTICKS; sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = truephy_service; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; - mii->mii_instance++; - if (MII_MODEL(ma->mii_id2) == MII_MODEL_AGERE_ET1011) mii_phy_reset(sc); else @@ -175,15 +172,11 @@ truephy_attach(device_t dev) } device_printf(dev, " "); - if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && - (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) - printf("no media present"); - else - mii_phy_add_media(sc); + mii_phy_add_media(sc); printf("\n"); MIIBUS_MEDIAINIT(sc->mii_dev); - return 0; + return (0); } static int @@ -194,24 +187,9 @@ truephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return 0; break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - bmcr = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); - return 0; - } - /* * If the interface is not up, don't do anything. */ @@ -238,14 +216,8 @@ truephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return 0; - if (mii_phy_tick(sc) == EJUSTRETURN) - return 0; + return (0); break; } @@ -254,7 +226,7 @@ truephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) /* Callback if something changed. */ mii_phy_update(sc, cmd); - return 0; + return (0); } static void diff --git a/sys/dev/mii/ukphy.c b/sys/dev/mii/ukphy.c index e51964041d6..05b1b45b05a 100644 --- a/sys/dev/mii/ukphy.c +++ b/sys/dev/mii/ukphy.c @@ -16,13 +16,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -48,11 +41,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Manuel Bouyer. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES @@ -134,7 +122,7 @@ ukphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); if (bootverbose) @@ -142,17 +130,15 @@ ukphy_attach(device_t dev) MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = ukphy_service; sc->mii_pdata = mii; - mii->mii_instance++; - mii_phy_reset(sc); - sc->mii_capabilities = - PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); @@ -168,29 +154,12 @@ ukphy_attach(device_t dev) static int ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { - struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg; switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -201,11 +170,6 @@ ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; diff --git a/sys/dev/mii/ukphy_subr.c b/sys/dev/mii/ukphy_subr.c index 3c25de845d2..9decd363904 100644 --- a/sys/dev/mii/ukphy_subr.c +++ b/sys/dev/mii/ukphy_subr.c @@ -104,17 +104,17 @@ ukphy_status(struct mii_softc *phy) mii->mii_media_active |= IFM_1000_T|IFM_FDX; else if ((gtcr & GTCR_ADV_1000THDX) && (gtsr & GTSR_LP_1000THDX)) - mii->mii_media_active |= IFM_1000_T; + mii->mii_media_active |= IFM_1000_T|IFM_HDX; else if (anlpar & ANLPAR_TX_FD) mii->mii_media_active |= IFM_100_TX|IFM_FDX; else if (anlpar & ANLPAR_T4) - mii->mii_media_active |= IFM_100_T4; + mii->mii_media_active |= IFM_100_T4|IFM_HDX; else if (anlpar & ANLPAR_TX) - mii->mii_media_active |= IFM_100_TX; + mii->mii_media_active |= IFM_100_TX|IFM_HDX; else if (anlpar & ANLPAR_10_FD) mii->mii_media_active |= IFM_10_T|IFM_FDX; else if (anlpar & ANLPAR_10) - mii->mii_media_active |= IFM_10_T; + mii->mii_media_active |= IFM_10_T|IFM_HDX; else mii->mii_media_active |= IFM_NONE; } else diff --git a/sys/dev/mii/xmphy.c b/sys/dev/mii/xmphy.c index 7beaae7c55c..745c7b33718 100644 --- a/sys/dev/mii/xmphy.c +++ b/sys/dev/mii/xmphy.c @@ -107,29 +107,23 @@ xmphy_attach(device_t dev) sc = device_get_softc(dev); ma = device_get_ivars(dev); sc->mii_dev = device_get_parent(dev); - mii = device_get_softc(sc->mii_dev); + mii = ma->mii_data; LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); - sc->mii_inst = mii->mii_instance; + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; sc->mii_phy = ma->mii_phyno; sc->mii_service = xmphy_service; sc->mii_pdata = mii; sc->mii_flags |= MIIF_NOISOLATE; - mii->mii_instance++; + sc->mii_anegticks = MII_ANEGTICKS; + + mii_phy_reset(sc); #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) #define PRINT(s) printf("%s%s", sep, s); sep = ", " - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), - BMCR_ISO); -#if 0 - ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), - BMCR_LOOP|BMCR_S100); -#endif - - mii_phy_reset(sc); - device_printf(dev, " "); ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), XMPHY_BMCR_FDX); @@ -155,24 +149,9 @@ xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) switch (cmd) { case MII_POLLSTAT: - /* - * If we're not polling our PHY instance, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); break; case MII_MEDIACHG: - /* - * If the media indicates a different PHY instance, - * isolate ourselves. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) { - reg = PHY_READ(sc, MII_BMCR); - PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); - return (0); - } - /* * If the interface is not up, don't do anything. */ @@ -209,12 +188,6 @@ xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) break; case MII_TICK: - /* - * If we're not currently selected, just return. - */ - if (IFM_INST(ife->ifm_media) != sc->mii_inst) - return (0); - /* * Is the interface even up? */ @@ -236,10 +209,8 @@ xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) if (reg & BMSR_LINK) break; - /* - * Only retry autonegotiation every 5 seconds. - */ - if (++sc->mii_ticks <= MII_ANEGTICKS) + /* Only retry autonegotiation every mii_anegticks seconds. */ + if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; diff --git a/sys/dev/mps/mpi/mpi2.h b/sys/dev/mps/mpi/mpi2.h new file mode 100644 index 00000000000..6d883bcdff8 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2.h @@ -0,0 +1,1121 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2.h + * Title: MPI Message independent structures and definitions + * including System Interface Register Set and + * scatter/gather formats. + * Creation Date: June 21, 2006 + * + * mpi2.h Version: 02.00.14 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_H +#define MPI2_H + + +/***************************************************************************** +* +* MPI Version Definitions +* +*****************************************************************************/ + +#define MPI2_VERSION_MAJOR (0x02) +#define MPI2_VERSION_MINOR (0x00) +#define MPI2_VERSION_MAJOR_MASK (0xFF00) +#define MPI2_VERSION_MAJOR_SHIFT (8) +#define MPI2_VERSION_MINOR_MASK (0x00FF) +#define MPI2_VERSION_MINOR_SHIFT (0) +#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ + MPI2_VERSION_MINOR) + +#define MPI2_VERSION_02_00 (0x0200) + +/* versioning for this MPI header set */ +#define MPI2_HEADER_VERSION_UNIT (0x0E) +#define MPI2_HEADER_VERSION_DEV (0x00) +#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) +#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) +#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) +#define MPI2_HEADER_VERSION_DEV_SHIFT (0) +#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) + + +/***************************************************************************** +* +* IOC State Definitions +* +*****************************************************************************/ + +#define MPI2_IOC_STATE_RESET (0x00000000) +#define MPI2_IOC_STATE_READY (0x10000000) +#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) +#define MPI2_IOC_STATE_FAULT (0x40000000) + +#define MPI2_IOC_STATE_MASK (0xF0000000) +#define MPI2_IOC_STATE_SHIFT (28) + +/* Fault state range for prodcut specific codes */ +#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) +#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) + + +/***************************************************************************** +* +* System Interface Register Definitions +* +*****************************************************************************/ + +typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS +{ + U32 Doorbell; /* 0x00 */ + U32 WriteSequence; /* 0x04 */ + U32 HostDiagnostic; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DiagRWData; /* 0x10 */ + U32 DiagRWAddressLow; /* 0x14 */ + U32 DiagRWAddressHigh; /* 0x18 */ + U32 Reserved2[5]; /* 0x1C */ + U32 HostInterruptStatus; /* 0x30 */ + U32 HostInterruptMask; /* 0x34 */ + U32 DCRData; /* 0x38 */ + U32 DCRAddress; /* 0x3C */ + U32 Reserved3[2]; /* 0x40 */ + U32 ReplyFreeHostIndex; /* 0x48 */ + U32 Reserved4[8]; /* 0x4C */ + U32 ReplyPostHostIndex; /* 0x6C */ + U32 Reserved5; /* 0x70 */ + U32 HCBSize; /* 0x74 */ + U32 HCBAddressLow; /* 0x78 */ + U32 HCBAddressHigh; /* 0x7C */ + U32 Reserved6[16]; /* 0x80 */ + U32 RequestDescriptorPostLow; /* 0xC0 */ + U32 RequestDescriptorPostHigh; /* 0xC4 */ + U32 Reserved7[14]; /* 0xC8 */ +} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS, + Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t; + +/* + * Defines for working with the Doorbell register. + */ +#define MPI2_DOORBELL_OFFSET (0x00000000) + +/* IOC --> System values */ +#define MPI2_DOORBELL_USED (0x08000000) +#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) +#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) +#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) +#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) + +/* System --> IOC values */ +#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) +#define MPI2_DOORBELL_FUNCTION_SHIFT (24) +#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) +#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) + + +/* + * Defines for the WriteSequence register + */ +#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) +#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) +#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) +#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) +#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) +#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) +#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) +#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) +#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) + +/* + * Defines for the HostDiagnostic register + */ +#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) + +#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) +#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) + +#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) +#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) +#define MPI2_DIAG_HCB_MODE (0x00000100) +#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) +#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) +#define MPI2_DIAG_RESET_HISTORY (0x00000020) +#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) +#define MPI2_DIAG_RESET_ADAPTER (0x00000004) +#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) + +/* + * Offsets for DiagRWData and address + */ +#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) +#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) +#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) + +/* + * Defines for the HostInterruptStatus register + */ +#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) +#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) +#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS +#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) +#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) +#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) +#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS + +/* + * Defines for the HostInterruptMask register + */ +#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) +#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) +#define MPI2_HIM_REPLY_INT_MASK (0x00000008) +#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK +#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) +#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK + +/* + * Offsets for DCRData and address + */ +#define MPI2_DCR_DATA_OFFSET (0x00000038) +#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) + +/* + * Offset for the Reply Free Queue + */ +#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) + +/* + * Defines for the Reply Descriptor Post Queue + */ +#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) +#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) +#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) +#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) + +/* + * Defines for the HCBSize and address + */ +#define MPI2_HCB_SIZE_OFFSET (0x00000074) +#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) +#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) + +#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) +#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) + +/* + * Offsets for the Request Queue + */ +#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) +#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) + + +/***************************************************************************** +* +* Message Descriptors +* +*****************************************************************************/ + +/* Request Descriptors */ + +/* Default Request Descriptor */ +typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DescriptorTypeDependent; /* 0x06 */ +} MPI2_DEFAULT_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, + Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; + +/* defines for the RequestFlags field */ +#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) +#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) +#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) +#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) +#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) + +#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) + + +/* High Priority Request Descriptor */ +typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved1; /* 0x06 */ +} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, + Mpi2HighPriorityRequestDescriptor_t, + MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; + + +/* SCSI IO Request Descriptor */ +typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 DevHandle; /* 0x06 */ +} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, + Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; + + +/* SCSI Target Request Descriptor */ +typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, + Mpi2SCSITargetRequestDescriptor_t, + MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + + +/* RAID Accelerator Request Descriptor */ +typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR +{ + U8 RequestFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 LMID; /* 0x04 */ + U16 Reserved; /* 0x06 */ +} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, + Mpi2RAIDAcceleratorRequestDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; + + +/* union of Request Descriptors */ +typedef union _MPI2_REQUEST_DESCRIPTOR_UNION +{ + MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; + MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; + MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; + MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; + MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; + U64 Words; +} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, + Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; + + +/* Reply Descriptors */ + +/* Default Reply Descriptor */ +typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 DescriptorTypeDependent1; /* 0x02 */ + U32 DescriptorTypeDependent2; /* 0x04 */ +} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, + Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; + +/* defines for the ReplyFlags field */ +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) + +/* values for marking a reply descriptor as unused */ +#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) +#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) + +/* Address Reply Descriptor */ +typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 ReplyFrameAddress; /* 0x04 */ +} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, + Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; + +#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) + + +/* SCSI IO Success Reply Descriptor */ +typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U16 TaskTag; /* 0x04 */ + U16 Reserved1; /* 0x06 */ +} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, + Mpi2SCSIIOSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; + + +/* TargetAssist Success Reply Descriptor */ +typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U8 SequenceNumber; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, + Mpi2TargetAssistSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; + + +/* Target Command Buffer Reply Descriptor */ +typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U8 VP_ID; /* 0x02 */ + U8 Flags; /* 0x03 */ + U16 InitiatorDevHandle; /* 0x04 */ + U16 IoIndex; /* 0x06 */ +} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, + Mpi2TargetCommandBufferReplyDescriptor_t, + MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; + +/* defines for Flags field */ +#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) + + +/* RAID Accelerator Success Reply Descriptor */ +typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR +{ + U8 ReplyFlags; /* 0x00 */ + U8 MSIxIndex; /* 0x01 */ + U16 SMID; /* 0x02 */ + U32 Reserved; /* 0x04 */ +} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, + Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, + MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; + + +/* union of Reply Descriptors */ +typedef union _MPI2_REPLY_DESCRIPTORS_UNION +{ + MPI2_DEFAULT_REPLY_DESCRIPTOR Default; + MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; + MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; + MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; + MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; + MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; + U64 Words; +} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, + Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; + + + +/***************************************************************************** +* +* Message Functions +* 0x80 -> 0x8F reserved for private message use per product +* +* +*****************************************************************************/ + +#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ +#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ +#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ +#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ +#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ +#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ +#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ +#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ +#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ +#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ +#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ +#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ +#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ +#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ +#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ +#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ +#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ +#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ +#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ +#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ +#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ +#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ +#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ +#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ +#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */ +#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */ + + + +/* Doorbell functions */ +#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) +#define MPI2_FUNCTION_HANDSHAKE (0x42) + + +/***************************************************************************** +* +* IOC Status Values +* +*****************************************************************************/ + +/* mask for IOCStatus status value */ +#define MPI2_IOCSTATUS_MASK (0x7FFF) + +/**************************************************************************** +* Common IOCStatus values for all replies +****************************************************************************/ + +#define MPI2_IOCSTATUS_SUCCESS (0x0000) +#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI2_IOCSTATUS_BUSY (0x0002) +#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) +#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) + +/**************************************************************************** +* Config IOCStatus values +****************************************************************************/ + +#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) + +/**************************************************************************** +* SCSI IO Reply +****************************************************************************/ + +#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) +#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/**************************************************************************** +* For use by SCSI Initiator and SCSI Target end-to-end data protection +****************************************************************************/ + +#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + +/**************************************************************************** +* SCSI Target values +****************************************************************************/ + +#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) +#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) +#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) +#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) +#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) +#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) +#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) +#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) +#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) +#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) + +/**************************************************************************** +* Serial Attached SCSI values +****************************************************************************/ + +#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) +#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) + +/**************************************************************************** +* Diagnostic Buffer Post / Diagnostic Release values +****************************************************************************/ + +#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + +/**************************************************************************** +* RAID Accelerator values +****************************************************************************/ + +#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) + +/**************************************************************************** +* IOCStatus flag to indicate that log info is available +****************************************************************************/ + +#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) + +/**************************************************************************** +* IOCLogInfo Types +****************************************************************************/ + +#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) +#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) +#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) +#define MPI2_IOCLOGINFO_TYPE_FC (0x2) +#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) +#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) + + +/***************************************************************************** +* +* Standard Message Structures +* +*****************************************************************************/ + +/**************************************************************************** +* Request Message Header for all request messages +****************************************************************************/ + +typedef struct _MPI2_REQUEST_HEADER +{ + U16 FunctionDependent1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ +} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER, + MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t; + + +/**************************************************************************** +* Default Reply +****************************************************************************/ + +typedef struct _MPI2_DEFAULT_REPLY +{ + U16 FunctionDependent1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 FunctionDependent2; /* 0x04 */ + U8 FunctionDependent3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 FunctionDependent5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY, + MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t; + + +/* common version structure/union used in messages and configuration pages */ + +typedef struct _MPI2_VERSION_STRUCT +{ + U8 Dev; /* 0x00 */ + U8 Unit; /* 0x01 */ + U8 Minor; /* 0x02 */ + U8 Major; /* 0x03 */ +} MPI2_VERSION_STRUCT; + +typedef union _MPI2_VERSION_UNION +{ + MPI2_VERSION_STRUCT Struct; + U32 Word; +} MPI2_VERSION_UNION; + + +/* LUN field defines, common to many structures */ +#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI2_LUN_LEVEL_1_WORD (0xFF00) +#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) + + +/***************************************************************************** +* +* Fusion-MPT MPI Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* MPI Simple Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_SIMPLE32 +{ + U32 FlagsLength; + U32 Address; +} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32, + Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t; + +typedef struct _MPI2_SGE_SIMPLE64 +{ + U32 FlagsLength; + U64 Address; +} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64, + Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t; + +typedef struct _MPI2_SGE_SIMPLE_UNION +{ + U32 FlagsLength; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, + Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; + + +/**************************************************************************** +* MPI Chain Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_CHAIN32 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U32 Address; +} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32, + Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t; + +typedef struct _MPI2_SGE_CHAIN64 +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + U64 Address; +} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64, + Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t; + +typedef struct _MPI2_SGE_CHAIN_UNION +{ + U16 Length; + U8 NextChainOffset; + U8 Flags; + union + { + U32 Address32; + U64 Address64; + } u; +} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, + Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; + + +/**************************************************************************** +* MPI Transaction Context Element structures +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANSACTION32 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[1]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32, + Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t; + +typedef struct _MPI2_SGE_TRANSACTION64 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[2]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64, + Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t; + +typedef struct _MPI2_SGE_TRANSACTION96 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[3]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96, + Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t; + +typedef struct _MPI2_SGE_TRANSACTION128 +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + U32 TransactionContext[4]; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128, + Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128; + +typedef struct _MPI2_SGE_TRANSACTION_UNION +{ + U8 Reserved; + U8 ContextSize; + U8 DetailsLength; + U8 Flags; + union + { + U32 TransactionContext32[1]; + U32 TransactionContext64[2]; + U32 TransactionContext96[3]; + U32 TransactionContext128[4]; + } u; + U32 TransactionDetails[1]; +} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION, + Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t; + + +/**************************************************************************** +* MPI SGE union for IO SGL's +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_IO_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + } u; +} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION, + Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t; + + +/**************************************************************************** +* MPI SGE union for SGL's with Simple and Transaction elements +****************************************************************************/ + +typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION, + Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t; + + +/**************************************************************************** +* All MPI SGE types union +****************************************************************************/ + +typedef struct _MPI2_MPI_SGE_UNION +{ + union + { + MPI2_SGE_SIMPLE_UNION Simple; + MPI2_SGE_CHAIN_UNION Chain; + MPI2_SGE_TRANSACTION_UNION Transaction; + } u; +} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION, + Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t; + + +/**************************************************************************** +* MPI SGE field definition and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) +#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) +#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) +#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) +#define MPI2_SGE_FLAGS_DIRECTION (0x04) +#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) +#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) + +#define MPI2_SGE_FLAGS_SHIFT (24) + +#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) +#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) + +/* Element Type */ + +#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) +#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) +#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) +#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) + +/* Address location */ + +#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) + +/* Direction */ + +#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) +#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) + +/* Address Size */ + +#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) +#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) + +/* Context Size */ + +#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) +#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) +#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) +#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) + +#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) +#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) + +/**************************************************************************** +* MPI SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT) +#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) +#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) + +#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l)) + +#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f) +#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l) + +#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT) + + +/***************************************************************************** +* +* Fusion-MPT IEEE Scatter Gather Elements +* +*****************************************************************************/ + +/**************************************************************************** +* IEEE Simple Element structures +****************************************************************************/ + +typedef struct _MPI2_IEEE_SGE_SIMPLE32 +{ + U32 Address; + U32 FlagsLength; +} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, + Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; + +typedef struct _MPI2_IEEE_SGE_SIMPLE64 +{ + U64 Address; + U32 Length; + U16 Reserved1; + U8 Reserved2; + U8 Flags; +} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, + Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; + +typedef union _MPI2_IEEE_SGE_SIMPLE_UNION +{ + MPI2_IEEE_SGE_SIMPLE32 Simple32; + MPI2_IEEE_SGE_SIMPLE64 Simple64; +} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, + Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; + + +/**************************************************************************** +* IEEE Chain Element structures +****************************************************************************/ + +typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; + +typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; + +typedef union _MPI2_IEEE_SGE_CHAIN_UNION +{ + MPI2_IEEE_SGE_CHAIN32 Chain32; + MPI2_IEEE_SGE_CHAIN64 Chain64; +} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, + Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; + + +/**************************************************************************** +* All IEEE SGE types union +****************************************************************************/ + +typedef struct _MPI2_IEEE_SGE_UNION +{ + union + { + MPI2_IEEE_SGE_SIMPLE_UNION Simple; + MPI2_IEEE_SGE_CHAIN_UNION Chain; + } u; +} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION, + Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t; + + +/**************************************************************************** +* IEEE SGE field definitions and masks +****************************************************************************/ + +/* Flags field bit definitions */ + +#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) + +#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) + +#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) + +/* Element Type */ + +#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) +#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) + +/* Data Location Address Space */ + +#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) +#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) +#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) +#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) +#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) + + +/**************************************************************************** +* IEEE SGE operation Macros +****************************************************************************/ + +/* SIMPLE FlagsLength manipulations... */ +#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT) +#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) + +#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l)) + +#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) +#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l) + +/* CAUTION - The following are READ-MODIFY-WRITE! */ +#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f) +#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l) + + + + +/***************************************************************************** +* +* Fusion-MPT MPI/IEEE Scatter Gather Unions +* +*****************************************************************************/ + +typedef union _MPI2_SIMPLE_SGE_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; +} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION, + Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t; + + +typedef union _MPI2_SGE_IO_UNION +{ + MPI2_SGE_SIMPLE_UNION MpiSimple; + MPI2_SGE_CHAIN_UNION MpiChain; + MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; + MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; +} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, + Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; + + +/**************************************************************************** +* +* Values for SGLFlags field, used in many request messages with an SGL +* +****************************************************************************/ + +/* values for MPI SGL Data Location Address Space subfield */ +#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) +#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) +#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) +#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) +#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) +/* values for SGL Type subfield */ +#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) +#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) +#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_cnfg.h b/sys/dev/mps/mpi/mpi2_cnfg.h new file mode 100644 index 00000000000..78f26f1a396 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_cnfg.h @@ -0,0 +1,2646 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_cnfg.h + * Title: MPI Configuration messages and pages + * Creation Date: November 10, 2006 + * + * mpi2_cnfg.h Version: 02.00.13 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_CNFG_H +#define MPI2_CNFG_H + +/***************************************************************************** +* Configuration Page Header and defines +*****************************************************************************/ + +/* Config Page Header */ +typedef struct _MPI2_CONFIG_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 PageLength; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ +} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER, + Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t; + +typedef union _MPI2_CONFIG_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + U8 Bytes[4]; + U16 Word16[2]; + U32 Word32; +} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION, + Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion; + +/* Extended Config Page Header */ +typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 PageNumber; /* 0x02 */ + U8 PageType; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 Reserved2; /* 0x07 */ +} MPI2_CONFIG_EXTENDED_PAGE_HEADER, + MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, + Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t; + +typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION +{ + MPI2_CONFIG_PAGE_HEADER Struct; + MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; + U8 Bytes[8]; + U16 Word16[4]; + U32 Word32[2]; +} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, + Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion; + + +/* PageType field values */ +#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) +#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) +#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) +#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) + +#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) +#define MPI2_CONFIG_PAGETYPE_IOC (0x01) +#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) +#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) +#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) +#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) +#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) + +#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) + + +/* ExtPageType field values */ +#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) +#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) +#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) +#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) +#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) +#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) +#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) + + +/***************************************************************************** +* PageAddress defines +*****************************************************************************/ + +/* RAID Volume PageAddress format */ +#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Physical Disk PageAddress format */ +#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) +#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) +#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) +#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) + +#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) +#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) + + +/* SAS Expander PageAddress format */ +#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) +#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) + +#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) +#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) + + +/* SAS Device PageAddress format */ +#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) + +#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* SAS PHY PageAddress format */ +#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) +#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) + +#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) +#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) + + +/* SAS Port PageAddress format */ +#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) +#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) + +#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) + + +/* SAS Enclosure PageAddress format */ +#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) + +#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) + + +/* RAID Configuration PageAddress format */ +#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) +#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) +#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) +#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) + +#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) + + +/* Driver Persistent Mapping PageAddress format */ +#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) +#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) + +#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) +#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) +#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) + + +/* Ethernet PageAddress format */ +#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) +#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) + +#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) + + + +/**************************************************************************** +* Configuration messages +****************************************************************************/ + +/* Configuration Request Message */ +typedef struct _MPI2_CONFIG_REQUEST +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ + U32 PageAddress; /* 0x18 */ + MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */ +} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST, + Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t; + +/* values for the Action field */ +#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) +#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) +#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) +#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) +#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) +#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) +#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Config Reply Message */ +typedef struct _MPI2_CONFIG_REPLY +{ + U8 Action; /* 0x00 */ + U8 SGLFlags; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ExtPageLength; /* 0x04 */ + U8 ExtPageType; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 Reserved2; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ +} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY, + Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t; + + + +/***************************************************************************** +* +* C o n f i g u r a t i o n P a g e s +* +*****************************************************************************/ + +/**************************************************************************** +* Manufacturing Config pages +****************************************************************************/ + +#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) + +/* SAS */ +#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) +#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) +#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) +#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) +#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) +#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) +#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) + +#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) +#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) +#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) +#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) +#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) +#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) +#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) +#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) + + +/* Manufacturing Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 ChipName[16]; /* 0x04 */ + U8 ChipRevision[8]; /* 0x14 */ + U8 BoardName[16]; /* 0x1C */ + U8 BoardAssembly[16]; /* 0x2C */ + U8 BoardTracerNumber[16]; /* 0x3C */ +} MPI2_CONFIG_PAGE_MAN_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0, + Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t; + +#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) + + +/* Manufacturing Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 VPD[256]; /* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1, + Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t; + +#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) + + +typedef struct _MPI2_CHIP_REVISION_ID +{ + U16 DeviceID; /* 0x00 */ + U8 PCIRevisionID; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID, + Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t; + + +/* Manufacturing Page 2 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS +#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_2, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2, + Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t; + +#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) + + +/* Manufacturing Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_MAN_PAGE_3_INFO_WORDS +#define MPI2_MAN_PAGE_3_INFO_WORDS (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ + U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_3, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3, + Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t; + +#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) + + +/* Manufacturing Page 4 */ + +typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS +{ + U8 PowerSaveFlags; /* 0x00 */ + U8 InternalOperationsSleepTime; /* 0x01 */ + U8 InternalOperationsRunTime; /* 0x02 */ + U8 HostIdleTime; /* 0x03 */ +} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, + Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t; + +/* defines for the PowerSaveFlags field */ +#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) +#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) +#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) +#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) + +typedef struct _MPI2_CONFIG_PAGE_MAN_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Flags; /* 0x08 */ + U8 InquirySize; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + U8 InquiryData[56]; /* 0x10 */ + U32 RAID0VolumeSettings; /* 0x48 */ + U32 RAID1EVolumeSettings; /* 0x4C */ + U32 RAID1VolumeSettings; /* 0x50 */ + U32 RAID10VolumeSettings; /* 0x54 */ + U32 Reserved4; /* 0x58 */ + U32 Reserved5; /* 0x5C */ + MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */ + U8 MaxOCEDisks; /* 0x64 */ + U8 ResyncRate; /* 0x65 */ + U16 DataScrubDuration; /* 0x66 */ + U8 MaxHotSpares; /* 0x68 */ + U8 MaxPhysDisksPerVol; /* 0x69 */ + U8 MaxPhysDisks; /* 0x6A */ + U8 MaxVolumes; /* 0x6B */ +} MPI2_CONFIG_PAGE_MAN_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4, + Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t; + +#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) + +/* Manufacturing Page 4 Flags field */ +#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) +#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) + +#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) +#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) +#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) + +#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) +#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) +#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) +#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) +#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) + +#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) +#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) +#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) +#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) + +#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) +#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) +#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) +#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) +#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) +#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) +#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) +#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) + + +/* Manufacturing Page 5 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhys at runtime. + */ +#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES +#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_MANUFACTURING5_ENTRY +{ + U64 WWID; /* 0x00 */ + U64 DeviceName; /* 0x08 */ +} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY, + Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_MAN_5 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */ +} MPI2_CONFIG_PAGE_MAN_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5, + Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t; + +#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) + + +/* Manufacturing Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6, + Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t; + +#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) + + +/* Manufacturing Page 7 */ + +typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO +{ + U32 Pinout; /* 0x00 */ + U8 Connector[16]; /* 0x04 */ + U8 Location; /* 0x14 */ + U8 Reserved1; /* 0x15 */ + U16 Slot; /* 0x16 */ + U32 Reserved2; /* 0x18 */ +} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, + Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; + +/* defines for the Pinout field */ +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) + +/* defines for the Location field */ +#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) +#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) +#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) +#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) +#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) +#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) +#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumPhys at runtime. + */ +#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX +#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_MAN_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 EnclosureName[16]; /* 0x10 */ + U8 NumPhys; /* 0x20 */ + U8 Reserved3; /* 0x21 */ + U16 Reserved4; /* 0x22 */ + MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */ +} MPI2_CONFIG_PAGE_MAN_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, + Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; + +#define MPI2_MANUFACTURING7_PAGEVERSION (0x00) + +/* defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) + + +/* + * Generic structure to use for product-specific manufacturing pages + * (currently Manufacturing Page 8 through Manufacturing Page 31). + */ + +typedef struct _MPI2_CONFIG_PAGE_MAN_PS +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 ProductSpecificInfo;/* 0x04 */ +} MPI2_CONFIG_PAGE_MAN_PS, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS, + Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t; + +#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) +#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) + + +/**************************************************************************** +* IO Unit Config Pages +****************************************************************************/ + +/* IO Unit Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 UniqueValue; /* 0x04 */ + MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */ + MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */ +} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, + Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t; + +#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) + + +/* IO Unit Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ +} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, + Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t; + +#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) + +/* IO Unit Page 1 Flags defines */ +#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) +#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) +#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) +#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) +#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) +#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) +#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) +#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) +#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI2_IOUNITPAGE1_MULTI_PATHING (0x00000002) +#define MPI2_IOUNITPAGE1_SINGLE_PATHING (0x00000000) + + +/* IO Unit Page 3 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX +#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 GPIOCount; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */ +} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, + Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t; + +#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) + +/* defines for IO Unit Page 3 GPIOVal field */ +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) +#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) +#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) + + +/* IO Unit Page 5 */ + +/* + * Upper layer code (drivers, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumDmaEngines at runtime. + */ +#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES +#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ + U64 RaidAcceleratorBufferSize; /* 0x0C */ + U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ + U8 RAControlSize; /* 0x1C */ + U8 NumDmaEngines; /* 0x1D */ + U8 RAMinControlSize; /* 0x1E */ + U8 RAMaxControlSize; /* 0x1F */ + U32 Reserved1; /* 0x20 */ + U32 Reserved2; /* 0x24 */ + U32 Reserved3; /* 0x28 */ + U32 DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ +} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, + Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; + +#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) + +/* defines for IO Unit Page 5 DmaEngineCapabilities field */ +#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFF00) +#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) + +#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) +#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) +#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) +#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) + + +/* IO Unit Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Flags; /* 0x04 */ + U8 RAHostControlSize; /* 0x06 */ + U8 Reserved0; /* 0x07 */ + U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ + U32 Reserved3; /* 0x18 */ +} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, + Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; + +#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) + +/* defines for IO Unit Page 6 Flags field */ +#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) + + +/* IO Unit Page 7 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x04 */ + U8 PCIeWidth; /* 0x06 */ + U8 PCIeSpeed; /* 0x07 */ + U32 ProcessorState; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 IOCTemperature; /* 0x10 */ + U8 IOCTemperatureUnits; /* 0x12 */ + U8 IOCSpeed; /* 0x13 */ + U32 Reserved3; /* 0x14 */ +} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, + Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; + +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00) + +/* defines for IO Unit Page 7 PCIeWidth field */ +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) +#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) + +/* defines for IO Unit Page 7 PCIeSpeed field */ +#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) +#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) + +/* defines for IO Unit Page 7 ProcessorState field */ +#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) +#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) + +#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) +#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) + +/* defines for IO Unit Page 7 IOCTemperatureUnits field */ +#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) +#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) +#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) + +/* defines for IO Unit Page 7 IOCSpeed field */ +#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) +#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) +#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) +#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) + + + +/**************************************************************************** +* IOC Config Pages +****************************************************************************/ + +/* IOC Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U16 VendorID; /* 0x0C */ + U16 DeviceID; /* 0x0E */ + U8 RevisionID; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + U32 ClassCode; /* 0x14 */ + U16 SubsystemVendorID; /* 0x18 */ + U16 SubsystemID; /* 0x1A */ +} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0, + Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t; + +#define MPI2_IOCPAGE0_PAGEVERSION (0x02) + + +/* IOC Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Flags; /* 0x04 */ + U32 CoalescingTimeout; /* 0x08 */ + U8 CoalescingDepth; /* 0x0C */ + U8 PCISlotNum; /* 0x0D */ + U8 PCIBusNum; /* 0x0E */ + U8 PCIDomainSegment; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1, + Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t; + +#define MPI2_IOCPAGE1_PAGEVERSION (0x05) + +/* defines for IOC Page 1 Flags field */ +#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) + +#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) +#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) + +/* IOC Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_6 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 CapabilitiesFlags; /* 0x04 */ + U8 MaxDrivesRAID0; /* 0x08 */ + U8 MaxDrivesRAID1; /* 0x09 */ + U8 MaxDrivesRAID1E; /* 0x0A */ + U8 MaxDrivesRAID10; /* 0x0B */ + U8 MinDrivesRAID0; /* 0x0C */ + U8 MinDrivesRAID1; /* 0x0D */ + U8 MinDrivesRAID1E; /* 0x0E */ + U8 MinDrivesRAID10; /* 0x0F */ + U32 Reserved1; /* 0x10 */ + U8 MaxGlobalHotSpares; /* 0x14 */ + U8 MaxPhysDisks; /* 0x15 */ + U8 MaxVolumes; /* 0x16 */ + U8 MaxConfigs; /* 0x17 */ + U8 MaxOCEDisks; /* 0x18 */ + U8 Reserved2; /* 0x19 */ + U16 Reserved3; /* 0x1A */ + U32 SupportedStripeSizeMapRAID0; /* 0x1C */ + U32 SupportedStripeSizeMapRAID1E; /* 0x20 */ + U32 SupportedStripeSizeMapRAID10; /* 0x24 */ + U32 Reserved4; /* 0x28 */ + U32 Reserved5; /* 0x2C */ + U16 DefaultMetadataSize; /* 0x30 */ + U16 Reserved6; /* 0x32 */ + U16 MaxBadBlockTableEntries; /* 0x34 */ + U16 Reserved7; /* 0x36 */ + U32 IRNvsramVersion; /* 0x38 */ +} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, + Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; + +#define MPI2_IOCPAGE6_PAGEVERSION (0x04) + +/* defines for IOC Page 6 CapabilitiesFlags */ +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) +#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) +#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) + + +/* IOC Page 7 */ + +#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) + +typedef struct _MPI2_CONFIG_PAGE_IOC_7 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ + U16 SASBroadcastPrimitiveMasks; /* 0x18 */ + U16 Reserved2; /* 0x1A */ + U32 Reserved3; /* 0x1C */ +} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, + Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; + +#define MPI2_IOCPAGE7_PAGEVERSION (0x01) + + +/* IOC Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_IOC_8 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumDevsPerEnclosure; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U16 MaxPersistentEntries; /* 0x08 */ + U16 MaxNumPhysicalMappedIDs; /* 0x0A */ + U16 Flags; /* 0x0C */ + U16 Reserved3; /* 0x0E */ + U16 IRVolumeMappingFlags; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U32 Reserved5; /* 0x14 */ +} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8, + Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t; + +#define MPI2_IOCPAGE8_PAGEVERSION (0x00) + +/* defines for IOC Page 8 Flags field */ +#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) +#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) + +#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) +#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) + +#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) +#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) + +/* defines for IOC Page 8 IRVolumeMappingFlags */ +#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) +#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) +#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) + + +/**************************************************************************** +* BIOS Config Pages +****************************************************************************/ + +/* BIOS Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_BIOS_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 BiosOptions; /* 0x04 */ + U32 IOCSettings; /* 0x08 */ + U32 Reserved1; /* 0x0C */ + U32 DeviceSettings; /* 0x10 */ + U16 NumberOfDevices; /* 0x14 */ + U16 Reserved2; /* 0x16 */ + U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ + U16 IOTimeoutSequential; /* 0x1A */ + U16 IOTimeoutOther; /* 0x1C */ + U16 IOTimeoutBlockDevicesRM; /* 0x1E */ +} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, + Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; + +#define MPI2_BIOSPAGE1_PAGEVERSION (0x04) + +/* values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for BIOS Page 1 IOCSettings field */ +#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) +#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for BIOS Page 1 DeviceSettings field */ +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + + +/* BIOS Page 2 */ + +typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER +{ + U32 Reserved1; /* 0x00 */ + U32 Reserved2; /* 0x04 */ + U32 Reserved3; /* 0x08 */ + U32 Reserved4; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_BOOT_DEVICE_ADAPTER_ORDER, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, + Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t; + +typedef struct _MPI2_BOOT_DEVICE_SAS_WWID +{ + U64 SASAddress; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID, + Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t; + +typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT +{ + U64 EnclosureLogicalID; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 SlotNumber; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + U32 Reserved4; /* 0x14 */ +} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, + Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t; + +typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME +{ + U64 DeviceName; /* 0x00 */ + U8 LUN[8]; /* 0x08 */ + U32 Reserved1; /* 0x10 */ + U32 Reserved2; /* 0x14 */ +} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, + Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t; + +typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE +{ + MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; + MPI2_BOOT_DEVICE_SAS_WWID SasWwid; + MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; + MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; +} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, + Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_2 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + U32 Reserved4; /* 0x10 */ + U32 Reserved5; /* 0x14 */ + U32 Reserved6; /* 0x18 */ + U8 ReqBootDeviceForm; /* 0x1C */ + U8 Reserved7; /* 0x1D */ + U16 Reserved8; /* 0x1E */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */ + U8 ReqAltBootDeviceForm; /* 0x38 */ + U8 Reserved9; /* 0x39 */ + U16 Reserved10; /* 0x3A */ + MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */ + U8 CurrentBootDeviceForm; /* 0x58 */ + U8 Reserved11; /* 0x59 */ + U16 Reserved12; /* 0x5A */ + MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */ +} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2, + Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t; + +#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) + +/* values for BIOS Page 2 BootDeviceForm fields */ +#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) +#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) +#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) +#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) +#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) + + +/* BIOS Page 3 */ + +typedef struct _MPI2_ADAPTER_INFO +{ + U8 PciBusNumber; /* 0x00 */ + U8 PciDeviceAndFunctionNumber; /* 0x01 */ + U16 AdapterFlags; /* 0x02 */ +} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO, + Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t; + +#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) +#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) + +typedef struct _MPI2_CONFIG_PAGE_BIOS_3 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U32 GlobalFlags; /* 0x04 */ + U32 BiosVersion; /* 0x08 */ + MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */ + U32 Reserved1; /* 0x1C */ +} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3, + Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t; + +#define MPI2_BIOSPAGE3_PAGEVERSION (0x00) + +/* values for BIOS Page 3 GlobalFlags */ +#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) +#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) +#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) + +#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + + +/* BIOS Page 4 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhys at runtime. + */ +#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES +#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) +#endif + +typedef struct _MPI2_BIOS4_ENTRY +{ + U64 ReassignmentWWID; /* 0x00 */ + U64 ReassignmentDeviceName; /* 0x08 */ +} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY, + Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_BIOS_4 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */ +} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4, + Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t; + +#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) + + +/**************************************************************************** +* RAID Volume Config Pages +****************************************************************************/ + +/* RAID Volume Page 0 */ + +typedef struct _MPI2_RAIDVOL0_PHYS_DISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U8 PhysDiskNum; /* 0x02 */ + U8 Reserved; /* 0x03 */ +} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK, + Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAIDVOL0_SETTINGS +{ + U16 Settings; /* 0x00 */ + U8 HotSparePool; /* 0x01 */ + U8 Reserved; /* 0x02 */ +} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS, + Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t; + +/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ +#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) +#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) +#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) +#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) +#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) +#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) +#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) +#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) + +/* RAID Volume Page 0 VolumeSettings defines */ +#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) +#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) + +#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) +#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) +#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) +#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX +#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 VolumeState; /* 0x06 */ + U8 VolumeType; /* 0x07 */ + U32 VolumeStatusFlags; /* 0x08 */ + MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */ + U64 MaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U16 BlockSize; /* 0x1C */ + U16 Reserved1; /* 0x1E */ + U8 SupportedPhysDisks; /* 0x20 */ + U8 ResyncRate; /* 0x21 */ + U16 DataScrubDuration; /* 0x22 */ + U8 NumPhysDisks; /* 0x24 */ + U8 Reserved2; /* 0x25 */ + U8 Reserved3; /* 0x26 */ + U8 InactiveStatus; /* 0x27 */ + MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */ +} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, + Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t; + +#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) + +/* values for RAID VolumeState */ +#define MPI2_RAID_VOL_STATE_MISSING (0x00) +#define MPI2_RAID_VOL_STATE_FAILED (0x01) +#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) +#define MPI2_RAID_VOL_STATE_ONLINE (0x03) +#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) +#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) + +/* values for RAID VolumeType */ +#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) +#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) +#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) +#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) +#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) + +/* values for RAID Volume Page 0 VolumeStatusFlags field */ +#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) +#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) +#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) +#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) +#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) +#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) +#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) +#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) +#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) +#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) +#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) +#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) +#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) + +/* values for RAID Volume Page 0 SupportedPhysDisks field */ +#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) +#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) +#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) +#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) + +/* values for RAID Volume Page 0 InactiveStatus field */ +#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) +#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) +#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) +#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) +#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) +#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) + + +/* RAID Volume Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U16 Reserved0; /* 0x06 */ + U8 GUID[24]; /* 0x08 */ + U8 Name[16]; /* 0x20 */ + U64 WWID; /* 0x30 */ + U32 Reserved1; /* 0x38 */ + U32 Reserved2; /* 0x3C */ +} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, + Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t; + +#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) + + +/**************************************************************************** +* RAID Physical Disk Config Pages +****************************************************************************/ + +/* RAID Physical Disk Page 0 */ + +typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS +{ + U16 Reserved1; /* 0x00 */ + U8 HotSparePool; /* 0x02 */ + U8 Reserved2; /* 0x03 */ +} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS, + Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t; + +/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ + +typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA +{ + U8 VendorID[8]; /* 0x00 */ + U8 ProductID[16]; /* 0x08 */ + U8 ProductRevLevel[4]; /* 0x18 */ + U8 SerialNum[32]; /* 0x1C */ +} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, + Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t; + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved1; /* 0x06 */ + U8 PhysDiskNum; /* 0x07 */ + MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */ + U32 Reserved3; /* 0x4C */ + U8 PhysDiskState; /* 0x50 */ + U8 OfflineReason; /* 0x51 */ + U8 IncompatibleReason; /* 0x52 */ + U8 PhysDiskAttributes; /* 0x53 */ + U32 PhysDiskStatusFlags; /* 0x54 */ + U64 DeviceMaxLBA; /* 0x58 */ + U64 HostMaxLBA; /* 0x60 */ + U64 CoercedMaxLBA; /* 0x68 */ + U16 BlockSize; /* 0x70 */ + U16 Reserved5; /* 0x72 */ + U32 Reserved6; /* 0x74 */ +} MPI2_CONFIG_PAGE_RD_PDISK_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, + Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t; + +#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) + +/* PhysDiskState defines */ +#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) +#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) +#define MPI2_RAID_PD_STATE_OFFLINE (0x02) +#define MPI2_RAID_PD_STATE_ONLINE (0x03) +#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) +#define MPI2_RAID_PD_STATE_DEGRADED (0x05) +#define MPI2_RAID_PD_STATE_REBUILDING (0x06) +#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) + +/* OfflineReason defines */ +#define MPI2_PHYSDISK0_ONLINE (0x00) +#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) +#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) +#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) +#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) +#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) +#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) + +/* IncompatibleReason defines */ +#define MPI2_PHYSDISK0_COMPATIBLE (0x00) +#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) +#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) +#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) +#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) +#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) +#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) + +/* PhysDiskAttributes defines */ +#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) +#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) +#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) +#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) + +/* PhysDiskStatusFlags defines */ +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) +#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) +#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) +#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) +#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) +#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) +#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) +#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) + + +/* RAID Physical Disk Page 1 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumPhysDiskPaths at runtime. + */ +#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX +#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) +#endif + +typedef struct _MPI2_RAIDPHYSDISK1_PATH +{ + U16 DevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U64 WWID; /* 0x04 */ + U64 OwnerWWID; /* 0x0C */ + U8 OwnerIdentifier; /* 0x14 */ + U8 Reserved2; /* 0x15 */ + U16 Flags; /* 0x16 */ +} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH, + Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t; + +/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ +#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) +#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) +#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) + +typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 +{ + MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhysDiskPaths; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 Reserved1; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */ +} MPI2_CONFIG_PAGE_RD_PDISK_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, + Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t; + +#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) + + +/**************************************************************************** +* values for fields used by several types of SAS Config Pages +****************************************************************************/ + +/* values for NegotiatedLinkRates fields */ +#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) +#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) +#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) +/* link rates used for Negotiated Physical and Logical Link Rate */ +#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) +#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) +#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) +#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) +#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) +#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) +#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) + + +/* values for AttachedPhyInfo fields */ +#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) +#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) +#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) + +#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) +#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) +#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) +#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) +#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) +#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) +#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) +#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) +#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) + + +/* values for PhyInfo fields */ +#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) + +#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) +#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) + +#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) +#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) +#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) +#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) +#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) + +#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) +#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) +#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) +#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) +#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) +#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) +#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) +#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) +#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) +#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) + +#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) +#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) +#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) + + +/* values for SAS ProgrammedLinkRate fields */ +#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) +#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) + + +/* values for SAS HwLinkRate fields */ +#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) +#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) +#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +/* SAS IO Unit Page 0 */ + +typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 NegotiatedLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo;/* 0x04 */ + U16 AttachedDevHandle; /* 0x08 */ + U16 ControllerDevHandle; /* 0x0A */ + U32 DiscoveryStatus; /* 0x0C */ + U32 Reserved; /* 0x10 */ +} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, + Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT0_PHY_MAX +#define MPI2_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhys; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, + Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t; + +#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) +#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + +/* values for SAS IO Unit Page 0 DiscoveryStatus */ +#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) +#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) + + +/* SAS IO Unit Page 1 */ + +typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 0x00 */ + U8 PortFlags; /* 0x01 */ + U8 PhyFlags; /* 0x02 */ + U8 MaxMinLinkRate; /* 0x03 */ + U32 ControllerPhyDeviceInfo; /* 0x04 */ + U16 MaxTargetPortConnectTime; /* 0x08 */ + U16 Reserved1; /* 0x0A */ +} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, + Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT1_PHY_MAX +#define MPI2_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 ControlFlags; /* 0x08 */ + U16 SASNarrowMaxQueueDepth; /* 0x0A */ + U16 AdditionalControlFlags; /* 0x0C */ + U16 SASWideMaxQueueDepth; /* 0x0E */ + U8 NumPhys; /* 0x10 */ + U8 SATAMaxQDepth; /* 0x11 */ + U8 ReportDeviceMissingDelay; /* 0x12 */ + U8 IODeviceMissingDelay; /* 0x13 */ + MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_1, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, + Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t; + +#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) + +/* values for SAS IO Unit Page 1 ControlFlags */ +#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) +#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) + +#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) +#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) +#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) + +#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) +#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) +#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) +#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) +#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) +#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) +#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) +#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) + +/* values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) +#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) +#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) +#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) +#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) +#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) +#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) +#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ +#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) +#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) + +/* values for SAS IO Unit Page 1 PortFlags */ +#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 1 PhyFlags */ +#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) +#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) + +/* values for SAS IO Unit Page 1 MaxMinLinkRate */ +#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) +#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) +#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) + +/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +/* SAS IO Unit Page 4 */ + +typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP +{ + U8 MaxTargetSpinup; /* 0x00 */ + U8 SpinupDelay; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, + Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * four and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT4_PHY_MAX +#define MPI2_SAS_IOUNIT4_PHY_MAX (4) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ + U32 Reserved1; /* 0x18 */ + U32 Reserved2; /* 0x1C */ + U32 Reserved3; /* 0x20 */ + U8 BootDeviceWaitTime; /* 0x24 */ + U8 Reserved4; /* 0x25 */ + U16 Reserved5; /* 0x26 */ + U8 NumPhys; /* 0x28 */ + U8 PEInitialSpinupDelay; /* 0x29 */ + U8 PEReplyDelay; /* 0x2A */ + U8 Flags; /* 0x2B */ + U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */ +} MPI2_CONFIG_PAGE_SASIOUNIT_4, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, + Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t; + +#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) + +/* defines for Flags field */ +#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) + +/* defines for PHY field */ +#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) + + +/* SAS IO Unit Page 5 */ + +typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS +{ + U8 ControlFlags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InactivityTimerExponent; /* 0x02 */ + U8 SATAPartialTimeout; /* 0x04 */ + U8 Reserved2; /* 0x05 */ + U8 SATASlumberTimeout; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U8 SASPartialTimeout; /* 0x08 */ + U8 Reserved4; /* 0x09 */ + U8 SASSlumberTimeout; /* 0x0A */ + U8 Reserved5; /* 0x0B */ +} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, + Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; + +/* defines for ControlFlags field */ +#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) +#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) +#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) +#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) + +/* defines for InactivityTimerExponent field */ +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) +#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) +#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) +#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) + +#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) +#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) +#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) +#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) +#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) +#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) +#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_SAS_IOUNIT5_PHY_MAX +#define MPI2_SAS_IOUNIT5_PHY_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumPhys; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_5, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, + Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; + +#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00) + + + + +/**************************************************************************** +* SAS Expander Config Pages +****************************************************************************/ + +/* SAS Expander Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 ReportGenLength; /* 0x09 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U32 DiscoveryStatus; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 ParentDevHandle; /* 0x1A */ + U16 ExpanderChangeCount; /* 0x1C */ + U16 ExpanderRouteIndexes; /* 0x1E */ + U8 NumPhys; /* 0x20 */ + U8 SASLevel; /* 0x21 */ + U16 Flags; /* 0x22 */ + U16 STPBusInactivityTimeLimit; /* 0x24 */ + U16 STPMaxConnectTimeLimit; /* 0x26 */ + U16 STP_SMP_NexusLossTime; /* 0x28 */ + U16 MaxNumRoutedSasAddresses; /* 0x2A */ + U64 ActiveZoneManagerSASAddress;/* 0x2C */ + U16 ZoneLockInactivityLimit; /* 0x34 */ + U16 Reserved1; /* 0x36 */ + U8 TimeToReducedFunc; /* 0x38 */ + U8 InitialTimeToReducedFunc; /* 0x39 */ + U8 MaxReducedFuncTime; /* 0x3A */ + U8 Reserved2; /* 0x3B */ +} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, + Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; + +#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) + +/* values for SAS Expander Page 0 DiscoveryStatus field */ +#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) +#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) +#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) +#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) +#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) +#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) +#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) +#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) +#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) +#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) +#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) +#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) + + +/* SAS Expander Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PhysicalPort; /* 0x08 */ + U8 Reserved1; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U8 NumPhys; /* 0x0C */ + U8 Phy; /* 0x0D */ + U16 NumTableEntriesProgrammed; /* 0x0E */ + U8 ProgrammedLinkRate; /* 0x10 */ + U8 HwLinkRate; /* 0x11 */ + U16 AttachedDevHandle; /* 0x12 */ + U32 PhyInfo; /* 0x14 */ + U32 AttachedDeviceInfo; /* 0x18 */ + U16 ExpanderDevHandle; /* 0x1C */ + U8 ChangeCount; /* 0x1E */ + U8 NegotiatedLinkRate; /* 0x1F */ + U8 PhyIdentifier; /* 0x20 */ + U8 AttachedPhyIdentifier; /* 0x21 */ + U8 Reserved3; /* 0x22 */ + U8 DiscoveryInfo; /* 0x23 */ + U32 AttachedPhyInfo; /* 0x24 */ + U8 ZoneGroup; /* 0x28 */ + U8 SelfConfigStatus; /* 0x29 */ + U16 Reserved4; /* 0x2A */ +} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1, + Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t; + +#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + +/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + +/* values for SAS Expander Page 1 DiscoveryInfo field */ +#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) +#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) +#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) + + +/**************************************************************************** +* SAS Device Config Pages +****************************************************************************/ + +/* SAS Device Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U64 SASAddress; /* 0x0C */ + U16 ParentDevHandle; /* 0x14 */ + U8 PhyNum; /* 0x16 */ + U8 AccessStatus; /* 0x17 */ + U16 DevHandle; /* 0x18 */ + U8 AttachedPhyIdentifier; /* 0x1A */ + U8 ZoneGroup; /* 0x1B */ + U32 DeviceInfo; /* 0x1C */ + U16 Flags; /* 0x20 */ + U8 PhysicalPort; /* 0x22 */ + U8 MaxPortConnections; /* 0x23 */ + U64 DeviceName; /* 0x24 */ + U8 PortGroups; /* 0x2C */ + U8 DmaGroup; /* 0x2D */ + U8 ControlGroup; /* 0x2E */ + U8 Reserved1; /* 0x2F */ + U32 Reserved2; /* 0x30 */ + U32 Reserved3; /* 0x34 */ +} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, + Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; + +#define MPI2_SASDEVICE0_PAGEVERSION (0x08) + +/* values for SAS Device Page 0 AccessStatus field */ +#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) +#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) +#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) +#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) +#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) +/* specific values for SATA Init failures */ +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) +#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) + +/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ + +/* values for SAS Device Page 0 Flags field */ +#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) +#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) +#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) +#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) +#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) + + +/* SAS Device Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U32 Reserved2; /* 0x14 */ + U16 DevHandle; /* 0x18 */ + U16 Reserved3; /* 0x1A */ + U8 InitialRegDeviceFIS[20];/* 0x1C */ +} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, + Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t; + +#define MPI2_SASDEVICE1_PAGEVERSION (0x01) + + +/**************************************************************************** +* SAS PHY Config Pages +****************************************************************************/ + +/* SAS PHY Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 OwnerDevHandle; /* 0x08 */ + U16 Reserved1; /* 0x0A */ + U16 AttachedDevHandle; /* 0x0C */ + U8 AttachedPhyIdentifier; /* 0x0E */ + U8 Reserved2; /* 0x0F */ + U32 AttachedPhyInfo; /* 0x10 */ + U8 ProgrammedLinkRate; /* 0x14 */ + U8 HwLinkRate; /* 0x15 */ + U8 ChangeCount; /* 0x16 */ + U8 Flags; /* 0x17 */ + U32 PhyInfo; /* 0x18 */ + U8 NegotiatedLinkRate; /* 0x1C */ + U8 Reserved3; /* 0x1D */ + U16 Reserved4; /* 0x1E */ +} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, + Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t; + +#define MPI2_SASPHY0_PAGEVERSION (0x03) + +/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ + +/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ + +/* values for SAS PHY Page 0 Flags field */ +#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + +/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ + +/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ + +/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ + + +/* SAS PHY Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 InvalidDwordCount; /* 0x0C */ + U32 RunningDisparityErrorCount; /* 0x10 */ + U32 LossDwordSynchCount; /* 0x14 */ + U32 PhyResetProblemCount; /* 0x18 */ +} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, + Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t; + +#define MPI2_SASPHY1_PAGEVERSION (0x01) + + +/* SAS PHY Page 2 */ + +typedef struct _MPI2_SASPHY2_PHY_EVENT +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 PhyEventInfo; /* 0x04 */ +} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, + Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY2_PHY_EVENT_MAX +#define MPI2_SASPHY2_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, + Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; + +#define MPI2_SASPHY2_PAGEVERSION (0x00) + + +/* SAS PHY Page 3 */ + +typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG +{ + U8 PhyEventCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 CounterType; /* 0x04 */ + U8 ThresholdWindow; /* 0x05 */ + U8 TimeUnits; /* 0x06 */ + U8 Reserved3; /* 0x07 */ + U32 EventThreshold; /* 0x08 */ + U16 ThresholdFlags; /* 0x0C */ + U16 Reserved4; /* 0x0E */ +} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, + Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; + +/* values for PhyEventCode field */ +#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) +#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) +#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) +#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) +#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) +#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) +#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) +#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) +#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) +#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) +#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) +#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) +#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) +#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) +#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) +#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) +#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) +#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) +#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) +#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) +#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) +#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) +#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) +#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) + +/* values for the CounterType field */ +#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) +#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) +#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) + +/* values for the TimeUnits field */ +#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) +#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) +#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) +#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) + +/* values for the ThresholdFlags field */ +#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) +#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY3_PHY_EVENT_MAX +#define MPI2_SASPHY3_PHY_EVENT_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 NumPhyEvents; /* 0x0C */ + U8 Reserved2; /* 0x0D */ + U16 Reserved3; /* 0x0E */ + MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, + Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; + +#define MPI2_SASPHY3_PAGEVERSION (0x00) + + +/* SAS PHY Page 4 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U16 Reserved1; /* 0x08 */ + U8 Reserved2; /* 0x0A */ + U8 Flags; /* 0x0B */ + U8 InitialFrame[28]; /* 0x0C */ +} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, + Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; + +#define MPI2_SASPHY4_PAGEVERSION (0x00) + +/* values for the Flags field */ +#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) +#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) + + + + +/**************************************************************************** +* SAS Port Config Pages +****************************************************************************/ + +/* SAS Port Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 PortNumber; /* 0x08 */ + U8 PhysicalPort; /* 0x09 */ + U8 PortWidth; /* 0x0A */ + U8 PhysicalPortWidth; /* 0x0B */ + U8 ZoneGroup; /* 0x0C */ + U8 Reserved1; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U64 SASAddress; /* 0x10 */ + U32 DeviceInfo; /* 0x18 */ + U32 Reserved3; /* 0x1C */ + U32 Reserved4; /* 0x20 */ +} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, + Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t; + +#define MPI2_SASPORT0_PAGEVERSION (0x00) + +/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ + + +/**************************************************************************** +* SAS Enclosure Config Pages +****************************************************************************/ + +/* SAS Enclosure Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U64 EnclosureLogicalID; /* 0x0C */ + U16 Flags; /* 0x14 */ + U16 EnclosureHandle; /* 0x16 */ + U16 NumSlots; /* 0x18 */ + U16 StartSlot; /* 0x1A */ + U16 Reserved2; /* 0x1C */ + U16 SEPDevHandle; /* 0x1E */ + U32 Reserved3; /* 0x20 */ + U32 Reserved4; /* 0x24 */ +} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, + Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; + +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) + +/* values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) +#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) + + +/**************************************************************************** +* Log Config Page +****************************************************************************/ + +/* Log Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES +#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) +#endif + +#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_LOG_0_ENTRY +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY, + Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t; + +/* values for Log Page 0 LogEntry LogEntryQualifier field */ +#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) +#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) +#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) +#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) +#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) + +typedef struct _MPI2_CONFIG_PAGE_LOG_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U16 NumLogEntries; /* 0x10 */ + U16 Reserved3; /* 0x12 */ + MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */ +} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0, + Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t; + +#define MPI2_LOG_0_PAGEVERSION (0x02) + + +/**************************************************************************** +* RAID Config Page +****************************************************************************/ + +/* RAID Page 0 */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhys at runtime. + */ +#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS +#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) +#endif + +typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 HotSparePool; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, + Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t; + +/* values for the ElementFlags field */ +#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) +#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) +#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) +#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) + + +typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumHotSpares; /* 0x08 */ + U8 NumPhysDisks; /* 0x09 */ + U8 NumVolumes; /* 0x0A */ + U8 ConfigNum; /* 0x0B */ + U32 Flags; /* 0x0C */ + U8 ConfigGUID[24]; /* 0x10 */ + U32 Reserved1; /* 0x28 */ + U8 NumElements; /* 0x2C */ + U8 Reserved2; /* 0x2D */ + U16 Reserved3; /* 0x2E */ + MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */ +} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, + Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t; + +#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) + +/* values for RAID Configuration Page 0 Flags field */ +#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) + + +/**************************************************************************** +* Driver Persistent Mapping Config Pages +****************************************************************************/ + +/* Driver Persistent Mapping Page 0 */ + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY +{ + U64 PhysicalIdentifier; /* 0x00 */ + U16 MappingInformation; /* 0x08 */ + U16 DeviceIndex; /* 0x0A */ + U32 PhysicalBitsMapping; /* 0x0C */ + U32 Reserved1; /* 0x10 */ +} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, + Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t; + +typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */ +} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, + Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t; + +#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) + +/* values for Driver Persistent Mapping Page 0 MappingInformation field */ +#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) +#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) +#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) + + +/**************************************************************************** +* Ethernet Config Pages +****************************************************************************/ + +/* Ethernet Page 0 */ + +/* IP address (union of IPv4 and IPv6) */ +typedef union _MPI2_ETHERNET_IP_ADDR +{ + U32 IPv4Addr; + U32 IPv6Addr[4]; +} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, + Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; + +#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 NumInterfaces; /* 0x08 */ + U8 Reserved0; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Status; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved2; /* 0x11 */ + U16 Reserved3; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved4; /* 0x1A */ + U8 Reserved5; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ + MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ + U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, + Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; + +#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) + +/* values for Ethernet Page 0 Status field */ +#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) +#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) +#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) +#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) +#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) +#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) +#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) +#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) +#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) +#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) + +/* values for Ethernet Page 0 MediaState field */ +#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) +#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) +#define MPI2_ETHPG0_MS_10MBIT (0x01) +#define MPI2_ETHPG0_MS_100MBIT (0x02) +#define MPI2_ETHPG0_MS_1GBIT (0x03) + + +/* Ethernet Page 1 */ + +typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved0; /* 0x08 */ + U32 Flags; /* 0x0C */ + U8 MediaState; /* 0x10 */ + U8 Reserved1; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 MacAddress[6]; /* 0x14 */ + U8 Reserved3; /* 0x1A */ + U8 Reserved4; /* 0x1B */ + MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ + MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ + MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ + MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ + MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ + U32 Reserved5; /* 0x6C */ + U32 Reserved6; /* 0x70 */ + U32 Reserved7; /* 0x74 */ + U32 Reserved8; /* 0x78 */ + U8 HostName[MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ +} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, + Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; + +#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) + +/* values for Ethernet Page 1 Flags field */ +#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) +#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) +#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) +#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) +#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) +#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) +#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) +#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) + +/* values for Ethernet Page 1 MediaState field */ +#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) +#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) +#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) + +#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) +#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) +#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) +#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) +#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_hbd.h b/sys/dev/mps/mpi/mpi2_hbd.h new file mode 100644 index 00000000000..d14e352c22a --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_hbd.h @@ -0,0 +1,114 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2009 LSI Corporation. + * + * + * Name: mpi2_hbd.h + * Title: MPI Host Based Discovery messages and structures + * Creation Date: October 21, 2009 + * + * mpi2_hbd.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 10-28-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_HBD_H +#define MPI2_HBD_H + +/**************************************************************************** +* Host Based Discovery Action messages +****************************************************************************/ + +/* Host Based Discovery Action Request Message */ +typedef struct _MPI2_HBD_ACTION_REQUEST +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 Reserved5; /* 0x18 */ + U32 HbdDeviceInfo; /* 0x1C */ + U16 ParentDevHandle; /* 0x20 */ + U16 MaxQDepth; /* 0x22 */ + U8 FirstPhyIdentifier; /* 0x24 */ + U8 Port; /* 0x25 */ + U8 MaxConnections; /* 0x26 */ + U8 MaxRate; /* 0x27 */ + U8 PortGroups; /* 0x28 */ + U8 DmaGroup; /* 0x29 */ + U8 ControlGroup; /* 0x2A */ + U8 Reserved6; /* 0x2B */ + U16 InitialAWT; /* 0x2C */ + U16 Reserved7; /* 0x2E */ + U32 Reserved8; /* 0x30 */ +} MPI2_HBD_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_HBD_ACTION_REQUEST, + Mpi2HbdActionRequest_t, MPI2_POINTER pMpi2HbdActionRequest_t; + +/* values for the Operation field */ +#define MPI2_HBD_OP_ADD_DEVICE (0x01) +#define MPI2_HBD_OP_REMOVE_DEVICE (0x02) +#define MPI2_HBD_OP_UPDATE_DEVICE (0x03) + +/* values for the HbdDeviceInfo field */ +#define MPI2_HBD_DEVICE_INFO_VIRTUAL_DEVICE (0x00004000) +#define MPI2_HBD_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI2_HBD_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI2_HBD_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI2_HBD_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI2_HBD_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI2_HBD_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI2_HBD_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI2_HBD_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI2_HBD_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI2_HBD_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI2_HBD_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI2_HBD_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI2_HBD_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI2_HBD_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI2_HBD_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + +/* values for the MaxRate field */ +#define MPI2_HBD_MAX_RATE_MASK (0x0F) +#define MPI2_HBD_MAX_RATE_1_5 (0x08) +#define MPI2_HBD_MAX_RATE_3_0 (0x09) +#define MPI2_HBD_MAX_RATE_6_0 (0x0A) + + +/* Host Based Discovery Action Reply Message */ +typedef struct _MPI2_HBD_ACTION_REPLY +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_HBD_ACTION_REPLY, MPI2_POINTER PTR_MPI2_HBD_ACTION_REPLY, + Mpi2HbdActionReply_t, MPI2_POINTER pMpi2HbdActionReply_t; + + +#endif + + diff --git a/sys/dev/mps/mpi/mpi2_history.txt b/sys/dev/mps/mpi/mpi2_history.txt new file mode 100644 index 00000000000..d70df0dc71d --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_history.txt @@ -0,0 +1,382 @@ +/* $FreeBSD$ */ + ============================== + Fusion-MPT MPI 2.0 Header File Change History + ============================== + + Copyright (c) 2000-2009 LSI Corporation. + + --------------------------------------- + Header Set Release Version: 02.00.14 + Header Set Release Date: 10-28-09 + --------------------------------------- + + Filename Current version Prior version + ---------- --------------- ------------- + mpi2.h 02.00.14 02.00.13 + mpi2_cnfg.h 02.00.13 02.00.12 + mpi2_init.h 02.00.08 02.00.07 + mpi2_ioc.h 02.00.13 02.00.12 + mpi2_raid.h 02.00.04 02.00.04 + mpi2_sas.h 02.00.03 02.00.02 + mpi2_targ.h 02.00.03 02.00.03 + mpi2_tool.h 02.00.04 02.00.04 + mpi2_type.h 02.00.00 02.00.00 + mpi2_ra.h 02.00.00 02.00.00 + mpi2_hbd.h 02.00.00 + mpi2_history.txt 02.00.14 02.00.13 + + + * Date Version Description + * -------- -------- ------------------------------------------------------ + +mpi2.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. + * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved ReplyPostHostIndex register to offset 0x6C of the + * MPI2_SYSTEM_INTERFACE_REGS and modified the define for + * MPI2_REPLY_POST_HOST_INDEX_OFFSET. + * Added union of request descriptors. + * Added union of reply descriptors. + * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_VERSION_02_00. + * Fixed the size of the FunctionDependent5 field in the + * MPI2_DEFAULT_REPLY structure. + * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. + * Removed the MPI-defined Fault Codes and extended the + * product specific codes up to 0xEFFF. + * Added a sixth key value for the WriteSequence register + * and changed the flush value to 0x0. + * Added message function codes for Diagnostic Buffer Post + * and Diagnsotic Release. + * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + * Moved MPI2_VERSION_UNION from mpi2_ioc.h. + * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. + * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. + * Added #defines for marking a reply descriptor as unused. + * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. + * Moved LUN field defines from mpi2_init.h. + * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. + * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. + * In all request and reply descriptors, replaced VF_ID + * field with MSIxIndex field. + * Removed DevHandle field from + * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + * bytes reserved. + * Added RAID Accelerator functionality. + * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. + * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. + * Added MSI-x index mask and shift for Reply Post Host + * Index register. + * Added function code for Host Based Discovery Action. + * -------------------------------------------------------------------------- + +mpi2_cnfg.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. + * Added Manufacturing Page 11. + * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + * define. + * 06-26-07 02.00.02 Adding generic structure for product-specific + * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + * Rework of BIOS Page 2 configuration page. + * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + * forms. + * Added configuration pages IOC Page 8 and Driver + * Persistent Mapping Page 0. + * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated + * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + * RAID Physical Disk Pages 0 and 1, RAID Configuration + * Page 0). + * Added new value for AccessStatus field of SAS Device + * Page 0 (_SATA_NEEDS_INITIALIZATION). + * 10-31-07 02.00.04 Added missing SEPDevHandle field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for + * NVDATA. + * Modified IOC Page 7 to use masks and added field for + * SASBroadcastPrimitiveMasks. + * Added MPI2_CONFIG_PAGE_BIOS_4. + * Added MPI2_CONFIG_PAGE_LOG_0. + * 02-29-08 02.00.06 Modified various names to make them 32-character unique. + * Added SAS Device IDs. + * Updated Integrated RAID configuration pages including + * Manufacturing Page 4, IOC Page 6, and RAID Configuration + * Page 0. + * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + * Added missing MaxNumRoutedSasAddresses field to + * MPI2_CONFIG_PAGE_EXPANDER_0. + * Added SAS Port Page 0. + * Modified structure layout for + * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + * to 0x000000FF. + * Added two new values for the Physical Disk Coercion Size + * bits in the Flags field of Manufacturing Page 4. + * Added product-specific Manufacturing pages 16 to 31. + * Modified Flags bits for controlling write cache on SATA + * drives in IO Unit Page 1. + * Added new bit to AdditionalControlFlags of SAS IO Unit + * Page 1 to control Invalid Topology Correction. + * Added SupportedPhysDisks field to RAID Volume Page 1 and + * added related defines. + * Added additional defines for RAID Volume Page 0 + * VolumeStatusFlags field. + * Modified meaning of RAID Volume Page 0 VolumeSettings + * define for auto-configure of hot-swap drives. + * Added PhysDiskAttributes field (and related defines) to + * RAID Physical Disk Page 0. + * Added MPI2_SAS_PHYINFO_PHY_VACANT define. + * Added three new DiscoveryStatus bits for SAS IO Unit + * Page 0 and SAS Expander Page 0. + * Removed multiplexing information from SAS IO Unit pages. + * Added BootDeviceWaitTime field to SAS IO Unit Page 4. + * Removed Zone Address Resolved bit from PhyInfo and from + * Expander Page 0 Flags field. + * Added two new AccessStatus values to SAS Device Page 0 + * for indicating routing problems. Added 3 reserved words + * to this page. + * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. + * Inserted missing reserved field into structure for IOC + * Page 6. + * Added more pending task bits to RAID Volume Page 0 + * VolumeStatusFlags defines. + * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + * and SAS Expander Page 0 to flag a downstream initiator + * when in simplified routing mode. + * Removed SATA Init Failure defines for DiscoveryStatus + * fields of SAS IO Unit Page 0 and SAS Expander Page 0. + * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + * Added PortGroups, DmaGroup, and ControlGroup fields to + * SAS Device Page 0. + * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO + * Unit Page 6. + * Added expander reduced functionality data to SAS + * Expander Page 0. + * Added SAS PHY Page 2 and SAS PHY Page 3. + * 07-30-09 02.00.12 Added IO Unit Page 7. + * Added new device ids. + * Added SAS IO Unit Page 5. + * Added partial and slumber power management capable flags + * to SAS Device Page 0 Flags field. + * Added PhyInfo defines for power condition. + * Added Ethernet configuration pages. + * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. + * Added SAS PHY Page 4 structure and defines. + * -------------------------------------------------------------------------- + +mpi2_init.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * -------------------------------------------------------------------------- + +mpi2_ioc.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * -------------------------------------------------------------------------- + +mpi2_raid.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * -------------------------------------------------------------------------- + +mpi2_sas.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * -------------------------------------------------------------------------- + +mpi2_targ.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to + * BufferPostFlags field of CommandBufferPostBase Request. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 10-02-08 02.00.03 Removed NextCmdBufferOffset from + * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + * Target Status Send Request only takes a single SGE for + * response data. + * -------------------------------------------------------------------------- + +mpi2_tool.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * -------------------------------------------------------------------------- + +mpi2_type.h + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + +mpi2_ra.h + * 05-06-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + +mpi2_hbd.h + * 10-28-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + + +mpi2_history.txt Parts list history + +Filename 02.00.14 02.00.13 02.00.12 +---------- -------- -------- -------- +mpi2.h 02.00.14 02.00.13 02.00.12 +mpi2_cnfg.h 02.00.13 02.00.12 02.00.11 +mpi2_init.h 02.00.08 02.00.07 02.00.07 +mpi2_ioc.h 02.00.13 02.00.12 02.00.11 +mpi2_raid.h 02.00.04 02.00.04 02.00.03 +mpi2_sas.h 02.00.03 02.00.02 02.00.02 +mpi2_targ.h 02.00.03 02.00.03 02.00.03 +mpi2_tool.h 02.00.04 02.00.04 02.00.03 +mpi2_type.h 02.00.00 02.00.00 02.00.00 +mpi2_ra.h 02.00.00 02.00.00 02.00.00 +mpi2_hbd.h 02.00.00 + +Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 +mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06 +mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03 +mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06 +mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02 +mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01 +mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + +Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +---------- -------- -------- -------- -------- -------- -------- +mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00 +mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 +mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00 +mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 +mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 + diff --git a/sys/dev/mps/mpi/mpi2_init.h b/sys/dev/mps/mpi/mpi2_init.h new file mode 100644 index 00000000000..8d2b1f98d88 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_init.h @@ -0,0 +1,454 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_init.h + * Title: MPI SCSI initiator mode messages and structures + * Creation Date: June 23, 2006 + * + * mpi2_init.h Version: 02.00.08 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. + * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. + * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. + * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. + * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO + * Control field Task Attribute flags. + * Moved LUN field defines to mpi2.h becasue they are + * common to many structures. + * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to + * Query Asynchronous Event. + * Defined two new bits in the SlotStatus field of the SCSI + * Enclosure Processor Request and Reply. + * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for + * both SCSI IO Error Reply and SCSI Task Management Reply. + * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. + * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_INIT_H +#define MPI2_INIT_H + +/***************************************************************************** +* +* SCSI Initiator Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SCSI IO messages and associated structures +****************************************************************************/ + +typedef struct +{ + U8 CDB[20]; /* 0x00 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, + Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; + +/* TBD: I don't think this is needed for MPI2/Gen2 */ +#if 0 +typedef struct +{ + U8 CDB[16]; /* 0x00 */ + U32 DataLength; /* 0x10 */ + U32 PrimaryReferenceTag; /* 0x14 */ + U16 PrimaryApplicationTag; /* 0x18 */ + U16 PrimaryApplicationTagMask; /* 0x1A */ + U32 TransferLength; /* 0x1C */ +} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16, + Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t; +#endif + +typedef union +{ + U8 CDB32[32]; + MPI2_SCSI_IO_CDB_EEDP32 EEDP32; + MPI2_SGE_SIMPLE_UNION SGE; +} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, + Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; + +/* SCSI IO Request Message */ +typedef struct _MPI2_SCSI_IO_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U32 SenseBufferLowAddress; /* 0x0C */ + U16 SGLFlags; /* 0x10 */ + U8 SenseBufferLength; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U32 EEDPBlockSize; /* 0x28 */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U8 LUN[8]; /* 0x34 */ + U32 Control; /* 0x3C */ + MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ + MPI2_SGE_IO_UNION SGL; /* 0x60 */ +} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, + Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; + +/* SCSI IO MsgFlags bits */ + +/* MsgFlags for SenseBufferAddressSpace */ +#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) +#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) +#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) +#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) + +/* SCSI IO SGLFlags bits */ + +/* base values for Data Location Address Space */ +#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) + +/* base values for Type */ +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) +#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) + +/* shift values for each sub-field */ +#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) +#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) +#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) +#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) + +/* SCSI IO IoFlags bits */ + +/* Large CDB Address Space */ +#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) +#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) +#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) +#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) + +#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) +#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) +#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) +#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) + +/* SCSI IO EEDPFlags bits */ + +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) +#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + +/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ + +/* SCSI IO Control bits */ +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) +#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) +#define MPI2_SCSIIO_CONTROL_READ (0x02000000) +#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) +#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) + +#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) +#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) +#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) +#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) + +#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) +#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) +#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) +#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) + + +/* SCSI IO Error Reply Message */ +typedef struct _MPI2_SCSI_IO_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 SCSIStatus; /* 0x0C */ + U8 SCSIState; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferCount; /* 0x14 */ + U32 SenseCount; /* 0x18 */ + U32 ResponseInfo; /* 0x1C */ + U16 TaskTag; /* 0x20 */ + U16 Reserved4; /* 0x22 */ + U32 BidirectionalTransferCount; /* 0x24 */ + U32 Reserved5; /* 0x28 */ + U32 Reserved6; /* 0x2C */ +} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY, + Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t; + +/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ + +#define MPI2_SCSI_STATUS_GOOD (0x00) +#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) +#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) +#define MPI2_SCSI_STATUS_BUSY (0x08) +#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) +#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) +#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) +#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */ +#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) +#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) + +/* SCSI IO Reply SCSIState flags */ + +#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) +#define MPI2_SCSI_STATE_TERMINATED (0x08) +#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) +#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) +#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) + +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) + +#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) + + +/**************************************************************************** +* SCSI Task Management messages +****************************************************************************/ + +/* SCSI Task Management Request Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved1; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U8 LUN[8]; /* 0x0C */ + U32 Reserved4[7]; /* 0x14 */ + U16 TaskMID; /* 0x30 */ + U16 Reserved5; /* 0x32 */ +} MPI2_SCSI_TASK_MANAGE_REQUEST, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, + Mpi2SCSITaskManagementRequest_t, + MPI2_POINTER pMpi2SCSITaskManagementRequest_t; + +/* TaskType values */ + +#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) +#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) +#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) +#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) +#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) + +/* obsolete TaskType name */ +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) + +/* MsgFlags bits */ + +#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) +#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) +#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) +#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) + +#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) + + + +/* SCSI Task Management Reply Message */ +typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 ResponseCode; /* 0x04 */ + U8 TaskType; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TerminationCount; /* 0x14 */ + U32 ResponseInfo; /* 0x18 */ +} MPI2_SCSI_TASK_MANAGE_REPLY, + MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, + Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; + +/* ResponseCode values */ + +#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) +#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) +#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) +#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) +#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) +#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) +#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) +#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) + +/* masks and shifts for the ResponseInfo field */ + +#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) +#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) +#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) +#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) + + +/**************************************************************************** +* SCSI Enclosure Processor messages +****************************************************************************/ + +/* SCSI Enclosure Processor Request Message */ +typedef struct _MPI2_SEP_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 SlotStatus; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST, + Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t; + +/* Action defines */ +#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) +#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) + +/* Flags defines */ +#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) +#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) + +/* SlotStatus defines */ +#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) +#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) + + +/* SCSI Enclosure Processor Reply Message */ +typedef struct _MPI2_SEP_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Action; /* 0x04 */ + U8 Flags; /* 0x05 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 SlotStatus; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U16 Slot; /* 0x1C */ + U16 EnclosureHandle; /* 0x1E */ +} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY, + Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t; + +/* SlotStatus defines */ +#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) +#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) +#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) +#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) +#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) +#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) +#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) + + +#endif + + diff --git a/sys/dev/mps/mpi/mpi2_ioc.h b/sys/dev/mps/mpi/mpi2_ioc.h new file mode 100644 index 00000000000..24a56625ef3 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_ioc.h @@ -0,0 +1,1414 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_ioc.h + * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages + * Creation Date: October 11, 2006 + * + * mpi2_ioc.h Version: 02.00.13 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to + * MaxTargets. + * Added TotalImageSize field to FWDownload Request. + * Added reserved words to FWUpload Request. + * 06-26-07 02.00.02 Added IR Configuration Change List Event. + * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit + * request and replaced it with + * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + * Replaced the MinReplyQueueDepth field of the IOCFacts + * reply with MaxReplyDescriptorPostQueueDepth. + * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + * depth for the Reply Descriptor Post Queue. + * Added SASAddress field to Initiator Device Table + * Overflow Event data. + * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + * for SAS Initiator Device Status Change Event data. + * Modified Reason Code defines for SAS Topology Change + * List Event data, including adding a bit for PHY Vacant + * status, and adding a mask for the Reason Code. + * Added define for + * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of + * the IOCFacts Reply. + * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Moved MPI2_VERSION_UNION to mpi2.h. + * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + * instead of enables, and added SASBroadcastPrimitiveMasks + * field. + * Added Log Entry Added Event and related structure. + * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + * Added MaxVolumes and MaxPersistentEntries fields to + * IOCFacts reply. + * Added ProtocalFlags and IOCCapabilities fields to + * MPI2_FW_IMAGE_HEADER. + * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + * a U16 (from a U32). + * Removed extra 's' from EventMasks name. + * 06-27-08 02.00.08 Fixed an offset in a comment. + * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + * renamed MinReplyFrameSize to ReplyFrameSize. + * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + * Added two new RAIDOperation values for Integrated RAID + * Operations Status Event data. + * Added four new IR Configuration Change List Event data + * ReasonCode values. + * Added two new ReasonCode defines for SAS Device Status + * Change Event data. + * Added three new DiscoveryStatus bits for the SAS + * Discovery event data. + * Added Multiplexing Status Change bit to the PhyStatus + * field of the SAS Topology Change List event data. + * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + * BootFlags are now product-specific. + * Added defines for the indivdual signature bytes + * for MPI2_INIT_IMAGE_FOOTER. + * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + * define. + * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + * define. + * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + * Added two new reason codes for SAS Device Status Change + * Event. + * Added new event: SAS PHY Counter. + * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. + * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + * Added new product id family for 2208. + * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. + * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. + * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. + * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. + * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. + * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. + * Added Host Based Discovery Phy Event data. + * Added defines for ProductID Product field + * (MPI2_FW_HEADER_PID_). + * Modified values for SAS ProductID Family + * (MPI2_FW_HEADER_PID_FAMILY_). + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_IOC_H +#define MPI2_IOC_H + +/***************************************************************************** +* +* IOC Messages +* +*****************************************************************************/ + +/**************************************************************************** +* IOCInit message +****************************************************************************/ + +/* IOCInit Request message */ +typedef struct _MPI2_IOC_INIT_REQUEST +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 MsgVersion; /* 0x0C */ + U16 HeaderVersion; /* 0x0E */ + U32 Reserved5; /* 0x10 */ + U16 Reserved6; /* 0x14 */ + U8 Reserved7; /* 0x16 */ + U8 HostMSIxVectors; /* 0x17 */ + U16 Reserved8; /* 0x18 */ + U16 SystemRequestFrameSize; /* 0x1A */ + U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ + U16 ReplyFreeQueueDepth; /* 0x1E */ + U32 SenseBufferAddressHigh; /* 0x20 */ + U32 SystemReplyAddressHigh; /* 0x24 */ + U64 SystemRequestFrameBaseAddress; /* 0x28 */ + U64 ReplyDescriptorPostQueueAddress;/* 0x30 */ + U64 ReplyFreeQueueAddress; /* 0x38 */ + U64 TimeStamp; /* 0x40 */ +} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, + Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; + +/* WhoInit values */ +#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) +#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI2_WHOINIT_ROM_BIOS (0x02) +#define MPI2_WHOINIT_PCI_PEER (0x03) +#define MPI2_WHOINIT_HOST_DRIVER (0x04) +#define MPI2_WHOINIT_MANUFACTURER (0x05) + +/* MsgVersion */ +#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) + +/* minimum depth for the Reply Descriptor Post Queue */ +#define MPI2_RDPQ_DEPTH_MIN (16) + + +/* IOCInit Reply message */ +typedef struct _MPI2_IOC_INIT_REPLY +{ + U8 WhoInit; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY, + Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t; + + +/**************************************************************************** +* IOCFacts message +****************************************************************************/ + +/* IOCFacts Request message */ +typedef struct _MPI2_IOC_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST, + Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t; + + +/* IOCFacts Reply message */ +typedef struct _MPI2_IOC_FACTS_REPLY +{ + U16 MsgVersion; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 HeaderVersion; /* 0x04 */ + U8 IOCNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U16 IOCExceptions; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 MaxChainDepth; /* 0x14 */ + U8 WhoInit; /* 0x15 */ + U8 NumberOfPorts; /* 0x16 */ + U8 MaxMSIxVectors; /* 0x17 */ + U16 RequestCredit; /* 0x18 */ + U16 ProductID; /* 0x1A */ + U32 IOCCapabilities; /* 0x1C */ + MPI2_VERSION_UNION FWVersion; /* 0x20 */ + U16 IOCRequestFrameSize; /* 0x24 */ + U16 Reserved3; /* 0x26 */ + U16 MaxInitiators; /* 0x28 */ + U16 MaxTargets; /* 0x2A */ + U16 MaxSasExpanders; /* 0x2C */ + U16 MaxEnclosures; /* 0x2E */ + U16 ProtocolFlags; /* 0x30 */ + U16 HighPriorityCredit; /* 0x32 */ + U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */ + U8 ReplyFrameSize; /* 0x36 */ + U8 MaxVolumes; /* 0x37 */ + U16 MaxDevHandle; /* 0x38 */ + U16 MaxPersistentEntries; /* 0x3A */ + U16 MinDevHandle; /* 0x3C */ + U16 Reserved4; /* 0x3E */ +} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, + Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; + +/* MsgVersion */ +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) +#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) +#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) + +/* HeaderVersion */ +#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) +#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) +#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) +#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) + +/* IOCExceptions */ +#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) + +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) +#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) + +#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) +#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) +#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) + +/* defines for WhoInit field are after the IOCInit Request */ + +/* ProductID field uses MPI2_FW_HEADER_PID_ */ + +/* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) +#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) +#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) +#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) +#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) +#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) +#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) +#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) +#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) + +/* ProtocolFlags */ +#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) +#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) + + +/**************************************************************************** +* PortFacts message +****************************************************************************/ + +/* PortFacts Request message */ +typedef struct _MPI2_PORT_FACTS_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ +} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST, + Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t; + +/* PortFacts Reply message */ +typedef struct _MPI2_PORT_FACTS_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 PortNumber; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 Reserved5; /* 0x14 */ + U8 PortType; /* 0x15 */ + U16 Reserved6; /* 0x16 */ + U16 MaxPostedCmdBuffers; /* 0x18 */ + U16 Reserved7; /* 0x1A */ +} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY, + Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t; + +/* PortType values */ +#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) +#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) +#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) + + +/**************************************************************************** +* PortEnable message +****************************************************************************/ + +/* PortEnable Request message */ +typedef struct _MPI2_PORT_ENABLE_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST, + Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t; + + +/* PortEnable Reply message */ +typedef struct _MPI2_PORT_ENABLE_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U8 Reserved2; /* 0x04 */ + U8 PortFlags; /* 0x05 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY, + Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t; + + +/**************************************************************************** +* EventNotification message +****************************************************************************/ + +/* EventNotification Request message */ +#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) + +typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ + U16 SASBroadcastPrimitiveMasks; /* 0x24 */ + U16 Reserved7; /* 0x26 */ + U32 Reserved8; /* 0x28 */ +} MPI2_EVENT_NOTIFICATION_REQUEST, + MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, + Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t; + + +/* EventNotification Reply message */ +typedef struct _MPI2_EVENT_NOTIFICATION_REPLY +{ + U16 EventDataLength; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 AckRequired; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 Event; /* 0x14 */ + U16 Reserved4; /* 0x16 */ + U32 EventContext; /* 0x18 */ + U32 EventData[1]; /* 0x1C */ +} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY, + Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t; + +/* AckRequired */ +#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) +#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) + +/* Event */ +#define MPI2_EVENT_LOG_DATA (0x0001) +#define MPI2_EVENT_STATE_CHANGE (0x0002) +#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) +#define MPI2_EVENT_EVENT_CHANGE (0x000A) +#define MPI2_EVENT_TASK_SET_FULL (0x000E) +#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) +#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) +#define MPI2_EVENT_SAS_DISCOVERY (0x0016) +#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) +#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) +#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) +#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) +#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) +#define MPI2_EVENT_IR_VOLUME (0x001E) +#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) +#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) +#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) +#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) +#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) +#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) + + +/* Log Entry Added Event data */ + +/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ +#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) + +typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U16 LogSequence; /* 0x0C */ + U16 LogEntryQualifier; /* 0x0E */ + U8 VP_ID; /* 0x10 */ + U8 VF_ID; /* 0x11 */ + U16 Reserved2; /* 0x12 */ + U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */ +} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, + Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; + +/* GPIO Interrupt Event data */ + +typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT +{ + U8 GPIONum; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_GPIO_INTERRUPT, + MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, + Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; + +/* Hard Reset Received Event data */ + +typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED +{ + U8 Reserved1; /* 0x00 */ + U8 Port; /* 0x01 */ + U16 Reserved2; /* 0x02 */ +} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, + Mpi2EventDataHardResetReceived_t, + MPI2_POINTER pMpi2EventDataHardResetReceived_t; + +/* Task Set Full Event data */ + +typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL +{ + U16 DevHandle; /* 0x00 */ + U16 CurrentDepth; /* 0x02 */ +} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL, + Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t; + + +/* SAS Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U16 TaskTag; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U8 ASC; /* 0x04 */ + U8 ASCQ; /* 0x05 */ + U16 DevHandle; /* 0x06 */ + U32 Reserved2; /* 0x08 */ + U64 SASAddress; /* 0x0C */ + U8 LUN[8]; /* 0x14 */ +} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + Mpi2EventDataSasDeviceStatusChange_t, + MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t; + +/* SAS Device Status Change Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) +#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) + + +/* Integrated RAID Operation Status Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS +{ + U16 VolDevHandle; /* 0x00 */ + U16 Reserved1; /* 0x02 */ + U8 RAIDOperation; /* 0x04 */ + U8 PercentComplete; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U32 Resereved3; /* 0x08 */ +} MPI2_EVENT_DATA_IR_OPERATION_STATUS, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, + Mpi2EventDataIrOperationStatus_t, + MPI2_POINTER pMpi2EventDataIrOperationStatus_t; + +/* Integrated RAID Operation Status Event data RAIDOperation values */ +#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) +#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) +#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) +#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) + + +/* Integrated RAID Volume Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_VOLUME +{ + U16 VolDevHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 NewValue; /* 0x04 */ + U32 PreviousValue; /* 0x08 */ +} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME, + Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t; + +/* Integrated RAID Volume Event data ReasonCode values */ +#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Physical Disk Event data */ + +typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK +{ + U16 Reserved1; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysDiskNum; /* 0x03 */ + U16 PhysDiskDevHandle; /* 0x04 */ + U16 Reserved2; /* 0x06 */ + U16 Slot; /* 0x08 */ + U16 EnclosureHandle; /* 0x0A */ + U32 NewValue; /* 0x0C */ + U32 PreviousValue; /* 0x10 */ +} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, + Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t; + +/* Integrated RAID Physical Disk Event data ReasonCode values */ +#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) +#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) + + +/* Integrated RAID Configuration Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumElements at runtime. + */ +#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT +#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT +{ + U16 ElementFlags; /* 0x00 */ + U16 VolDevHandle; /* 0x02 */ + U8 ReasonCode; /* 0x04 */ + U8 PhysDiskNum; /* 0x05 */ + U16 PhysDiskDevHandle; /* 0x06 */ +} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, + Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t; + +/* IR Configuration Change List Event data ElementFlags values */ +#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) +#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) + +/* IR Configuration Change List Event data ReasonCode values */ +#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) +#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) +#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) +#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) +#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) +#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) +#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) +#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) + +typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST +{ + U8 NumElements; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 Reserved2; /* 0x02 */ + U8 ConfigNum; /* 0x03 */ + U32 Flags; /* 0x04 */ + MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */ +} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, + Mpi2EventDataIrConfigChangeList_t, + MPI2_POINTER pMpi2EventDataIrConfigChangeList_t; + +/* IR Configuration Change List Event data Flags values */ +#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) + + +/* SAS Discovery Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY +{ + U8 Flags; /* 0x00 */ + U8 ReasonCode; /* 0x01 */ + U8 PhysicalPort; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 DiscoveryStatus; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_DISCOVERY, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, + Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t; + +/* SAS Discovery Event data Flags values */ +#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) +#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) + +/* SAS Discovery Event data ReasonCode values */ +#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) + +/* SAS Discovery Event data DiscoveryStatus values */ +#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) +#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) +#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) +#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) +#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) +#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) +#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) +#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) +#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) +#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) +#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) +#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) +#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) +#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) +#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) + + +/* SAS Broadcast Primitive Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 0x00 */ + U8 Port; /* 0x01 */ + U8 PortWidth; /* 0x02 */ + U8 Primitive; /* 0x03 */ +} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + Mpi2EventDataSasBroadcastPrimitive_t, + MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t; + +/* defines for the Primitive field */ +#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) +#define MPI2_EVENT_PRIMITIVE_SES (0x02) +#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) +#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) +#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) +#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) +#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) + + +/* SAS Initiator Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U16 DevHandle; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + Mpi2EventDataSasInitDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t; + +/* SAS Initiator Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) + + +/* SAS Initiator Device Table Overflow Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U16 MaxInit; /* 0x00 */ + U16 CurrentInit; /* 0x02 */ + U64 SASAddress; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + Mpi2EventDataSasInitTableOverflow_t, + MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t; + + +/* SAS Topology Change List Event data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumEntries at runtime. + */ +#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT +#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) +#endif + +typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY +{ + U16 AttachedDevHandle; /* 0x00 */ + U8 LinkRate; /* 0x02 */ + U8 PhyStatus; /* 0x03 */ +} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, + Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t; + +typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST +{ + U16 EnclosureHandle; /* 0x00 */ + U16 ExpanderDevHandle; /* 0x02 */ + U8 NumPhys; /* 0x04 */ + U8 Reserved1; /* 0x05 */ + U16 Reserved2; /* 0x06 */ + U8 NumEntries; /* 0x08 */ + U8 StartPhyNum; /* 0x09 */ + U8 ExpStatus; /* 0x0A */ + U8 PhysicalPort; /* 0x0B */ + MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/ +} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, + Mpi2EventDataSasTopologyChangeList_t, + MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; + +/* values for the ExpStatus field */ +#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) +#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) +#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) + +/* defines for the LinkRate field */ +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) +#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) + +#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) +#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) +#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) +#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) +#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) +#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) +#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) + +/* values for the PhyStatus field */ +#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) +#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) +/* values for the PhyStatus ReasonCode sub-field */ +#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) +#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) +#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) +#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) +#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) + + +/* SAS Enclosure Device Status Change Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE +{ + U16 EnclosureHandle; /* 0x00 */ + U8 ReasonCode; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U64 EnclosureLogicalID; /* 0x04 */ + U16 NumSlots; /* 0x0C */ + U16 StartSlot; /* 0x0E */ + U32 PhyBits; /* 0x10 */ +} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, + Mpi2EventDataSasEnclDevStatusChange_t, + MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t; + +/* SAS Enclosure Device Status Change event ReasonCode values */ +#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) +#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) + + +/* SAS PHY Counter Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER +{ + U64 TimeStamp; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U8 PhyEventCode; /* 0x0C */ + U8 PhyNum; /* 0x0D */ + U16 Reserved2; /* 0x0E */ + U32 PhyEventInfo; /* 0x10 */ + U8 CounterType; /* 0x14 */ + U8 ThresholdWindow; /* 0x15 */ + U8 TimeUnits; /* 0x16 */ + U8 Reserved3; /* 0x17 */ + U32 EventThreshold; /* 0x18 */ + U16 ThresholdFlags; /* 0x1C */ + U16 Reserved4; /* 0x1E */ +} MPI2_EVENT_DATA_SAS_PHY_COUNTER, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, + Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the PhyEventCode field */ + +/* use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the CounterType field */ + +/* use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the TimeUnits field */ + +/* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */ + + +/* Host Based Discovery Phy Event data */ + +typedef struct _MPI2_EVENT_HBD_PHY_SAS +{ + U8 Flags; /* 0x00 */ + U8 NegotiatedLinkRate; /* 0x01 */ + U8 PhyNum; /* 0x02 */ + U8 PhysicalPort; /* 0x03 */ + U32 Reserved1; /* 0x04 */ + U8 InitialFrame[28]; /* 0x08 */ +} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, + Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; + +/* values for the Flags field */ +#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) +#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) + +/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for the NegotiatedLinkRate field */ + +typedef union _MPI2_EVENT_HBD_DESCRIPTOR +{ + MPI2_EVENT_HBD_PHY_SAS Sas; +} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, + Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; + +typedef struct _MPI2_EVENT_DATA_HBD_PHY +{ + U8 DescriptorType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ + MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ +} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, + Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; + +/* values for the DescriptorType field */ +#define MPI2_EVENT_HBD_DT_SAS (0x01) + + + +/**************************************************************************** +* EventAck message +****************************************************************************/ + +/* EventAck Request message */ +typedef struct _MPI2_EVENT_ACK_REQUEST +{ + U16 Reserved1; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Event; /* 0x0C */ + U16 Reserved5; /* 0x0E */ + U32 EventContext; /* 0x10 */ +} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST, + Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t; + + +/* EventAck Reply message */ +typedef struct _MPI2_EVENT_ACK_REPLY +{ + U16 Reserved1; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY, + Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t; + + +/**************************************************************************** +* FWDownload message +****************************************************************************/ + +/* FWDownload Request message */ +typedef struct _MPI2_FW_DOWNLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 TotalImageSize; /* 0x0C */ + U32 Reserved5; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST, + Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest; + +#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) + +#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) +#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) +#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + +/* FWDownload TransactionContext Element */ +typedef struct _MPI2_FW_DOWNLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE, + Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t; + +/* FWDownload Reply message */ +typedef struct _MPI2_FW_DOWNLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY, + Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t; + + +/**************************************************************************** +* FWUpload message +****************************************************************************/ + +/* FWUpload Request message */ +typedef struct _MPI2_FW_UPLOAD_REQUEST +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + MPI2_MPI_SGE_UNION SGL; /* 0x14 */ +} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST, + Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t; + +#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) +#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) +#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) +#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) +#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) +#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) +#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) +#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) + +typedef struct _MPI2_FW_UPLOAD_TCSGE +{ + U8 Reserved1; /* 0x00 */ + U8 ContextSize; /* 0x01 */ + U8 DetailsLength; /* 0x02 */ + U8 Flags; /* 0x03 */ + U32 Reserved2; /* 0x04 */ + U32 ImageOffset; /* 0x08 */ + U32 ImageSize; /* 0x0C */ +} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE, + Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t; + +/* FWUpload Reply message */ +typedef struct _MPI2_FW_UPLOAD_REPLY +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ActualImageSize; /* 0x14 */ +} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY, + Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t; + + +/* FW Image Header */ +typedef struct _MPI2_FW_IMAGE_HEADER +{ + U32 Signature; /* 0x00 */ + U32 Signature0; /* 0x04 */ + U32 Signature1; /* 0x08 */ + U32 Signature2; /* 0x0C */ + MPI2_VERSION_UNION MPIVersion; /* 0x10 */ + MPI2_VERSION_UNION FWVersion; /* 0x14 */ + MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */ + MPI2_VERSION_UNION PackageVersion; /* 0x1C */ + U16 VendorID; /* 0x20 */ + U16 ProductID; /* 0x22 */ + U16 ProtocolFlags; /* 0x24 */ + U16 Reserved26; /* 0x26 */ + U32 IOCCapabilities; /* 0x28 */ + U32 ImageSize; /* 0x2C */ + U32 NextImageHeaderOffset; /* 0x30 */ + U32 Checksum; /* 0x34 */ + U32 Reserved38; /* 0x38 */ + U32 Reserved3C; /* 0x3C */ + U32 Reserved40; /* 0x40 */ + U32 Reserved44; /* 0x44 */ + U32 Reserved48; /* 0x48 */ + U32 Reserved4C; /* 0x4C */ + U32 Reserved50; /* 0x50 */ + U32 Reserved54; /* 0x54 */ + U32 Reserved58; /* 0x58 */ + U32 Reserved5C; /* 0x5C */ + U32 Reserved60; /* 0x60 */ + U32 FirmwareVersionNameWhat; /* 0x64 */ + U8 FirmwareVersionName[32]; /* 0x68 */ + U32 VendorNameWhat; /* 0x88 */ + U8 VendorName[32]; /* 0x8C */ + U32 PackageNameWhat; /* 0x88 */ + U8 PackageName[32]; /* 0x8C */ + U32 ReservedD0; /* 0xD0 */ + U32 ReservedD4; /* 0xD4 */ + U32 ReservedD8; /* 0xD8 */ + U32 ReservedDC; /* 0xDC */ + U32 ReservedE0; /* 0xE0 */ + U32 ReservedE4; /* 0xE4 */ + U32 ReservedE8; /* 0xE8 */ + U32 ReservedEC; /* 0xEC */ + U32 ReservedF0; /* 0xF0 */ + U32 ReservedF4; /* 0xF4 */ + U32 ReservedF8; /* 0xF8 */ + U32 ReservedFC; /* 0xFC */ +} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER, + Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t; + +/* Signature field */ +#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) +#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) +#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) + +/* Signature0 field */ +#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) +#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) + +/* Signature1 field */ +#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) +#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) + +/* Signature2 field */ +#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) +#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) + + +/* defines for using the ProductID field */ +#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) +#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) + +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_A (0x0000) +#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) +#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) +#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) + + +#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SAS */ +#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) +#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) + +/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ + +/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ + + +#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) +#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) +#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) + +#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) + +#define MPI2_FW_HEADER_SIZE (0x100) + + +/* Extended Image Header */ +typedef struct _MPI2_EXT_IMAGE_HEADER + +{ + U8 ImageType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Checksum; /* 0x04 */ + U32 ImageSize; /* 0x08 */ + U32 NextImageHeaderOffset; /* 0x0C */ + U32 PackageVersion; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U32 Reserved4; /* 0x18 */ + U32 Reserved5; /* 0x1C */ + U8 IdentifyString[32]; /* 0x20 */ +} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER, + Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t; + +/* useful offsets */ +#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) +#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) +#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) + +#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) + +/* defines for the ImageType field */ +#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) +#define MPI2_EXT_IMAGE_TYPE_FW (0x01) +#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) +#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) +#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) +#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) + +#define MPI2_EXT_IMAGE_TYPE_MAX (MPI2_EXT_IMAGE_TYPE_MEGARAID) + + + +/* FLASH Layout Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check RegionsPerLayout at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_REGIONS +#define MPI2_FLASH_NUMBER_OF_REGIONS (1) +#endif + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfLayouts at runtime. + */ +#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS +#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) +#endif + +typedef struct _MPI2_FLASH_REGION +{ + U8 RegionType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 RegionOffset; /* 0x04 */ + U32 RegionSize; /* 0x08 */ + U32 Reserved3; /* 0x0C */ +} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION, + Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t; + +typedef struct _MPI2_FLASH_LAYOUT +{ + U32 FlashSize; /* 0x00 */ + U32 Reserved1; /* 0x04 */ + U32 Reserved2; /* 0x08 */ + U32 Reserved3; /* 0x0C */ + MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */ +} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT, + Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t; + +typedef struct _MPI2_FLASH_LAYOUT_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 SizeOfRegion; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U16 NumberOfLayouts; /* 0x04 */ + U16 RegionsPerLayout; /* 0x06 */ + U16 MinimumSectorAlignment; /* 0x08 */ + U16 Reserved3; /* 0x0A */ + U32 Reserved4; /* 0x0C */ + MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */ +} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA, + Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t; + +/* defines for the RegionType field */ +#define MPI2_FLASH_REGION_UNUSED (0x00) +#define MPI2_FLASH_REGION_FIRMWARE (0x01) +#define MPI2_FLASH_REGION_BIOS (0x02) +#define MPI2_FLASH_REGION_NVDATA (0x03) +#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) +#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) +#define MPI2_FLASH_REGION_CONFIG_1 (0x07) +#define MPI2_FLASH_REGION_CONFIG_2 (0x08) +#define MPI2_FLASH_REGION_MEGARAID (0x09) +#define MPI2_FLASH_REGION_INIT (0x0A) + +/* ImageRevision */ +#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) + + + +/* Supported Devices Extended Image Data */ + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumberOfDevices at runtime. + */ +#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES +#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) +#endif + +typedef struct _MPI2_SUPPORTED_DEVICE +{ + U16 DeviceID; /* 0x00 */ + U16 VendorID; /* 0x02 */ + U16 DeviceIDMask; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U8 LowPCIRev; /* 0x08 */ + U8 HighPCIRev; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ +} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE, + Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t; + +typedef struct _MPI2_SUPPORTED_DEVICES_DATA +{ + U8 ImageRevision; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 NumberOfDevices; /* 0x02 */ + U8 Reserved2; /* 0x03 */ + U32 Reserved3; /* 0x04 */ + MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */ +} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA, + Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t; + +/* ImageRevision */ +#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) + + +/* Init Extended Image Data */ + +typedef struct _MPI2_INIT_IMAGE_FOOTER + +{ + U32 BootFlags; /* 0x00 */ + U32 ImageSize; /* 0x04 */ + U32 Signature0; /* 0x08 */ + U32 Signature1; /* 0x0C */ + U32 Signature2; /* 0x10 */ + U32 ResetVector; /* 0x14 */ +} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER, + Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t; + +/* defines for the BootFlags field */ +#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) + +/* defines for the ImageSize field */ +#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) + +/* defines for the Signature0 field */ +#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) +#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) + +/* defines for the Signature1 field */ +#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) +#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) + +/* defines for the Signature2 field */ +#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) +#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) + +/* Signature fields as individual bytes */ +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) + +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) +#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) + +/* defines for the ResetVector field */ +#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_ra.h b/sys/dev/mps/mpi/mpi2_ra.h new file mode 100644 index 00000000000..18b0b3d8015 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_ra.h @@ -0,0 +1,86 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2009 LSI Corporation. + * + * + * Name: mpi2_ra.h + * Title: MPI RAID Accelerator messages and structures + * Creation Date: April 13, 2009 + * + * mpi2_ra.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 05-06-09 02.00.00 Initial version. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RA_H +#define MPI2_RA_H + +/* generic structure for RAID Accelerator Control Block */ +typedef struct _MPI2_RAID_ACCELERATOR_CONTROL_BLOCK +{ + U32 Reserved[8]; /* 0x00 */ + U32 RaidAcceleratorCDB[1]; /* 0x20 */ +} MPI2_RAID_ACCELERATOR_CONTROL_BLOCK, + MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_CONTROL_BLOCK, + Mpi2RAIDAcceleratorControlBlock_t, + MPI2_POINTER pMpi2RAIDAcceleratorControlBlock_t; + + +/****************************************************************************** +* +* RAID Accelerator Messages +* +*******************************************************************************/ + +/* RAID Accelerator Request Message */ +typedef struct _MPI2_RAID_ACCELERATOR_REQUEST +{ + U16 Reserved0; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U64 RaidAcceleratorControlBlockAddress; /* 0x0C */ + U8 DmaEngineNumber; /* 0x14 */ + U8 Reserved4; /* 0x15 */ + U16 Reserved5; /* 0x16 */ + U32 Reserved6; /* 0x18 */ + U32 Reserved7; /* 0x1C */ + U32 Reserved8; /* 0x20 */ +} MPI2_RAID_ACCELERATOR_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REQUEST, + Mpi2RAIDAcceleratorRequest_t, MPI2_POINTER pMpi2RAIDAcceleratorRequest_t; + + +/* RAID Accelerator Error Reply Message */ +typedef struct _MPI2_RAID_ACCELERATOR_REPLY +{ + U16 Reserved0; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ProductSpecificData[3]; /* 0x14 */ +} MPI2_RAID_ACCELERATOR_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_REPLY, + Mpi2RAIDAcceleratorReply_t, MPI2_POINTER pMpi2RAIDAcceleratorReply_t; + + +#endif + + diff --git a/sys/dev/mps/mpi/mpi2_raid.h b/sys/dev/mps/mpi/mpi2_raid.h new file mode 100644 index 00000000000..f65302817ce --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_raid.h @@ -0,0 +1,302 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi2_raid.h + * Title: MPI Integrated RAID messages and structures + * Creation Date: April 26, 2007 + * + * mpi2_raid.h Version: 02.00.04 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Modifications to RAID Action request and reply, + * including the Actions and ActionData. + * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + * can be sized by the build environment. + * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of + * VolumeCreationFlags and marked the old one as obsolete. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_RAID_H +#define MPI2_RAID_H + +/***************************************************************************** +* +* Integrated RAID Messages +* +*****************************************************************************/ + +/**************************************************************************** +* RAID Action messages +****************************************************************************/ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ +#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) +#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ +#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) + +/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ +typedef struct _MPI2_RAID_ACTION_RATE_DATA +{ + U8 RateToChange; /* 0x00 */ + U8 RateOrMode; /* 0x01 */ + U16 DataScrubDuration; /* 0x02 */ +} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA, + Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t; + +#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) +#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) +#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) + +/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_START_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, + Mpi2RaidActionStartRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStartRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_START_NEW (0x00) +#define MPI2_RAID_ACTION_START_RESUME (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ +typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION +{ + U8 RAIDFunction; /* 0x00 */ + U8 Flags; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, + Mpi2RaidActionStopRaidFunction_t, + MPI2_POINTER pMpi2RaidActionStopRaidFunction_t; + +/* defines for the RAIDFunction field */ +#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) +#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) +#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) + +/* defines for the Flags field */ +#define MPI2_RAID_ACTION_STOP_ABORT (0x00) +#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) + +/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ +typedef struct _MPI2_RAID_ACTION_HOT_SPARE +{ + U8 HotSparePool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 DevHandle; /* 0x02 */ +} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE, + Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t; + +/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ +typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE +{ + U8 Flags; /* 0x00 */ + U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */ + U16 Reserved1; /* 0x02 */ +} MPI2_RAID_ACTION_FW_UPDATE_MODE, + MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, + Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t; + +/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ +#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) +#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) + +typedef union _MPI2_RAID_ACTION_DATA +{ + U32 Word; + MPI2_RAID_ACTION_RATE_DATA Rates; + MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; + MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; + MPI2_RAID_ACTION_HOT_SPARE HotSpare; + MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; +} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA, + Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t; + + +/* RAID Action Request Message */ +typedef struct _MPI2_RAID_ACTION_REQUEST +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */ + MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */ +} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST, + Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t; + +/* RAID Action request Action values */ + +#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) +#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) +#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) +#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) +#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) +#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) +#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) +#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) +#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) +#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) +#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) +#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) +#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) +#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) +#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) +#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) +#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) +#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) +#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) + + +/* RAID Volume Creation Structure */ + +/* + * The following define can be customized for the targeted product. + */ +#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS +#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) +#endif + +typedef struct _MPI2_RAID_VOLUME_PHYSDISK +{ + U8 RAIDSetNum; /* 0x00 */ + U8 PhysDiskMap; /* 0x01 */ + U16 PhysDiskDevHandle; /* 0x02 */ +} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK, + Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t; + +/* defines for the PhysDiskMap field */ +#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) +#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) + +typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT +{ + U8 NumPhysDisks; /* 0x00 */ + U8 VolumeType; /* 0x01 */ + U16 Reserved1; /* 0x02 */ + U32 VolumeCreationFlags; /* 0x04 */ + U32 VolumeSettings; /* 0x08 */ + U8 Reserved2; /* 0x0C */ + U8 ResyncRate; /* 0x0D */ + U16 DataScrubDuration; /* 0x0E */ + U64 VolumeMaxLBA; /* 0x10 */ + U32 StripeSize; /* 0x18 */ + U8 Name[16]; /* 0x1C */ + MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */ +} MPI2_RAID_VOLUME_CREATION_STRUCT, + MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, + Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t; + +/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ + +/* defines for the VolumeCreationFlags field */ +#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) +#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) +#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) +#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) +/* The following is an obsolete define. + * It must be shifted left 24 bits in order to set the proper bit. + */ +#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) + + +/* RAID Online Capacity Expansion Structure */ + +typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION +{ + U32 Flags; /* 0x00 */ + U16 DevHandle0; /* 0x04 */ + U16 Reserved1; /* 0x06 */ + U16 DevHandle1; /* 0x08 */ + U16 Reserved2; /* 0x0A */ +} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, + Mpi2RaidOnlineCapacityExpansion_t, + MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; + + +/* RAID Volume Indicator Structure */ + +typedef struct _MPI2_RAID_VOL_INDICATOR +{ + U64 TotalBlocks; /* 0x00 */ + U64 BlocksRemaining; /* 0x08 */ + U32 Flags; /* 0x10 */ +} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR, + Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t; + +/* defines for RAID Volume Indicator Flags field */ +#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) +#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) +#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) +#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) +#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) + + +/* RAID Action Reply ActionData union */ +typedef union _MPI2_RAID_ACTION_REPLY_DATA +{ + U32 Word[5]; + MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; + U16 VolDevHandle; + U8 VolumeState; + U8 PhysDiskNum; +} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, + Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; + +/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ + + +/* RAID Action Reply Message */ +typedef struct _MPI2_RAID_ACTION_REPLY +{ + U8 Action; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 VolDevHandle; /* 0x04 */ + U8 PhysDiskNum; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U16 Reserved3; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */ +} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY, + Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t; + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_sas.h b/sys/dev/mps/mpi/mpi2_sas.h new file mode 100644 index 00000000000..ef64a7307df --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_sas.h @@ -0,0 +1,285 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2007 LSI Corporation. + * + * + * Name: mpi2_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: February 9, 2007 + * + * mpi2.h Version: 02.00.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit + * Control Request. + * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control + * Request. + * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST + * to MPI2_SGE_IO_UNION since it supports chained SGLs. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_SAS_H +#define MPI2_SAS_H + +/* + * Values for SASStatus. + */ +#define MPI2_SASSTATUS_SUCCESS (0x00) +#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI2_SASSTATUS_INVALID_FRAME (0x02) +#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS Configuration pages. + */ +#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) +#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/***************************************************************************** +* +* SAS Messages +* +*****************************************************************************/ + +/**************************************************************************** +* SMP Passthrough messages +****************************************************************************/ + +/* SMP Passthrough Request Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 RequestDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U64 SASAddress; /* 0x10 */ + U32 Reserved3; /* 0x18 */ + U32 Reserved4; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ +} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST, + Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* SMP Passthrough Reply Message */ +typedef struct _MPI2_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 0x00 */ + U8 PhysicalPort; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 ResponseDataLength; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 Reserved3; /* 0x14 */ + U8 ResponseData[4]; /* 0x18 */ +} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY, + Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t; + +/* values for PassthroughFlags field */ +#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SATA Passthrough messages +****************************************************************************/ + +/* SATA Passthrough Request Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST +{ + U16 DevHandle; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U32 Reserved4; /* 0x14 */ + U32 DataLength; /* 0x18 */ + U8 CommandFIS[20]; /* 0x1C */ + MPI2_SGE_IO_UNION SGL; /* 0x20 */ +} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, + Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; + +/* values for PassthroughFlags field */ +#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) +#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) +#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) +#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) +#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) +#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* SATA Passthrough Reply Message */ +typedef struct _MPI2_SATA_PASSTHROUGH_REPLY +{ + U16 DevHandle; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 PassthroughFlags; /* 0x04 */ + U8 SGLFlags; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U8 Reserved2; /* 0x0C */ + U8 SASStatus; /* 0x0D */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 StatusFIS[20]; /* 0x14 */ + U32 StatusControlRegisters; /* 0x28 */ + U32 TransferCount; /* 0x2C */ +} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY, + Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t; + +/* values for SASStatus field are at the top of this file */ + + +/**************************************************************************** +* SAS IO Unit Control messages +****************************************************************************/ + +/* SAS IO Unit Control Request Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U8 PhyNum; /* 0x0E */ + U8 PrimFlags; /* 0x0F */ + U32 Primitive; /* 0x10 */ + U8 LookupMethod; /* 0x14 */ + U8 Reserved5; /* 0x15 */ + U16 SlotNumber; /* 0x16 */ + U64 LookupAddress; /* 0x18 */ + U32 IOCParameterValue; /* 0x20 */ + U32 Reserved7; /* 0x24 */ + U32 Reserved8; /* 0x28 */ +} MPI2_SAS_IOUNIT_CONTROL_REQUEST, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, + Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t; + +/* values for the Operation field */ +#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) +#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) +#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) +#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) +#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) +#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) +#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) +#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) +#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) + +/* values for the PrimFlags field */ +#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) +#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) +#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) + +/* values for the LookupMethod field */ +#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) +#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) +#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) + + +/* SAS IO Unit Control Reply Message */ +typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 DevHandle; /* 0x04 */ + U8 IOCParameter; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_SAS_IOUNIT_CONTROL_REPLY, + MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, + Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t; + + +#endif + + diff --git a/sys/dev/mps/mpi/mpi2_targ.h b/sys/dev/mps/mpi/mpi2_targ.h new file mode 100644 index 00000000000..50f38d0c2b2 --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_targ.h @@ -0,0 +1,441 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2008 LSI Corporation. + * + * + * Name: mpi2_targ.h + * Title: MPI Target mode messages and structures + * Creation Date: September 8, 2006 + * + * mpi2_targ.h Version: 02.00.03 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to + * BufferPostFlags field of CommandBufferPostBase Request. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 10-02-08 02.00.03 Removed NextCmdBufferOffset from + * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + * Target Status Send Request only takes a single SGE for + * response data. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TARG_H +#define MPI2_TARG_H + + +/****************************************************************************** +* +* SCSI Target Messages +* +*******************************************************************************/ + +/**************************************************************************** +* Target Command Buffer Post Base Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST +{ + U8 BufferPostFlags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 TotalCmdBuffers; /* 0x04 */ + U8 Reserved; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 CmdBufferLength; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U32 BaseAddressLow; /* 0x14 */ + U32 BaseAddressHigh; /* 0x18 */ +} MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST, + Mpi2TargetCmdBufferPostBaseRequest_t, + MPI2_POINTER pMpi2TargetCmdBufferPostBaseRequest_t; + +/* values for the BufferPostflags field */ +#define MPI2_CMD_BUF_POST_BASE_ADDRESS_SPACE_MASK (0x0C) +#define MPI2_CMD_BUF_POST_BASE_SYSTEM_ADDRESS_SPACE (0x00) +#define MPI2_CMD_BUF_POST_BASE_IOCDDR_ADDRESS_SPACE (0x04) +#define MPI2_CMD_BUF_POST_BASE_IOCPLB_ADDRESS_SPACE (0x08) +#define MPI2_CMD_BUF_POST_BASE_IOCPLBNTA_ADDRESS_SPACE (0x0C) + +#define MPI2_CMD_BUF_POST_BASE_FLAGS_AUTO_POST_ALL (0x01) + + +/**************************************************************************** +* Target Command Buffer Post List Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST +{ + U16 Reserved; /* 0x00 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 CmdBufferCount; /* 0x04 */ + U8 Reserved1; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved2; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 IoIndex[2]; /* 0x10 */ +} MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_CMD_BUF_POST_LIST_REQUEST, + Mpi2TargetCmdBufferPostListRequest_t, + MPI2_POINTER pMpi2TargetCmdBufferPostListRequest_t; + +/**************************************************************************** +* Target Command Buffer Post Base List Reply +****************************************************************************/ + +typedef struct _MPI2_TARGET_BUF_POST_BASE_LIST_REPLY +{ + U8 Flags; /* 0x00 */ + U8 Reserved; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 IoIndex; /* 0x14 */ + U16 Reserved5; /* 0x16 */ + U32 Reserved6; /* 0x18 */ +} MPI2_TARGET_BUF_POST_BASE_LIST_REPLY, + MPI2_POINTER PTR_MPI2_TARGET_BUF_POST_BASE_LIST_REPLY, + Mpi2TargetCmdBufferPostBaseListReply_t, + MPI2_POINTER pMpi2TargetCmdBufferPostBaseListReply_t; + +/* Flags defines */ +#define MPI2_CMD_BUF_POST_REPLY_IOINDEX_VALID (0x01) + + +/**************************************************************************** +* Command Buffer Formats (with 16 byte CDB) +****************************************************************************/ + +typedef struct _MPI2_TARGET_SSP_CMD_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved2; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + /* COMMAND information unit starts here */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U8 Reserved4; /* 0x20 */ + U8 TaskAttribute; /* lower 3 bits */ /* 0x21 */ + U8 Reserved5; /* 0x22 */ + U8 AdditionalCDBLength; /* upper 5 bits */ /* 0x23 */ + U8 CDB[16]; /* 0x24 */ + /* Additional CDB bytes extend past the CDB field */ +} MPI2_TARGET_SSP_CMD_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_CMD_BUFFER, + Mpi2TargetSspCmdBuffer, MPI2_POINTER pMp2iTargetSspCmdBuffer; + +typedef struct _MPI2_TARGET_SSP_TASK_BUFFER +{ + U8 FrameType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 InitiatorConnectionTag; /* 0x02 */ + U32 HashedSourceSASAddress; /* 0x04 */ + U16 Reserved2; /* 0x08 */ + U16 Flags; /* 0x0A */ + U32 Reserved3; /* 0x0C */ + U16 Tag; /* 0x10 */ + U16 TargetPortTransferTag; /* 0x12 */ + U32 DataOffset; /* 0x14 */ + /* TASK information unit starts here */ + U8 LogicalUnitNumber[8]; /* 0x18 */ + U16 Reserved4; /* 0x20 */ + U8 TaskManagementFunction; /* 0x22 */ + U8 Reserved5; /* 0x23 */ + U16 ManagedTaskTag; /* 0x24 */ + U16 Reserved6; /* 0x26 */ + U32 Reserved7; /* 0x28 */ + U32 Reserved8; /* 0x2C */ + U32 Reserved9; /* 0x30 */ +} MPI2_TARGET_SSP_TASK_BUFFER, MPI2_POINTER PTR_MPI2_TARGET_SSP_TASK_BUFFER, + Mpi2TargetSspTaskBuffer, MPI2_POINTER pMpi2TargetSspTaskBuffer; + +/* mask and shift for HashedSourceSASAddress field */ +#define MPI2_TARGET_HASHED_SAS_ADDRESS_MASK (0xFFFFFF00) +#define MPI2_TARGET_HASHED_SAS_ADDRESS_SHIFT (8) + + +/**************************************************************************** +* Target Assist Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_ASSIST_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 TargetAssistFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 QueueTag; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 IoIndex; /* 0x0C */ + U16 InitiatorConnectionTag; /* 0x0E */ + U16 SGLFlags; /* 0x10 */ + U8 SequenceNumber; /* 0x12 */ + U8 Reserved4; /* 0x13 */ + U8 SGLOffset0; /* 0x14 */ + U8 SGLOffset1; /* 0x15 */ + U8 SGLOffset2; /* 0x16 */ + U8 SGLOffset3; /* 0x17 */ + U32 SkipCount; /* 0x18 */ + U32 DataLength; /* 0x1C */ + U32 BidirectionalDataLength; /* 0x20 */ + U16 IoFlags; /* 0x24 */ + U16 EEDPFlags; /* 0x26 */ + U32 EEDPBlockSize; /* 0x28 */ + U32 SecondaryReferenceTag; /* 0x2C */ + U16 SecondaryApplicationTag; /* 0x30 */ + U16 ApplicationTagTranslationMask; /* 0x32 */ + U32 PrimaryReferenceTag; /* 0x34 */ + U16 PrimaryApplicationTag; /* 0x38 */ + U16 PrimaryApplicationTagMask; /* 0x3A */ + U32 RelativeOffset; /* 0x3C */ + U32 Reserved5; /* 0x40 */ + U32 Reserved6; /* 0x44 */ + U32 Reserved7; /* 0x48 */ + U32 Reserved8; /* 0x4C */ + MPI2_SGE_IO_UNION SGL[1]; /* 0x50 */ +} MPI2_TARGET_ASSIST_REQUEST, MPI2_POINTER PTR_MPI2_TARGET_ASSIST_REQUEST, + Mpi2TargetAssistRequest_t, MPI2_POINTER pMpi2TargetAssistRequest_t; + +/* Target Assist TargetAssistFlags bits */ + +#define MPI2_TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) +#define MPI2_TARGET_ASSIST_FLAGS_TLR (0x10) +#define MPI2_TARGET_ASSIST_FLAGS_RETRANSMIT (0x04) +#define MPI2_TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02) +#define MPI2_TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01) + +/* Target Assist SGLFlags bits */ + +/* base values for Data Location Address Space */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_TARGET_ASSIST_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_TARGET_ASSIST_SGLFLAGS_PLBNTA_ADDR (0x0C) + +/* base values for Type */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_TARGET_ASSIST_SGLFLAGS_MPI_TYPE (0x00) +#define MPI2_TARGET_ASSIST_SGLFLAGS_32IEEE_TYPE (0x01) +#define MPI2_TARGET_ASSIST_SGLFLAGS_64IEEE_TYPE (0x02) + +/* shift values for each sub-field */ +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL3_SHIFT (12) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL2_SHIFT (8) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL1_SHIFT (4) +#define MPI2_TARGET_ASSIST_SGLFLAGS_SGL0_SHIFT (0) + +/* Target Assist IoFlags bits */ + +#define MPI2_TARGET_ASSIST_IOFLAGS_BIDIRECTIONAL (0x0800) +#define MPI2_TARGET_ASSIST_IOFLAGS_MULTICAST (0x0400) +#define MPI2_TARGET_ASSIST_IOFLAGS_RECEIVE_FIRST (0x0200) + +/* Target Assist EEDPFlags bits */ + +#define MPI2_TA_EEDPFLAGS_INC_PRI_REFTAG (0x8000) +#define MPI2_TA_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI2_TA_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI2_TA_EEDPFLAGS_INC_SEC_APPTAG (0x1000) + +#define MPI2_TA_EEDPFLAGS_CHECK_REFTAG (0x0400) +#define MPI2_TA_EEDPFLAGS_CHECK_APPTAG (0x0200) +#define MPI2_TA_EEDPFLAGS_CHECK_GUARD (0x0100) + +#define MPI2_TA_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) + +#define MPI2_TA_EEDPFLAGS_MASK_OP (0x0007) +#define MPI2_TA_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI2_TA_EEDPFLAGS_CHECK_OP (0x0001) +#define MPI2_TA_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI2_TA_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) +#define MPI2_TA_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI2_TA_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI2_TA_EEDPFLAGS_CHECK_REGEN_OP (0x0007) + + +/**************************************************************************** +* Target Status Send Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_STATUS_SEND_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 StatusFlags; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 QueueTag; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 IoIndex; /* 0x0C */ + U16 InitiatorConnectionTag; /* 0x0E */ + U16 SGLFlags; /* 0x10 */ + U16 Reserved4; /* 0x12 */ + U8 SGLOffset0; /* 0x14 */ + U8 Reserved5; /* 0x15 */ + U16 Reserved6; /* 0x16 */ + U32 Reserved7; /* 0x18 */ + U32 Reserved8; /* 0x1C */ + MPI2_SIMPLE_SGE_UNION StatusDataSGE; /* 0x20 */ +} MPI2_TARGET_STATUS_SEND_REQUEST, + MPI2_POINTER PTR_MPI2_TARGET_STATUS_SEND_REQUEST, + Mpi2TargetStatusSendRequest_t, MPI2_POINTER pMpi2TargetStatusSendRequest_t; + +/* Target Status Send StatusFlags bits */ + +#define MPI2_TSS_FLAGS_REPOST_CMD_BUFFER (0x80) +#define MPI2_TSS_FLAGS_RETRANSMIT (0x04) +#define MPI2_TSS_FLAGS_AUTO_GOOD_STATUS (0x01) + +/* Target Status Send SGLFlags bits */ +/* Data Location Address Space */ +#define MPI2_TSS_SGLFLAGS_ADDR_MASK (0x0C) +#define MPI2_TSS_SGLFLAGS_SYSTEM_ADDR (0x00) +#define MPI2_TSS_SGLFLAGS_IOCDDR_ADDR (0x04) +#define MPI2_TSS_SGLFLAGS_IOCPLB_ADDR (0x08) +#define MPI2_TSS_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) +/* Type */ +#define MPI2_TSS_SGLFLAGS_TYPE_MASK (0x03) +#define MPI2_TSS_SGLFLAGS_MPI_TYPE (0x00) +#define MPI2_TSS_SGLFLAGS_IEEE32_TYPE (0x01) +#define MPI2_TSS_SGLFLAGS_IEEE64_TYPE (0x02) + + + +/* + * NOTE: The SSP status IU is big-endian. When used on a little-endian system, + * this structure properly orders the bytes. + */ +typedef struct _MPI2_TARGET_SSP_RSP_IU +{ + U32 Reserved0[6]; /* reserved for SSP header */ /* 0x00 */ + /* start of RESPONSE information unit */ + U32 Reserved1; /* 0x18 */ + U32 Reserved2; /* 0x1C */ + U16 Reserved3; /* 0x20 */ + U8 DataPres; /* lower 2 bits */ /* 0x22 */ + U8 Status; /* 0x23 */ + U32 Reserved4; /* 0x24 */ + U32 SenseDataLength; /* 0x28 */ + U32 ResponseDataLength; /* 0x2C */ + U8 ResponseSenseData[4]; /* 0x30 */ +} MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU, + Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t; + + +/**************************************************************************** +* Target Standard Reply - used with Target Assist or Target Status Send +****************************************************************************/ + +typedef struct _MPI2_TARGET_STANDARD_REPLY +{ + U16 Reserved; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U16 IoIndex; /* 0x14 */ + U16 Reserved5; /* 0x16 */ + U32 TransferCount; /* 0x18 */ + U32 BidirectionalTransferCount; /* 0x1C */ +} MPI2_TARGET_STANDARD_REPLY, MPI2_POINTER PTR_MPI2_TARGET_STANDARD_REPLY, + Mpi2TargetErrorReply_t, MPI2_POINTER pMpi2TargetErrorReply_t; + + +/**************************************************************************** +* Target Mode Abort Request +****************************************************************************/ + +typedef struct _MPI2_TARGET_MODE_ABORT_REQUEST +{ + U8 AbortType; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 IoIndexToAbort; /* 0x0C */ + U16 Reserved6; /* 0x0E */ + U32 MidToAbort; /* 0x10 */ +} MPI2_TARGET_MODE_ABORT, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT, + Mpi2TargetModeAbort_t, MPI2_POINTER pMpi2TargetModeAbort_t; + +/* Target Mode Abort AbortType values */ + +#define MPI2_TARGET_MODE_ABORT_ALL_CMD_BUFFERS (0x00) +#define MPI2_TARGET_MODE_ABORT_ALL_IO (0x01) +#define MPI2_TARGET_MODE_ABORT_EXACT_IO (0x02) +#define MPI2_TARGET_MODE_ABORT_EXACT_IO_REQUEST (0x03) +#define MPI2_TARGET_MODE_ABORT_IO_REQUEST_AND_IO (0x04) + + +/**************************************************************************** +* Target Mode Abort Reply +****************************************************************************/ + +typedef struct _MPI2_TARGET_MODE_ABORT_REPLY +{ + U16 Reserved; /* 0x00 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved1; /* 0x04 */ + U8 Reserved2; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved3; /* 0x0A */ + U16 Reserved4; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 AbortCount; /* 0x14 */ +} MPI2_TARGET_MODE_ABORT_REPLY, MPI2_POINTER PTR_MPI2_TARGET_MODE_ABORT_REPLY, + Mpi2TargetModeAbortReply_t, MPI2_POINTER pMpi2TargetModeAbortReply_t; + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_tool.h b/sys/dev/mps/mpi/mpi2_tool.h new file mode 100644 index 00000000000..f782507302d --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_tool.h @@ -0,0 +1,391 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2009 LSI Corporation. + * + * + * Name: mpi2_tool.h + * Title: MPI diagnostic tool structures and definitions + * Creation Date: March 26, 2007 + * + * mpi2_tool.h Version: 02.00.04 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release + * structures and defines. + * 02-29-08 02.00.02 Modified various names to make them 32-character unique. + * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. + * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request + * and reply messages. + * Added MPI2_DIAG_BUF_TYPE_EXTENDED. + * Incremented MPI2_DIAG_BUF_TYPE_COUNT. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TOOL_H +#define MPI2_TOOL_H + +/***************************************************************************** +* +* Toolbox Messages +* +*****************************************************************************/ + +/* defines for the Tools */ +#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) +#define MPI2_TOOLBOX_BEACON_TOOL (0x05) +#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) + + +/**************************************************************************** +* Toolbox reply +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY, + Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t; + + +/**************************************************************************** +* Toolbox Clean Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Flags; /* 0x0C */ + } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST, + Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) +#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) +#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) +#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) + + +/**************************************************************************** +* Toolbox Memory Move request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */ +} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, + Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t; + + +/**************************************************************************** +* Toolbox ISTWI Read Write Tool +****************************************************************************/ + +/* Toolbox ISTWI Read Write Tool request message */ +typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U32 Reserved5; /* 0x0C */ + U32 Reserved6; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 SGLFlags; /* 0x16 */ + U8 Reserved7; /* 0x17 */ + U16 TxDataLength; /* 0x18 */ + U16 RxDataLength; /* 0x1A */ + U32 Reserved8; /* 0x1C */ + U32 Reserved9; /* 0x20 */ + U32 Reserved10; /* 0x24 */ + U32 Reserved11; /* 0x28 */ + U32 Reserved12; /* 0x2C */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ +} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + Mpi2ToolboxIstwiReadWriteRequest_t, + MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; + +/* values for the Action field */ +#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) +#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) +#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) +#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) +#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) +#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Toolbox ISTWI Read Write Tool reply message */ +typedef struct _MPI2_TOOLBOX_ISTWI_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U8 DevIndex; /* 0x14 */ + U8 Action; /* 0x15 */ + U8 IstwiStatus; /* 0x16 */ + U8 Reserved6; /* 0x17 */ + U16 TxDataCount; /* 0x18 */ + U16 RxDataCount; /* 0x1A */ +} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, + Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; + + +/**************************************************************************** +* Toolbox Beacon Tool request +****************************************************************************/ + +typedef struct _MPI2_TOOLBOX_BEACON_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Reserved5; /* 0x0C */ + U8 PhysicalPort; /* 0x0D */ + U8 Reserved6; /* 0x0E */ + U8 Flags; /* 0x0F */ +} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST, + Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t; + +/* values for the Flags field */ +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) +#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) + + +/**************************************************************************** +* Toolbox Diagnostic CLI Tool +****************************************************************************/ + +#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) + +/* Toolbox Diagnostic CLI Tool request message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 SGLFlags; /* 0x0C */ + U8 Reserved5; /* 0x0D */ + U16 Reserved6; /* 0x0E */ + U32 DataLength; /* 0x10 */ + U8 DiagnosticCliCommand[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ + MPI2_SGE_SIMPLE_UNION SGL; /* 0x70 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, + Mpi2ToolboxDiagnosticCliRequest_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Toolbox Diagnostic CLI Tool reply message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY +{ + U8 Tool; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 ReturnedDataLength; /* 0x14 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, + MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, + Mpi2ToolboxDiagnosticCliReply_t, + MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; + + +/***************************************************************************** +* +* Diagnostic Buffer Messages +* +*****************************************************************************/ + + +/**************************************************************************** +* Diagnostic Buffer Post request +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST +{ + U8 ExtendedType; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U64 BufferAddress; /* 0x0C */ + U32 BufferLength; /* 0x14 */ + U32 Reserved5; /* 0x18 */ + U32 Reserved6; /* 0x1C */ + U32 Flags; /* 0x20 */ + U32 ProductSpecific[23]; /* 0x24 */ +} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, + Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; + +/* values for the ExtendedType field */ +#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) + +/* values for the BufferType field */ +#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) +/* count of the number of buffer types */ +#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_BUFFER_POST_REPLY +{ + U8 ExtendedType; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ + U32 TransferLength; /* 0x14 */ +} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY, + Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t; + + +/**************************************************************************** +* Diagnostic Release request +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ +} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST, + Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t; + + +/**************************************************************************** +* Diagnostic Buffer Post reply +****************************************************************************/ + +typedef struct _MPI2_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 0x00 */ + U8 BufferType; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY, + Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t; + + +#endif + diff --git a/sys/dev/mps/mpi/mpi2_type.h b/sys/dev/mps/mpi/mpi2_type.h new file mode 100644 index 00000000000..9effe68e28c --- /dev/null +++ b/sys/dev/mps/mpi/mpi2_type.h @@ -0,0 +1,99 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000-2007 LSI Corporation. + * + * + * Name: mpi2_type.h + * Title: MPI basic type definitions + * Creation Date: August 16, 2006 + * + * mpi2_type.h Version: 02.00.00 + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI2_TYPE_H +#define MPI2_TYPE_H + + +/******************************************************************************* + * Define MPI2_POINTER if it hasn't already been defined. By default + * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as + * a far pointer by defining MPI2_POINTER as "far *" before this header file is + * included. + */ +#ifndef MPI2_POINTER +#define MPI2_POINTER * +#endif + +/* the basic types may have already been included by mpi_type.h */ +#ifndef MPI_TYPE_H +/***************************************************************************** +* +* Basic Types +* +*****************************************************************************/ + +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; + +#ifdef __FreeBSD__ + +typedef int32_t S32; +typedef uint32_t U32; + +#else + +#if defined(unix) || defined(__arm) || defined(ALPHA) || defined(__PPC__) || defined(__ppc) + + typedef signed int S32; + typedef unsigned int U32; + +#else + + typedef signed long S32; + typedef unsigned long U32; + +#endif +#endif + +typedef struct _S64 +{ + U32 Low; + S32 High; +} S64; + +typedef struct _U64 +{ + U32 Low; + U32 High; +} U64; + + +/***************************************************************************** +* +* Pointer Types +* +*****************************************************************************/ + +typedef S8 *PS8; +typedef U8 *PU8; +typedef S16 *PS16; +typedef U16 *PU16; +typedef S32 *PS32; +typedef U32 *PU32; +typedef S64 *PS64; +typedef U64 *PU64; + +#endif + +#endif + diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c new file mode 100644 index 00000000000..404b12e1e23 --- /dev/null +++ b/sys/dev/mps/mps.c @@ -0,0 +1,1734 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* Communications core for LSI MPT2 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +static void mps_startup(void *arg); +static void mps_startup_complete(struct mps_softc *sc, struct mps_command *cm); +static int mps_send_iocinit(struct mps_softc *sc); +static int mps_attach_log(struct mps_softc *sc); +static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *reply); +static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm); +static void mps_periodic(void *); + +SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters"); + +MALLOC_DEFINE(M_MPT2, "mps", "mpt2 driver memory"); + +/* + * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of + * any state and back to its initialization state machine. + */ +static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d }; + +static int +mps_hard_reset(struct mps_softc *sc) +{ + uint32_t reg; + int i, error, tries = 0; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + /* Clear any pending interrupts */ + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* Push the magic sequence */ + error = ETIMEDOUT; + while (tries++ < 20) { + for (i = 0; i < sizeof(mpt2_reset_magic); i++) + mps_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, + mpt2_reset_magic[i]); + + DELAY(100 * 1000); + + reg = mps_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); + if (reg & MPI2_DIAG_DIAG_WRITE_ENABLE) { + error = 0; + break; + } + } + if (error) + return (error); + + /* Send the actual reset. XXX need to refresh the reg? */ + mps_regwrite(sc, MPI2_HOST_DIAGNOSTIC_OFFSET, + reg | MPI2_DIAG_RESET_ADAPTER); + + /* Wait up to 300 seconds in 50ms intervals */ + error = ETIMEDOUT; + for (i = 0; i < 60000; i++) { + DELAY(50000); + reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); + if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) { + error = 0; + break; + } + } + if (error) + return (error); + + mps_regwrite(sc, MPI2_WRITE_SEQUENCE_OFFSET, 0x0); + + return (0); +} + +static int +mps_soft_reset(struct mps_softc *sc) +{ + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + mps_regwrite(sc, MPI2_DOORBELL_OFFSET, + MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET << + MPI2_DOORBELL_FUNCTION_SHIFT); + DELAY(50000); + + return (0); +} + +static int +mps_transition_ready(struct mps_softc *sc) +{ + uint32_t reg, state; + int error, tries = 0; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + error = 0; + while (tries++ < 5) { + reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); + mps_dprint(sc, MPS_INFO, "Doorbell= 0x%x\n", reg); + + /* + * Ensure the IOC is ready to talk. If it's not, try + * resetting it. + */ + if (reg & MPI2_DOORBELL_USED) { + mps_hard_reset(sc); + DELAY(50000); + continue; + } + + /* Is the adapter owned by another peer? */ + if ((reg & MPI2_DOORBELL_WHO_INIT_MASK) == + (MPI2_WHOINIT_PCI_PEER << MPI2_DOORBELL_WHO_INIT_SHIFT)) { + device_printf(sc->mps_dev, "IOC is under the control " + "of another peer host, aborting initialization.\n"); + return (ENXIO); + } + + state = reg & MPI2_IOC_STATE_MASK; + if (state == MPI2_IOC_STATE_READY) { + /* Ready to go! */ + error = 0; + break; + } else if (state == MPI2_IOC_STATE_FAULT) { + mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n", + state & MPI2_DOORBELL_FAULT_CODE_MASK); + mps_hard_reset(sc); + } else if (state == MPI2_IOC_STATE_OPERATIONAL) { + /* Need to take ownership */ + mps_soft_reset(sc); + } else if (state == MPI2_IOC_STATE_RESET) { + /* Wait a bit, IOC might be in transition */ + mps_dprint(sc, MPS_FAULT, + "IOC in unexpected reset state\n"); + } else { + mps_dprint(sc, MPS_FAULT, + "IOC in unknown state 0x%x\n", state); + error = EINVAL; + break; + } + + /* Wait 50ms for things to settle down. */ + DELAY(50000); + } + + if (error) + device_printf(sc->mps_dev, "Cannot transition IOC to ready\n"); + + return (error); +} + +static int +mps_transition_operational(struct mps_softc *sc) +{ + uint32_t reg, state; + int error; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + error = 0; + reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); + mps_dprint(sc, MPS_INFO, "Doorbell= 0x%x\n", reg); + + state = reg & MPI2_IOC_STATE_MASK; + if (state != MPI2_IOC_STATE_READY) { + if ((error = mps_transition_ready(sc)) != 0) + return (error); + } + + error = mps_send_iocinit(sc); + return (error); +} + +/* Wait for the chip to ACK a word that we've put into its FIFO */ +static int +mps_wait_db_ack(struct mps_softc *sc) +{ + int retry; + + for (retry = 0; retry < MPS_DB_MAX_WAIT; retry++) { + if ((mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) & + MPI2_HIS_SYS2IOC_DB_STATUS) == 0) + return (0); + DELAY(2000); + } + return (ETIMEDOUT); +} + +/* Wait for the chip to signal that the next word in its FIFO can be fetched */ +static int +mps_wait_db_int(struct mps_softc *sc) +{ + int retry; + + for (retry = 0; retry < MPS_DB_MAX_WAIT; retry++) { + if ((mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET) & + MPI2_HIS_IOC2SYS_DB_STATUS) != 0) + return (0); + DELAY(2000); + } + return (ETIMEDOUT); +} + +/* Step through the synchronous command state machine, i.e. "Doorbell mode" */ +static int +mps_request_sync(struct mps_softc *sc, void *req, MPI2_DEFAULT_REPLY *reply, + int req_sz, int reply_sz, int timeout) +{ + uint32_t *data32; + uint16_t *data16; + int i, count, ioc_sz, residual; + + /* Step 1 */ + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* Step 2 */ + if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) + return (EBUSY); + + /* Step 3 + * Announce that a message is coming through the doorbell. Messages + * are pushed at 32bit words, so round up if needed. + */ + count = (req_sz + 3) / 4; + mps_regwrite(sc, MPI2_DOORBELL_OFFSET, + (MPI2_FUNCTION_HANDSHAKE << MPI2_DOORBELL_FUNCTION_SHIFT) | + (count << MPI2_DOORBELL_ADD_DWORDS_SHIFT)); + + /* Step 4 */ + if (mps_wait_db_int(sc) || + (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) == 0) { + mps_dprint(sc, MPS_FAULT, "Doorbell failed to activate\n"); + return (ENXIO); + } + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + if (mps_wait_db_ack(sc) != 0) { + mps_dprint(sc, MPS_FAULT, "Doorbell handshake failed\n"); + return (ENXIO); + } + + /* Step 5 */ + /* Clock out the message data synchronously in 32-bit dwords*/ + data32 = (uint32_t *)req; + for (i = 0; i < count; i++) { + mps_regwrite(sc, MPI2_DOORBELL_OFFSET, data32[i]); + if (mps_wait_db_ack(sc) != 0) { + mps_dprint(sc, MPS_FAULT, + "Timeout while writing doorbell\n"); + return (ENXIO); + } + } + + /* Step 6 */ + /* Clock in the reply in 16-bit words. The total length of the + * message is always in the 4th byte, so clock out the first 2 words + * manually, then loop the rest. + */ + data16 = (uint16_t *)reply; + if (mps_wait_db_int(sc) != 0) { + mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 0\n"); + return (ENXIO); + } + data16[0] = + mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + if (mps_wait_db_int(sc) != 0) { + mps_dprint(sc, MPS_FAULT, "Timeout reading doorbell 1\n"); + return (ENXIO); + } + data16[1] = + mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_DATA_MASK; + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + /* Number of 32bit words in the message */ + ioc_sz = reply->MsgLength; + + /* + * Figure out how many 16bit words to clock in without overrunning. + * The precision loss with dividing reply_sz can safely be + * ignored because the messages can only be multiples of 32bits. + */ + residual = 0; + count = MIN((reply_sz / 4), ioc_sz) * 2; + if (count < ioc_sz * 2) { + residual = ioc_sz * 2 - count; + mps_dprint(sc, MPS_FAULT, "Driver error, throwing away %d " + "residual message words\n", residual); + } + + for (i = 2; i < count; i++) { + if (mps_wait_db_int(sc) != 0) { + mps_dprint(sc, MPS_FAULT, + "Timeout reading doorbell %d\n", i); + return (ENXIO); + } + data16[i] = mps_regread(sc, MPI2_DOORBELL_OFFSET) & + MPI2_DOORBELL_DATA_MASK; + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + } + + /* + * Pull out residual words that won't fit into the provided buffer. + * This keeps the chip from hanging due to a driver programming + * error. + */ + while (residual--) { + if (mps_wait_db_int(sc) != 0) { + mps_dprint(sc, MPS_FAULT, + "Timeout reading doorbell\n"); + return (ENXIO); + } + (void)mps_regread(sc, MPI2_DOORBELL_OFFSET); + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + } + + /* Step 7 */ + if (mps_wait_db_int(sc) != 0) { + mps_dprint(sc, MPS_FAULT, "Timeout waiting to exit doorbell\n"); + return (ENXIO); + } + if (mps_regread(sc, MPI2_DOORBELL_OFFSET) & MPI2_DOORBELL_USED) + mps_dprint(sc, MPS_FAULT, "Warning, doorbell still active\n"); + mps_regwrite(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET, 0x0); + + return (0); +} + +void +mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm) +{ + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET, + cm->cm_desc.Words.Low); + mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET, + cm->cm_desc.Words.High); +} + +int +mps_request_polled(struct mps_softc *sc, struct mps_command *cm) +{ + int error, timeout = 0; + + error = 0; + + cm->cm_flags |= MPS_CM_FLAGS_POLLED; + cm->cm_complete = NULL; + mps_map_command(sc, cm); + + while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { + mps_intr(sc); + DELAY(50 * 1000); + if (timeout++ > 1000) { + mps_dprint(sc, MPS_FAULT, "polling failed\n"); + error = ETIMEDOUT; + break; + } + } + + return (error); +} + +/* + * Just the FACTS, ma'am. + */ +static int +mps_get_iocfacts(struct mps_softc *sc, MPI2_IOC_FACTS_REPLY *facts) +{ + MPI2_DEFAULT_REPLY *reply; + MPI2_IOC_FACTS_REQUEST request; + int error, req_sz, reply_sz; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + req_sz = sizeof(MPI2_IOC_FACTS_REQUEST); + reply_sz = sizeof(MPI2_IOC_FACTS_REPLY); + reply = (MPI2_DEFAULT_REPLY *)facts; + + bzero(&request, req_sz); + request.Function = MPI2_FUNCTION_IOC_FACTS; + error = mps_request_sync(sc, &request, reply, req_sz, reply_sz, 5); + + return (error); +} + +static int +mps_get_portfacts(struct mps_softc *sc, MPI2_PORT_FACTS_REPLY *facts, int port) +{ + MPI2_PORT_FACTS_REQUEST *request; + MPI2_PORT_FACTS_REPLY *reply; + struct mps_command *cm; + int error; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + request = (MPI2_PORT_FACTS_REQUEST *)cm->cm_req; + request->Function = MPI2_FUNCTION_PORT_FACTS; + request->PortNumber = port; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + error = mps_request_polled(sc, cm); + reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply; + if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + error = ENXIO; + bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY)); + mps_free_command(sc, cm); + + return (error); +} + +static int +mps_send_iocinit(struct mps_softc *sc) +{ + MPI2_IOC_INIT_REQUEST init; + MPI2_DEFAULT_REPLY reply; + int req_sz, reply_sz, error; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + req_sz = sizeof(MPI2_IOC_INIT_REQUEST); + reply_sz = sizeof(MPI2_IOC_INIT_REPLY); + bzero(&init, req_sz); + bzero(&reply, reply_sz); + + /* + * Fill in the init block. Note that most addresses are + * deliberately in the lower 32bits of memory. This is a micro- + * optimzation for PCI/PCIX, though it's not clear if it helps PCIe. + */ + init.Function = MPI2_FUNCTION_IOC_INIT; + init.WhoInit = MPI2_WHOINIT_HOST_DRIVER; + init.MsgVersion = MPI2_VERSION; + init.HeaderVersion = MPI2_HEADER_VERSION; + init.SystemRequestFrameSize = sc->facts->IOCRequestFrameSize; + init.ReplyDescriptorPostQueueDepth = sc->pqdepth; + init.ReplyFreeQueueDepth = sc->fqdepth; + init.SenseBufferAddressHigh = 0; + init.SystemReplyAddressHigh = 0; + init.SystemRequestFrameBaseAddress.High = 0; + init.SystemRequestFrameBaseAddress.Low = (uint32_t)sc->req_busaddr; + init.ReplyDescriptorPostQueueAddress.High = 0; + init.ReplyDescriptorPostQueueAddress.Low = (uint32_t)sc->post_busaddr; + init.ReplyFreeQueueAddress.High = 0; + init.ReplyFreeQueueAddress.Low = (uint32_t)sc->free_busaddr; + init.TimeStamp.High = 0; + init.TimeStamp.Low = (uint32_t)time_uptime; + + error = mps_request_sync(sc, &init, &reply, req_sz, reply_sz, 5); + if ((reply.IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + error = ENXIO; + + mps_dprint(sc, MPS_INFO, "IOCInit status= 0x%x\n", reply.IOCStatus); + return (error); +} + +static int +mps_send_portenable(struct mps_softc *sc) +{ + MPI2_PORT_ENABLE_REQUEST *request; + struct mps_command *cm; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; + request->Function = MPI2_FUNCTION_PORT_ENABLE; + request->MsgFlags = 0; + request->VP_ID = 0; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete = mps_startup_complete; + + mps_enqueue_request(sc, cm); + return (0); +} + +static int +mps_send_mur(struct mps_softc *sc) +{ + + /* Placeholder */ + return (0); +} + +void +mps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + bus_addr_t *addr; + + addr = arg; + *addr = segs[0].ds_addr; +} + +static int +mps_alloc_queues(struct mps_softc *sc) +{ + bus_addr_t queues_busaddr; + uint8_t *queues; + int qsize, fqsize, pqsize; + + /* + * The reply free queue contains 4 byte entries in multiples of 16 and + * aligned on a 16 byte boundary. There must always be an unused entry. + * This queue supplies fresh reply frames for the firmware to use. + * + * The reply descriptor post queue contains 8 byte entries in + * multiples of 16 and aligned on a 16 byte boundary. This queue + * contains filled-in reply frames sent from the firmware to the host. + * + * These two queues are allocated together for simplicity. + */ + sc->fqdepth = roundup2((sc->num_replies + 1), 16); + sc->pqdepth = roundup2((sc->num_replies + 1), 16); + fqsize= sc->fqdepth * 4; + pqsize = sc->pqdepth * 8; + qsize = fqsize + pqsize; + + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + qsize, /* maxsize */ + 1, /* nsegments */ + qsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->queues_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate queues DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->queues_dmat, (void **)&queues, BUS_DMA_NOWAIT, + &sc->queues_map)) { + device_printf(sc->mps_dev, "Cannot allocate queues memory\n"); + return (ENOMEM); + } + bzero(queues, qsize); + bus_dmamap_load(sc->queues_dmat, sc->queues_map, queues, qsize, + mps_memaddr_cb, &queues_busaddr, 0); + + sc->free_queue = (uint32_t *)queues; + sc->free_busaddr = queues_busaddr; + sc->post_queue = (MPI2_REPLY_DESCRIPTORS_UNION *)(queues + fqsize); + sc->post_busaddr = queues_busaddr + fqsize; + + return (0); +} + +static int +mps_alloc_replies(struct mps_softc *sc) +{ + int rsize; + + rsize = sc->facts->ReplyFrameSize * sc->num_replies * 4; + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 4, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->reply_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate replies DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->reply_dmat, (void **)&sc->reply_frames, + BUS_DMA_NOWAIT, &sc->reply_map)) { + device_printf(sc->mps_dev, "Cannot allocate replies memory\n"); + return (ENOMEM); + } + bzero(sc->reply_frames, rsize); + bus_dmamap_load(sc->reply_dmat, sc->reply_map, sc->reply_frames, rsize, + mps_memaddr_cb, &sc->reply_busaddr, 0); + + return (0); +} + +static int +mps_alloc_requests(struct mps_softc *sc) +{ + struct mps_command *cm; + struct mps_chain *chain; + int i, rsize, nsegs; + + rsize = sc->facts->IOCRequestFrameSize * sc->num_reqs * 4; + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->req_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate request DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->req_dmat, (void **)&sc->req_frames, + BUS_DMA_NOWAIT, &sc->req_map)) { + device_printf(sc->mps_dev, "Cannot allocate request memory\n"); + return (ENOMEM); + } + bzero(sc->req_frames, rsize); + bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize, + mps_memaddr_cb, &sc->req_busaddr, 0); + + rsize = sc->facts->IOCRequestFrameSize * MPS_CHAIN_FRAMES * 4; + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 16, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->chain_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate chain DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->chain_dmat, (void **)&sc->chain_frames, + BUS_DMA_NOWAIT, &sc->chain_map)) { + device_printf(sc->mps_dev, "Cannot allocate chain memory\n"); + return (ENOMEM); + } + bzero(sc->chain_frames, rsize); + bus_dmamap_load(sc->chain_dmat, sc->chain_map, sc->chain_frames, rsize, + mps_memaddr_cb, &sc->chain_busaddr, 0); + + rsize = MPS_SENSE_LEN * sc->num_reqs; + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + rsize, /* maxsize */ + 1, /* nsegments */ + rsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->sense_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n"); + return (ENOMEM); + } + if (bus_dmamem_alloc(sc->sense_dmat, (void **)&sc->sense_frames, + BUS_DMA_NOWAIT, &sc->sense_map)) { + device_printf(sc->mps_dev, "Cannot allocate sense memory\n"); + return (ENOMEM); + } + bzero(sc->sense_frames, rsize); + bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize, + mps_memaddr_cb, &sc->sense_busaddr, 0); + + sc->chains = malloc(sizeof(struct mps_chain) * MPS_CHAIN_FRAMES, + M_MPT2, M_WAITOK | M_ZERO); + for (i = 0; i < MPS_CHAIN_FRAMES; i++) { + chain = &sc->chains[i]; + chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames + + i * sc->facts->IOCRequestFrameSize * 4); + chain->chain_busaddr = sc->chain_busaddr + + i * sc->facts->IOCRequestFrameSize * 4; + mps_free_chain(sc, chain); + } + + /* XXX Need to pick a more precise value */ + nsegs = (MAXPHYS / PAGE_SIZE) + 1; + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ + nsegs, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->mps_mtx, /* lockarg */ + &sc->buffer_dmat)) { + device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n"); + return (ENOMEM); + } + + /* + * SMID 0 cannot be used as a free command per the firmware spec. + * Just drop that command instead of risking accounting bugs. + */ + sc->commands = malloc(sizeof(struct mps_command) * sc->num_reqs, + M_MPT2, M_WAITOK | M_ZERO); + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + cm->cm_req = sc->req_frames + + i * sc->facts->IOCRequestFrameSize * 4; + cm->cm_req_busaddr = sc->req_busaddr + + i * sc->facts->IOCRequestFrameSize * 4; + cm->cm_sense = &sc->sense_frames[i]; + cm->cm_sense_busaddr = sc->sense_busaddr + i * MPS_SENSE_LEN; + cm->cm_desc.Default.SMID = i; + cm->cm_sc = sc; + TAILQ_INIT(&cm->cm_chain_list); + callout_init(&cm->cm_callout, 1 /*MPSAFE*/); + + /* XXX Is a failure here a critical problem? */ + if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0) + mps_free_command(sc, cm); + else { + sc->num_reqs = i; + break; + } + } + + return (0); +} + +static int +mps_init_queues(struct mps_softc *sc) +{ + int i; + + memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8); + + if (sc->num_replies >= sc->fqdepth) + return (EINVAL); + + for (i = 0; i < sc->num_replies; i++) + sc->free_queue[i] = sc->reply_busaddr + i * sc->facts->ReplyFrameSize * 4; + sc->replyfreeindex = sc->num_replies; + + return (0); +} + +int +mps_attach(struct mps_softc *sc) +{ + int i, error; + char tmpstr[80], tmpstr2[80]; + + /* + * Grab any tunable-set debug level so that tracing works as early + * as possible. + */ + snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.debug_level", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug); + snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.allow_multiple_tm_cmds", + device_get_unit(sc->mps_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->allow_multiple_tm_cmds); + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF); + callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0); + TAILQ_INIT(&sc->event_list); + + /* + * Setup the sysctl variable so the user can change the debug level + * on the fly. + */ + snprintf(tmpstr, sizeof(tmpstr), "MPS controller %d", + device_get_unit(sc->mps_dev)); + snprintf(tmpstr2, sizeof(tmpstr2), "%d", device_get_unit(sc->mps_dev)); + + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, CTLFLAG_RD, + 0, tmpstr); + if (sc->sysctl_tree == NULL) + return (ENOMEM); + + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0, + "mps debug level"); + + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "allow_multiple_tm_cmds", CTLFLAG_RW, + &sc->allow_multiple_tm_cmds, 0, + "allow multiple simultaneous task management cmds"); + + if ((error = mps_transition_ready(sc)) != 0) + return (error); + + sc->facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2, + M_ZERO|M_NOWAIT); + if ((error = mps_get_iocfacts(sc, sc->facts)) != 0) + return (error); + + mps_print_iocfacts(sc, sc->facts); + + mps_printf(sc, "Firmware: %02d.%02d.%02d.%02d\n", + sc->facts->FWVersion.Struct.Major, + sc->facts->FWVersion.Struct.Minor, + sc->facts->FWVersion.Struct.Unit, + sc->facts->FWVersion.Struct.Dev); + mps_printf(sc, "IOCCapabilities: %b\n", sc->facts->IOCCapabilities, + "\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf" + "\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR" + "\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc"); + + /* + * If the chip doesn't support event replay then a hard reset will be + * required to trigger a full discovery. Do the reset here then + * retransition to Ready. A hard reset might have already been done, + * but it doesn't hurt to do it again. + */ + if ((sc->facts->IOCCapabilities & + MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) { + mps_hard_reset(sc); + if ((error = mps_transition_ready(sc)) != 0) + return (error); + } + + /* + * Size the queues. Since the reply queues always need one free entry, + * we'll just deduct one reply message here. + */ + sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit); + sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES, + sc->facts->MaxReplyDescriptorPostQueueDepth) - 1; + TAILQ_INIT(&sc->req_list); + TAILQ_INIT(&sc->chain_list); + TAILQ_INIT(&sc->tm_list); + + if (((error = mps_alloc_queues(sc)) != 0) || + ((error = mps_alloc_replies(sc)) != 0) || + ((error = mps_alloc_requests(sc)) != 0)) { + mps_free(sc); + return (error); + } + + if (((error = mps_init_queues(sc)) != 0) || + ((error = mps_transition_operational(sc)) != 0)) { + mps_free(sc); + return (error); + } + + /* + * Finish the queue initialization. + * These are set here instead of in mps_init_queues() because the + * IOC resets these values during the state transition in + * mps_transition_operational(). The free index is set to 1 + * because the corresponding index in the IOC is set to 0, and the + * IOC treats the queues as full if both are set to the same value. + * Hence the reason that the queue can't hold all of the possible + * replies. + */ + sc->replypostindex = 0; + sc->replycurindex = 0; + mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); + mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0); + + sc->pfacts = malloc(sizeof(MPI2_PORT_FACTS_REPLY) * + sc->facts->NumberOfPorts, M_MPT2, M_ZERO|M_WAITOK); + for (i = 0; i < sc->facts->NumberOfPorts; i++) { + if ((error = mps_get_portfacts(sc, &sc->pfacts[i], i)) != 0) { + mps_free(sc); + return (error); + } + mps_print_portfacts(sc, &sc->pfacts[i]); + } + + /* Attach the subsystems so they can prepare their event masks. */ + /* XXX Should be dynamic so that IM/IR and user modules can attach */ + if (((error = mps_attach_log(sc)) != 0) || + ((error = mps_attach_sas(sc)) != 0) || + ((error = mps_attach_user(sc)) != 0)) { + mps_printf(sc, "%s failed to attach all subsystems: error %d\n", + __func__, error); + mps_free(sc); + return (error); + } + + if ((error = mps_pci_setup_interrupts(sc)) != 0) { + mps_free(sc); + return (error); + } + + /* Start the periodic watchdog check on the IOC Doorbell */ + mps_periodic(sc); + + /* + * The portenable will kick off discovery events that will drive the + * rest of the initialization process. The CAM/SAS module will + * hold up the boot sequence until discovery is complete. + */ + sc->mps_ich.ich_func = mps_startup; + sc->mps_ich.ich_arg = sc; + if (config_intrhook_establish(&sc->mps_ich) != 0) { + mps_dprint(sc, MPS_FAULT, "Cannot establish MPS config hook\n"); + error = EINVAL; + } + + return (error); +} + +static void +mps_startup(void *arg) +{ + struct mps_softc *sc; + + sc = (struct mps_softc *)arg; + + mps_lock(sc); + mps_unmask_intr(sc); + mps_send_portenable(sc); + mps_unlock(sc); +} + +/* Periodic watchdog. Is called with the driver lock already held. */ +static void +mps_periodic(void *arg) +{ + struct mps_softc *sc; + uint32_t db; + + sc = (struct mps_softc *)arg; + if (sc->mps_flags & MPS_FLAGS_SHUTDOWN) + return; + + db = mps_regread(sc, MPI2_DOORBELL_OFFSET); + if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db); + /* XXX Need to broaden this to re-initialize the chip */ + mps_hard_reset(sc); + db = mps_regread(sc, MPI2_DOORBELL_OFFSET); + if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + device_printf(sc->mps_dev, "Second IOC Fault 0x%08x, " + "Giving up!\n", db); + return; + } + } + + callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc); +} + +static void +mps_startup_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_PORT_ENABLE_REPLY *reply; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; + if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + mps_dprint(sc, MPS_FAULT, "Portenable failed\n"); + + mps_free_command(sc, cm); + config_intrhook_disestablish(&sc->mps_ich); + +} + +static void +mps_log_evt_handler(struct mps_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + MPI2_EVENT_DATA_LOG_ENTRY_ADDED *entry; + + mps_print_event(sc, event); + + switch (event->Event) { + case MPI2_EVENT_LOG_DATA: + device_printf(sc->mps_dev, "MPI2_EVENT_LOG_DATA:\n"); + hexdump(event->EventData, event->EventDataLength, NULL, 0); + break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + entry = (MPI2_EVENT_DATA_LOG_ENTRY_ADDED *)event->EventData; + mps_dprint(sc, MPS_INFO, "MPI2_EVENT_LOG_ENTRY_ADDED event " + "0x%x Sequence %d:\n", entry->LogEntryQualifier, + entry->LogSequence); + break; + default: + break; + } + return; +} + +static int +mps_attach_log(struct mps_softc *sc) +{ + uint8_t events[16]; + + bzero(events, 16); + setbit(events, MPI2_EVENT_LOG_DATA); + setbit(events, MPI2_EVENT_LOG_ENTRY_ADDED); + + mps_register_events(sc, events, mps_log_evt_handler, NULL, + &sc->mps_log_eh); + + return (0); +} + +static int +mps_detach_log(struct mps_softc *sc) +{ + + if (sc->mps_log_eh != NULL) + mps_deregister_events(sc, sc->mps_log_eh); + return (0); +} + +/* + * Free all of the driver resources and detach submodules. Should be called + * without the lock held. + */ +int +mps_free(struct mps_softc *sc) +{ + struct mps_command *cm; + int i, error; + + /* Turn off the watchdog */ + mps_lock(sc); + sc->mps_flags |= MPS_FLAGS_SHUTDOWN; + mps_unlock(sc); + /* Lock must not be held for this */ + callout_drain(&sc->periodic); + + if (((error = mps_detach_log(sc)) != 0) || + ((error = mps_detach_sas(sc)) != 0)) + return (error); + + /* Put the IOC back in the READY state. */ + mps_lock(sc); + if ((error = mps_send_mur(sc)) != 0) { + mps_unlock(sc); + return (error); + } + mps_unlock(sc); + + if (sc->facts != NULL) + free(sc->facts, M_MPT2); + + if (sc->pfacts != NULL) + free(sc->pfacts, M_MPT2); + + if (sc->post_busaddr != 0) + bus_dmamap_unload(sc->queues_dmat, sc->queues_map); + if (sc->post_queue != NULL) + bus_dmamem_free(sc->queues_dmat, sc->post_queue, + sc->queues_map); + if (sc->queues_dmat != NULL) + bus_dma_tag_destroy(sc->queues_dmat); + + if (sc->chain_busaddr != 0) + bus_dmamap_unload(sc->chain_dmat, sc->chain_map); + if (sc->chain_frames != NULL) + bus_dmamem_free(sc->chain_dmat, sc->chain_frames,sc->chain_map); + if (sc->chain_dmat != NULL) + bus_dma_tag_destroy(sc->chain_dmat); + + if (sc->sense_busaddr != 0) + bus_dmamap_unload(sc->sense_dmat, sc->sense_map); + if (sc->sense_frames != NULL) + bus_dmamem_free(sc->sense_dmat, sc->sense_frames,sc->sense_map); + if (sc->sense_dmat != NULL) + bus_dma_tag_destroy(sc->sense_dmat); + + if (sc->reply_busaddr != 0) + bus_dmamap_unload(sc->reply_dmat, sc->reply_map); + if (sc->reply_frames != NULL) + bus_dmamem_free(sc->reply_dmat, sc->reply_frames,sc->reply_map); + if (sc->reply_dmat != NULL) + bus_dma_tag_destroy(sc->reply_dmat); + + if (sc->req_busaddr != 0) + bus_dmamap_unload(sc->req_dmat, sc->req_map); + if (sc->req_frames != NULL) + bus_dmamem_free(sc->req_dmat, sc->req_frames, sc->req_map); + if (sc->req_dmat != NULL) + bus_dma_tag_destroy(sc->req_dmat); + + if (sc->chains != NULL) + free(sc->chains, M_MPT2); + if (sc->commands != NULL) { + for (i = 1; i < sc->num_reqs; i++) { + cm = &sc->commands[i]; + bus_dmamap_destroy(sc->buffer_dmat, cm->cm_dmamap); + } + free(sc->commands, M_MPT2); + } + if (sc->buffer_dmat != NULL) + bus_dma_tag_destroy(sc->buffer_dmat); + + if (sc->sysctl_tree != NULL) + sysctl_ctx_free(&sc->sysctl_ctx); + + mtx_destroy(&sc->mps_mtx); + + return (0); +} + +void +mps_intr(void *data) +{ + struct mps_softc *sc; + uint32_t status; + + sc = (struct mps_softc *)data; + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + /* + * Check interrupt status register to flush the bus. This is + * needed for both INTx interrupts and driver-driven polling + */ + status = mps_regread(sc, MPI2_HOST_INTERRUPT_STATUS_OFFSET); + if ((status & MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT) == 0) + return; + + mps_lock(sc); + mps_intr_locked(data); + mps_unlock(sc); + return; +} + +/* + * In theory, MSI/MSIX interrupts shouldn't need to read any registers on the + * chip. Hopefully this theory is correct. + */ +void +mps_intr_msi(void *data) +{ + struct mps_softc *sc; + + sc = (struct mps_softc *)data; + mps_lock(sc); + mps_intr_locked(data); + mps_unlock(sc); + return; +} + +/* + * The locking is overly broad and simplistic, but easy to deal with for now. + */ +void +mps_intr_locked(void *data) +{ + MPI2_REPLY_DESCRIPTORS_UNION *desc; + struct mps_softc *sc; + struct mps_command *cm = NULL; + uint8_t flags; + u_int pq; + + sc = (struct mps_softc *)data; + + pq = sc->replypostindex; + + for ( ;; ) { + cm = NULL; + desc = &sc->post_queue[pq]; + flags = desc->Default.ReplyFlags & + MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; + if (flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) + break; + + switch (flags) { + case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS: + cm = &sc->commands[desc->SCSIIOSuccess.SMID]; + cm->cm_reply = NULL; + break; + case MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY: + { + uint32_t baddr; + uint8_t *reply; + + reply = sc->reply_frames + + sc->replycurindex * sc->facts->ReplyFrameSize * 4; + baddr = desc->AddressReply.ReplyFrameAddress; + if (desc->AddressReply.SMID == 0) { + mps_dispatch_event(sc, baddr, + (MPI2_EVENT_NOTIFICATION_REPLY *) reply); + } else { + cm = &sc->commands[desc->AddressReply.SMID]; + cm->cm_reply = reply; + cm->cm_reply_data = + desc->AddressReply.ReplyFrameAddress; + } + if (++sc->replycurindex >= sc->fqdepth) + sc->replycurindex = 0; + break; + } + case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS: + case MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER: + case MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS: + default: + /* Unhandled */ + device_printf(sc->mps_dev, "Unhandled reply 0x%x\n", + desc->Default.ReplyFlags); + cm = NULL; + break; + } + + if (cm != NULL) { + if (cm->cm_flags & MPS_CM_FLAGS_POLLED) + cm->cm_flags |= MPS_CM_FLAGS_COMPLETE; + + if (cm->cm_complete != NULL) + cm->cm_complete(sc, cm); + + if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) + wakeup(cm); + } + + desc->Words.Low = 0xffffffff; + desc->Words.High = 0xffffffff; + if (++pq >= sc->pqdepth) + pq = 0; + } + + if (pq != sc->replypostindex) { + mps_dprint(sc, MPS_INFO, "writing postindex %d\n", pq); + mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, pq); + sc->replypostindex = pq; + } + + return; +} + +static void +mps_dispatch_event(struct mps_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *reply) +{ + struct mps_event_handle *eh; + int event, handled = 0;; + + event = reply->Event; + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + if (isset(eh->mask, event)) { + eh->callback(sc, data, reply); + handled++; + } + } + + if (handled == 0) + device_printf(sc->mps_dev, "Unhandled event 0x%x\n", event); +} + +/* + * For both register_events and update_events, the caller supplies a bitmap + * of events that it _wants_. These functions then turn that into a bitmask + * suitable for the controller. + */ +int +mps_register_events(struct mps_softc *sc, uint8_t *mask, + mps_evt_callback_t *cb, void *data, struct mps_event_handle **handle) +{ + struct mps_event_handle *eh; + int error = 0; + + eh = malloc(sizeof(struct mps_event_handle), M_MPT2, M_WAITOK|M_ZERO); + eh->callback = cb; + eh->data = data; + TAILQ_INSERT_TAIL(&sc->event_list, eh, eh_list); + if (mask != NULL) + error = mps_update_events(sc, eh, mask); + *handle = eh; + + return (error); +} + +int +mps_update_events(struct mps_softc *sc, struct mps_event_handle *handle, + uint8_t *mask) +{ + MPI2_EVENT_NOTIFICATION_REQUEST *evtreq; + MPI2_EVENT_NOTIFICATION_REPLY *reply; + struct mps_command *cm; + struct mps_event_handle *eh; + int error, i; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if ((mask != NULL) && (handle != NULL)) + bcopy(mask, &handle->mask[0], 16); + memset(sc->event_mask, 0xff, 16); + + TAILQ_FOREACH(eh, &sc->event_list, eh_list) { + for (i = 0; i < 16; i++) + sc->event_mask[i] &= ~eh->mask[i]; + } + + if ((cm = mps_alloc_command(sc)) == NULL) + return (EBUSY); + evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req; + evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; + evtreq->MsgFlags = 0; + evtreq->SASBroadcastPrimitiveMasks = 0; +#ifdef MPS_DEBUG_ALL_EVENTS + { + u_char fullmask[16]; + memset(fullmask, 0x00, 16); + bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16); + } +#else + bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16); +#endif + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_data = NULL; + + error = mps_request_polled(sc, cm); + reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply; + if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) + error = ENXIO; + mps_print_event(sc, reply); + + mps_free_command(sc, cm); + return (error); +} + +int +mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle) +{ + + TAILQ_REMOVE(&sc->event_list, handle, eh_list); + free(handle, M_MPT2); + return (mps_update_events(sc, NULL, NULL)); +} + +/* + * Add a chain element as the next SGE for the specified command. + * Reset cm_sge and cm_sgesize to indicate all the available space. + */ +static int +mps_add_chain(struct mps_command *cm) +{ + MPI2_SGE_CHAIN32 *sgc; + struct mps_chain *chain; + int space; + + if (cm->cm_sglsize < MPS_SGC_SIZE) + panic("MPS: Need SGE Error Code\n"); + + chain = mps_alloc_chain(cm->cm_sc); + if (chain == NULL) + return (ENOBUFS); + + space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; + + /* + * Note: a double-linked list is used to make it easier to + * walk for debugging. + */ + TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link); + + sgc = (MPI2_SGE_CHAIN32 *)&cm->cm_sge->MpiChain; + sgc->Length = space; + sgc->NextChainOffset = 0; + sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT; + sgc->Address = chain->chain_busaddr; + + cm->cm_sge = (MPI2_SGE_IO_UNION *)&chain->chain->MpiSimple; + cm->cm_sglsize = space; + return (0); +} + +/* + * Add one scatter-gather element (chain, simple, transaction context) + * to the scatter-gather list for a command. Maintain cm_sglsize and + * cm_sge as the remaining size and pointer to the next SGE to fill + * in, respectively. + */ +int +mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft) +{ + MPI2_SGE_TRANSACTION_UNION *tc = sgep; + MPI2_SGE_SIMPLE64 *sge = sgep; + int error, type; + + type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK); + +#ifdef INVARIANTS + switch (type) { + case MPI2_SGE_FLAGS_TRANSACTION_ELEMENT: { + if (len != tc->DetailsLength + 4) + panic("TC %p length %u or %zu?", tc, + tc->DetailsLength + 4, len); + } + break; + case MPI2_SGE_FLAGS_CHAIN_ELEMENT: + /* Driver only uses 32-bit chain elements */ + if (len != MPS_SGC_SIZE) + panic("CHAIN %p length %u or %zu?", sgep, + MPS_SGC_SIZE, len); + break; + case MPI2_SGE_FLAGS_SIMPLE_ELEMENT: + /* Driver only uses 64-bit SGE simple elements */ + sge = sgep; + if (len != MPS_SGE64_SIZE) + panic("SGE simple %p length %u or %zu?", sge, + MPS_SGE64_SIZE, len); + if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) & + MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0) + panic("SGE simple %p flags %02x not marked 64-bit?", + sge, sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT); + + break; + default: + panic("Unexpected SGE %p, flags %02x", tc, tc->Flags); + } +#endif + + /* + * case 1: 1 more segment, enough room for it + * case 2: 2 more segments, enough room for both + * case 3: >=2 more segments, only enough room for 1 and a chain + * case 4: >=1 more segment, enough room for only a chain + * case 5: >=1 more segment, no room for anything (error) + */ + + /* + * There should be room for at least a chain element, or this + * code is buggy. Case (5). + */ + if (cm->cm_sglsize < MPS_SGC_SIZE) + panic("MPS: Need SGE Error Code\n"); + + if (segsleft >= 2 && + cm->cm_sglsize < len + MPS_SGC_SIZE + MPS_SGE64_SIZE) { + /* + * There are 2 or more segments left to add, and only + * enough room for 1 and a chain. Case (3). + * + * Mark as last element in this chain if necessary. + */ + if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { + sge->FlagsLength |= + (MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT); + } + + /* + * Add the item then a chain. Do the chain now, + * rather than on the next iteration, to simplify + * understanding the code. + */ + cm->cm_sglsize -= len; + bcopy(sgep, cm->cm_sge, len); + cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); + return (mps_add_chain(cm)); + } + + if (segsleft >= 1 && cm->cm_sglsize < len + MPS_SGC_SIZE) { + /* + * 1 or more segment, enough room for only a chain. + * Hope the previous element wasn't a Simple entry + * that needed to be marked with + * MPI2_SGE_FLAGS_LAST_ELEMENT. Case (4). + */ + if ((error = mps_add_chain(cm)) != 0) + return (error); + } + +#ifdef INVARIANTS + /* Case 1: 1 more segment, enough room for it. */ + if (segsleft == 1 && cm->cm_sglsize < len) + panic("1 seg left and no room? %u versus %zu", + cm->cm_sglsize, len); + + /* Case 2: 2 more segments, enough room for both */ + if (segsleft == 2 && cm->cm_sglsize < len + MPS_SGE64_SIZE) + panic("2 segs left and no room? %u versus %zu", + cm->cm_sglsize, len); +#endif + + if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) { + /* + * Last element of the last segment of the entire + * buffer. + */ + sge->FlagsLength |= ((MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT); + } + + cm->cm_sglsize -= len; + bcopy(sgep, cm->cm_sge, len); + cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len); + return (0); +} + +/* + * Add one dma segment to the scatter-gather list for a command. + */ +int +mps_add_dmaseg(struct mps_command *cm, vm_paddr_t pa, size_t len, u_int flags, + int segsleft) +{ + MPI2_SGE_SIMPLE64 sge; + + /* + * This driver always uses 64-bit address elements for + * simplicity. + */ + flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_ADDRESS_SIZE; + sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT); + mps_from_u64(pa, &sge.Address); + + return (mps_push_sge(cm, &sge, sizeof sge, segsleft)); +} + +static void +mps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct mps_softc *sc; + struct mps_command *cm; + u_int i, dir, sflags; + + cm = (struct mps_command *)arg; + sc = cm->cm_sc; + + /* + * Set up DMA direction flags. Note no support for + * bi-directional transactions. + */ + sflags = 0; + if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) { + sflags |= MPI2_SGE_FLAGS_DIRECTION; + dir = BUS_DMASYNC_PREWRITE; + } else + dir = BUS_DMASYNC_PREREAD; + + for (i = 0; i < nsegs; i++) { + error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len, + sflags, nsegs - i); + if (error != 0) { + /* Resource shortage, roll back! */ + mps_printf(sc, "out of chain frames\n"); + return; + } + } + + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); + mps_enqueue_request(sc, cm); + + return; +} + +/* + * Note that the only error path here is from bus_dmamap_load(), which can + * return EINPROGRESS if it is waiting for resources. + */ +int +mps_map_command(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SGE_SIMPLE32 *sge; + int error = 0; + + if ((cm->cm_data != NULL) && (cm->cm_length != 0)) { + error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap, + cm->cm_data, cm->cm_length, mps_data_cb, cm, 0); + } else { + /* Add a zero-length element as needed */ + if (cm->cm_sge != NULL) { + sge = (MPI2_SGE_SIMPLE32 *)cm->cm_sge; + sge->FlagsLength = (MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << + MPI2_SGE_FLAGS_SHIFT; + sge->Address = 0; + } + mps_enqueue_request(sc, cm); + } + + return (error); +} + +/* + * The MPT driver had a verbose interface for config pages. In this driver, + * reduce it to much simplier terms, similar to the Linux driver. + */ +int +mps_read_config_page(struct mps_softc *sc, struct mps_config_params *params) +{ + MPI2_CONFIG_REQUEST *req; + struct mps_command *cm; + int error; + + if (sc->mps_flags & MPS_FLAGS_BUSY) { + return (EBUSY); + } + + cm = mps_alloc_command(sc); + if (cm == NULL) { + return (EBUSY); + } + + req = (MPI2_CONFIG_REQUEST *)cm->cm_req; + req->Function = MPI2_FUNCTION_CONFIG; + req->Action = params->action; + req->SGLFlags = 0; + req->ChainOffset = 0; + req->PageAddress = params->page_address; + if (params->hdr.Ext.ExtPageType != 0) { + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + + hdr = ¶ms->hdr.Ext; + req->ExtPageType = hdr->ExtPageType; + req->ExtPageLength = hdr->ExtPageLength; + req->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; + req->Header.PageLength = 0; /* Must be set to zero */ + req->Header.PageNumber = hdr->PageNumber; + req->Header.PageVersion = hdr->PageVersion; + } else { + MPI2_CONFIG_PAGE_HEADER *hdr; + + hdr = ¶ms->hdr.Struct; + req->Header.PageType = hdr->PageType; + req->Header.PageNumber = hdr->PageNumber; + req->Header.PageLength = hdr->PageLength; + req->Header.PageVersion = hdr->PageVersion; + } + + cm->cm_data = params->buffer; + cm->cm_length = params->length; + cm->cm_sge = &req->PageBufferSGE; + cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION); + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + cm->cm_complete_data = params; + if (params->callback != NULL) { + cm->cm_complete = mps_config_complete; + return (mps_map_command(sc, cm)); + } else { + cm->cm_complete = NULL; + cm->cm_flags |= MPS_CM_FLAGS_WAKEUP; + if ((error = mps_map_command(sc, cm)) != 0) + return (error); + msleep(cm, &sc->mps_mtx, 0, "mpswait", 0); + mps_config_complete(sc, cm); + } + + return (0); +} + +int +mps_write_config_page(struct mps_softc *sc, struct mps_config_params *params) +{ + return (EINVAL); +} + +static void +mps_config_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_CONFIG_REPLY *reply; + struct mps_config_params *params; + + params = cm->cm_complete_data; + + if (cm->cm_data != NULL) { + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + } + + reply = (MPI2_CONFIG_REPLY *)cm->cm_reply; + params->status = reply->IOCStatus; + if (params->hdr.Ext.ExtPageType != 0) { + params->hdr.Ext.ExtPageType = reply->ExtPageType; + params->hdr.Ext.ExtPageLength = reply->ExtPageLength; + } else { + params->hdr.Struct.PageType = reply->Header.PageType; + params->hdr.Struct.PageNumber = reply->Header.PageNumber; + params->hdr.Struct.PageLength = reply->Header.PageLength; + params->hdr.Struct.PageVersion = reply->Header.PageVersion; + } + + mps_free_command(sc, cm); + if (params->callback != NULL) + params->callback(sc, params); + + return; +} diff --git a/sys/dev/mps/mps_ioctl.h b/sys/dev/mps/mps_ioctl.h new file mode 100644 index 00000000000..811b13e0cca --- /dev/null +++ b/sys/dev/mps/mps_ioctl.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPT-Fusion Host Adapter FreeBSD userland interface + * + * $FreeBSD$ + */ + +#ifndef _MPS_IOCTL_H_ +#define _MPS_IOCTL_H_ + +#include +#include +#include +#include + +/* + * For the read header requests, the header should include the page + * type or extended page type, page number, and page version. The + * buffer and length are unused. The completed header is returned in + * the 'header' member. + * + * For the read page and write page requests, 'buf' should point to a + * buffer of 'len' bytes which holds the entire page (including the + * header). + * + * All requests specify the page address in 'page_address'. + */ +struct mps_cfg_page_req { + MPI2_CONFIG_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mps_ext_cfg_page_req { + MPI2_CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + void *buf; + int len; + uint16_t ioc_status; +}; + +struct mps_raid_action { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + void *buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +struct mps_usr_command { + void *req; + uint32_t req_len; + void *rpl; + uint32_t rpl_len; + void *buf; + int len; + uint32_t flags; +}; + +#define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01 +#define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02 +#define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req) +#define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req) +#define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req) +#define MPSIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mps_ext_cfg_page_req) +#define MPSIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mps_cfg_page_req) +#define MPSIO_RAID_ACTION _IOWR('M', 205, struct mps_raid_action) +#define MPSIO_MPS_COMMAND _IOWR('M', 210, struct mps_usr_command) + +#endif /* !_MPS_IOCTL_H_ */ diff --git a/sys/dev/mps/mps_pci.c b/sys/dev/mps/mps_pci.c new file mode 100644 index 00000000000..2b33ba857d8 --- /dev/null +++ b/sys/dev/mps/mps_pci.c @@ -0,0 +1,364 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* PCI/PCI-X/PCIe bus interface for the LSI MPT2 controllers */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +static int mps_pci_probe(device_t); +static int mps_pci_attach(device_t); +static int mps_pci_detach(device_t); +static int mps_pci_suspend(device_t); +static int mps_pci_resume(device_t); +static void mps_pci_free(struct mps_softc *); +static int mps_alloc_msix(struct mps_softc *sc, int msgs); +static int mps_alloc_msi(struct mps_softc *sc, int msgs); + +int mps_disable_msix = 0; +TUNABLE_INT("hw.mps.disable_msix", &mps_disable_msix); +SYSCTL_INT(_hw_mps, OID_AUTO, disable_msix, CTLFLAG_RD, &mps_disable_msix, 0, + "Disable MSIX interrupts\n"); +int mps_disable_msi = 0; +TUNABLE_INT("hw.mps.disable_msi", &mps_disable_msi); +SYSCTL_INT(_hw_mps, OID_AUTO, disable_msi, CTLFLAG_RD, &mps_disable_msi, 0, + "Disable MSI interrupts\n"); + +static device_method_t mps_methods[] = { + DEVMETHOD(device_probe, mps_pci_probe), + DEVMETHOD(device_attach, mps_pci_attach), + DEVMETHOD(device_detach, mps_pci_detach), + DEVMETHOD(device_suspend, mps_pci_suspend), + DEVMETHOD(device_resume, mps_pci_resume), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + { 0, 0 } +}; + +static driver_t mps_pci_driver = { + "mps", + mps_methods, + sizeof(struct mps_softc) +}; + +static devclass_t mps_devclass; +DRIVER_MODULE(mps, pci, mps_pci_driver, mps_devclass, 0, 0); + +struct mps_ident { + uint16_t vendor; + uint16_t device; + uint16_t subvendor; + uint16_t subdevice; + u_int flags; + const char *desc; +} mps_identifiers[] = { + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, + 0xffff, 0xffff, 0, "LSI SAS2004" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, + 0xffff, 0xffff, 0, "LSI SAS2008" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, + 0xffff, 0xffff, 0, "LSI SAS2108" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, + 0xffff, 0xffff, 0, "LSI SAS2108" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, + 0xffff, 0xffff, 0, "LSI SAS2108" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, + 0xffff, 0xffff, 0, "LSI SAS2116" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, + 0xffff, 0xffff, 0, "LSI SAS2116" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, + 0xffff, 0xffff, 0, "LSI SAS2208" }, + { 0, 0, 0, 0, 0, NULL } +}; + +static struct mps_ident * +mps_find_ident(device_t dev) +{ + struct mps_ident *m; + + for (m = mps_identifiers; m->vendor != 0; m++) { + if (m->vendor != pci_get_vendor(dev)) + continue; + if (m->device != pci_get_device(dev)) + continue; + if ((m->subvendor != 0xffff) && + (m->subvendor != pci_get_subvendor(dev))) + continue; + if ((m->subdevice != 0xffff) && + (m->subdevice != pci_get_subdevice(dev))) + continue; + return (m); + } + + return (NULL); +} + +static int +mps_pci_probe(device_t dev) +{ + struct mps_ident *id; + + if ((id = mps_find_ident(dev)) != NULL) { + device_set_desc(dev, id->desc); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static int +mps_pci_attach(device_t dev) +{ + struct mps_softc *sc; + struct mps_ident *m; + uint16_t command; + int error; + + sc = device_get_softc(dev); + bzero(sc, sizeof(*sc)); + sc->mps_dev = dev; + m = mps_find_ident(dev); + sc->mps_flags = m->flags; + + /* Twiddle basic PCI config bits for a sanity check */ + command = pci_read_config(dev, PCIR_COMMAND, 2); + command |= PCIM_CMD_BUSMASTEREN; + pci_write_config(dev, PCIR_COMMAND, command, 2); + command = pci_read_config(dev, PCIR_COMMAND, 2); + if ((command & PCIM_CMD_BUSMASTEREN) == 0) { + device_printf(dev, "Cannot enable PCI busmaster\n"); + return (ENXIO); + } + if ((command & PCIM_CMD_MEMEN) == 0) { + device_printf(dev, "PCI memory window not available\n"); + return (ENXIO); + } + + /* Allocate the System Interface Register Set */ + sc->mps_regs_rid = PCIR_BAR(1); + if ((sc->mps_regs_resource = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &sc->mps_regs_rid, RF_ACTIVE)) == NULL) { + device_printf(dev, "Cannot allocate PCI registers\n"); + return (ENXIO); + } + sc->mps_btag = rman_get_bustag(sc->mps_regs_resource); + sc->mps_bhandle = rman_get_bushandle(sc->mps_regs_resource); + + /* Allocate the parent DMA tag */ + if (bus_dma_tag_create( NULL, /* parent */ + 1, 0, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->mps_parent_dmat)) { + device_printf(dev, "Cannot allocate parent DMA tag\n"); + mps_pci_free(sc); + return (ENOMEM); + } + + if ((error = mps_attach(sc)) != 0) + mps_pci_free(sc); + + return (error); +} + +int +mps_pci_setup_interrupts(struct mps_softc *sc) +{ + device_t dev; + int i, error, msgs; + + dev = sc->mps_dev; + error = ENXIO; + if ((mps_disable_msix == 0) && + ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT)) + error = mps_alloc_msix(sc, MPS_MSI_COUNT); + if ((error != 0) && (mps_disable_msi == 0) && + ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT)) + error = mps_alloc_msi(sc, MPS_MSI_COUNT); + + if (error != 0) { + sc->mps_flags |= MPS_FLAGS_INTX; + sc->mps_irq_rid[0] = 0; + sc->mps_irq[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->mps_irq_rid[0], RF_SHAREABLE | RF_ACTIVE); + if (sc->mps_irq[0] == NULL) { + device_printf(dev, "Cannot allocate INTx interrupt\n"); + return (ENXIO); + } + error = bus_setup_intr(dev, sc->mps_irq[0], + INTR_TYPE_BIO | INTR_MPSAFE, NULL, mps_intr, sc, + &sc->mps_intrhand[0]); + if (error) + device_printf(dev, "Cannot setup INTx interrupt\n"); + } else { + sc->mps_flags |= MPS_FLAGS_MSI; + for (i = 0; i < MPS_MSI_COUNT; i++) { + sc->mps_irq_rid[i] = i + 1; + sc->mps_irq[i] = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &sc->mps_irq_rid[i], RF_ACTIVE); + if (sc->mps_irq[i] == NULL) { + device_printf(dev, + "Cannot allocate MSI interrupt\n"); + return (ENXIO); + } + error = bus_setup_intr(dev, sc->mps_irq[i], + INTR_TYPE_BIO | INTR_MPSAFE, NULL, mps_intr_msi, + sc, &sc->mps_intrhand[i]); + if (error) { + device_printf(dev, + "Cannot setup MSI interrupt %d\n", i); + break; + } + } + } + + return (error); +} + +static int +mps_pci_detach(device_t dev) +{ + struct mps_softc *sc; + int error; + + sc = device_get_softc(dev); + + if ((error = mps_free(sc)) != 0) + return (error); + + mps_pci_free(sc); + return (0); +} + +static void +mps_pci_free(struct mps_softc *sc) +{ + int i; + + if (sc->mps_parent_dmat != NULL) { + bus_dma_tag_destroy(sc->mps_parent_dmat); + } + + if (sc->mps_flags & MPS_FLAGS_MSI) { + for (i = 0; i < MPS_MSI_COUNT; i++) { + if (sc->mps_irq[i] != NULL) { + bus_teardown_intr(sc->mps_dev, sc->mps_irq[i], + sc->mps_intrhand[i]); + bus_release_resource(sc->mps_dev, SYS_RES_IRQ, + sc->mps_irq_rid[i], sc->mps_irq[i]); + } + } + pci_release_msi(sc->mps_dev); + } + + if (sc->mps_flags & MPS_FLAGS_INTX) { + bus_teardown_intr(sc->mps_dev, sc->mps_irq[0], + sc->mps_intrhand[0]); + bus_release_resource(sc->mps_dev, SYS_RES_IRQ, + sc->mps_irq_rid[0], sc->mps_irq[0]); + } + + if (sc->mps_regs_resource != NULL) { + bus_release_resource(sc->mps_dev, SYS_RES_MEMORY, + sc->mps_regs_rid, sc->mps_regs_resource); + } + + return; +} + +static int +mps_pci_suspend(device_t dev) +{ + return (EINVAL); +} + +static int +mps_pci_resume(device_t dev) +{ + return (EINVAL); +} + +static int +mps_alloc_msix(struct mps_softc *sc, int msgs) +{ + int error; + + error = pci_alloc_msix(sc->mps_dev, &msgs); + return (error); +} + +static int +mps_alloc_msi(struct mps_softc *sc, int msgs) +{ + int error; + + error = pci_alloc_msi(sc->mps_dev, &msgs); + return (error); +} + diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c new file mode 100644 index 00000000000..5883e496ebd --- /dev/null +++ b/sys/dev/mps/mps_sas.c @@ -0,0 +1,1625 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* Communications core for LSI MPT2 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct mpssas_target { + uint16_t handle; + uint8_t linkrate; + uint64_t devname; + uint32_t devinfo; + uint16_t encl_handle; + uint16_t encl_slot; + int flags; +#define MPSSAS_TARGET_INABORT (1 << 0) +#define MPSSAS_TARGET_INRESET (1 << 1) +#define MPSSAS_TARGET_INCHIPRESET (1 << 2) +#define MPSSAS_TARGET_INRECOVERY 0x7 + uint16_t tid; +}; + +struct mpssas_softc { + struct mps_softc *sc; + u_int flags; +#define MPSSAS_IN_DISCOVERY (1 << 0) +#define MPSSAS_IN_STARTUP (1 << 1) +#define MPSSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2) +#define MPSSAS_QUEUE_FROZEN (1 << 3) + struct mpssas_target *targets; + struct cam_devq *devq; + struct cam_sim *sim; + struct cam_path *path; + struct intr_config_hook sas_ich; + struct callout discovery_callout; + u_int discovery_timeouts; + struct mps_event_handle *mpssas_eh; +}; + +struct mpssas_devprobe { + struct mps_config_params params; + u_int state; +#define MPSSAS_PROBE_DEV1 0x01 +#define MPSSAS_PROBE_DEV2 0x02 +#define MPSSAS_PROBE_PHY 0x03 +#define MPSSAS_PROBE_EXP 0x04 +#define MPSSAS_PROBE_PHY2 0x05 +#define MPSSAS_PROBE_EXP2 0x06 + struct mpssas_target target; +}; + +#define MPSSAS_DISCOVERY_TIMEOUT 20 +#define MPSSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ + +MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory"); + +static struct mpssas_target * mpssas_alloc_target(struct mpssas_softc *, + struct mpssas_target *); +static struct mpssas_target * mpssas_find_target(struct mpssas_softc *, int, + uint16_t); +static void mpssas_announce_device(struct mpssas_softc *, + struct mpssas_target *); +static void mpssas_startup(void *data); +static void mpssas_discovery_end(struct mpssas_softc *sassc); +static void mpssas_discovery_timeout(void *data); +static void mpssas_prepare_remove(struct mpssas_softc *, + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *); +static void mpssas_remove_device(struct mps_softc *, struct mps_command *); +static void mpssas_remove_complete(struct mps_softc *, struct mps_command *); +static void mpssas_action(struct cam_sim *sim, union ccb *ccb); +static void mpssas_poll(struct cam_sim *sim); +static void mpssas_probe_device(struct mps_softc *sc, uint16_t handle); +static void mpssas_probe_device_complete(struct mps_softc *sc, + struct mps_config_params *params); +static void mpssas_scsiio_timeout(void *data); +static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm); +static void mpssas_recovery(struct mps_softc *, struct mps_command *); +static int mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm); +static void mpssas_issue_tm_request(struct mps_softc *sc, + struct mps_command *cm); +static void mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, + int error); +static int mpssas_complete_tm_request(struct mps_softc *sc, + struct mps_command *cm, int free_cm); +static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *); +static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *); +static void mpssas_resetdev(struct mpssas_softc *, struct mps_command *); +static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *); +static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *); +static void mpssas_freeze_device(struct mpssas_softc *, struct mpssas_target *); +static void mpssas_unfreeze_device(struct mpssas_softc *, struct mpssas_target *) __unused; + +static struct mpssas_target * +mpssas_alloc_target(struct mpssas_softc *sassc, struct mpssas_target *probe) +{ + struct mpssas_target *target; + int start; + + mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); + + /* + * If it's not a sata or sas target, CAM won't be able to see it. Put + * it into a high-numbered slot so that it's accessible but not + * interrupting the target numbering sequence of real drives. + */ + if ((probe->devinfo & (MPI2_SAS_DEVICE_INFO_SSP_TARGET | + MPI2_SAS_DEVICE_INFO_STP_TARGET | MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) + == 0) { + start = 200; + } else { + /* + * Use the enclosure number and slot number as a hint for target + * numbering. If that doesn't produce a sane result, search the + * entire space. + */ +#if 0 + start = probe->encl_handle * 16 + probe->encl_slot; +#else + start = probe->encl_slot; +#endif + if (start >= sassc->sc->facts->MaxTargets) + start = 0; + } + + target = mpssas_find_target(sassc, start, 0); + + /* + * Nothing found on the first pass, try a second pass that searches the + * entire space. + */ + if (target == NULL) + target = mpssas_find_target(sassc, 0, 0); + + return (target); +} + +static struct mpssas_target * +mpssas_find_target(struct mpssas_softc *sassc, int start, uint16_t handle) +{ + struct mpssas_target *target; + int i; + + for (i = start; i < sassc->sc->facts->MaxTargets; i++) { + target = &sassc->targets[i]; + if (target->handle == handle) + return (target); + } + + return (NULL); +} + +/* + * Start the probe sequence for a given device handle. This will not + * block. + */ +static void +mpssas_probe_device(struct mps_softc *sc, uint16_t handle) +{ + struct mpssas_devprobe *probe; + struct mps_config_params *params; + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + int error; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + probe = malloc(sizeof(*probe), M_MPSSAS, M_NOWAIT | M_ZERO); + if (probe == NULL) { + mps_dprint(sc, MPS_FAULT, "Out of memory starting probe\n"); + return; + } + params = &probe->params; + hdr = ¶ms->hdr.Ext; + + params->action = MPI2_CONFIG_ACTION_PAGE_HEADER; + params->page_address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE | handle; + hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; + hdr->ExtPageLength = 0; + hdr->PageNumber = 0; + hdr->PageVersion = 0; + params->buffer = NULL; + params->length = 0; + params->callback = mpssas_probe_device_complete; + params->cbdata = probe; + probe->target.handle = handle; + probe->state = MPSSAS_PROBE_DEV1; + + if ((error = mps_read_config_page(sc, params)) != 0) { + free(probe, M_MPSSAS); + mps_dprint(sc, MPS_FAULT, "Failure starting device probe\n"); + return; + } +} + +static void +mpssas_probe_device_complete(struct mps_softc *sc, + struct mps_config_params *params) +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + struct mpssas_devprobe *probe; + int error; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + hdr = ¶ms->hdr.Ext; + probe = params->cbdata; + + switch (probe->state) { + case MPSSAS_PROBE_DEV1: + case MPSSAS_PROBE_PHY: + case MPSSAS_PROBE_EXP: + if (params->status != MPI2_IOCSTATUS_SUCCESS) { + mps_dprint(sc, MPS_FAULT, + "Probe Failure 0x%x state %d\n", params->status, + probe->state); + free(probe, M_MPSSAS); + return; + } + params->action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + params->length = hdr->ExtPageLength * 4; + params->buffer = malloc(params->length, M_MPSSAS, + M_ZERO|M_NOWAIT); + if (params->buffer == NULL) { + mps_dprint(sc, MPS_FAULT, "Out of memory at state " + "0x%x, size 0x%x\n", probe->state, params->length); + free(probe, M_MPSSAS); + return; + } + if (probe->state == MPSSAS_PROBE_DEV1) + probe->state = MPSSAS_PROBE_DEV2; + else if (probe->state == MPSSAS_PROBE_PHY) + probe->state = MPSSAS_PROBE_PHY2; + else if (probe->state == MPSSAS_PROBE_EXP) + probe->state = MPSSAS_PROBE_EXP2; + error = mps_read_config_page(sc, params); + break; + case MPSSAS_PROBE_DEV2: + { + MPI2_CONFIG_PAGE_SAS_DEV_0 *buf; + + if (params->status != MPI2_IOCSTATUS_SUCCESS) { + mps_dprint(sc, MPS_FAULT, + "Probe Failure 0x%x state %d\n", params->status, + probe->state); + free(params->buffer, M_MPSSAS); + free(probe, M_MPSSAS); + return; + } + buf = params->buffer; + mps_print_sasdev0(sc, buf); + + probe->target.devname = mps_to_u64(&buf->DeviceName); + probe->target.devinfo = buf->DeviceInfo; + probe->target.encl_handle = buf->EnclosureHandle; + probe->target.encl_slot = buf->Slot; + + if (buf->DeviceInfo & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) { + params->page_address = + MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | buf->PhyNum; + hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; + hdr->PageNumber = 0; + probe->state = MPSSAS_PROBE_PHY; + } else { + params->page_address = + MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | + buf->ParentDevHandle | (buf->PhyNum << 16); + hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + hdr->PageNumber = 1; + probe->state = MPSSAS_PROBE_EXP; + } + params->action = MPI2_CONFIG_ACTION_PAGE_HEADER; + hdr->ExtPageLength = 0; + hdr->PageVersion = 0; + params->buffer = NULL; + params->length = 0; + free(buf, M_MPSSAS); + error = mps_read_config_page(sc, params); + break; + } + case MPSSAS_PROBE_PHY2: + case MPSSAS_PROBE_EXP2: + { + MPI2_CONFIG_PAGE_SAS_PHY_0 *phy; + MPI2_CONFIG_PAGE_EXPANDER_1 *exp; + struct mpssas_softc *sassc; + struct mpssas_target *targ; + char devstring[80]; + uint16_t handle; + + if (params->status != MPI2_IOCSTATUS_SUCCESS) { + mps_dprint(sc, MPS_FAULT, + "Probe Failure 0x%x state %d\n", params->status, + probe->state); + free(params->buffer, M_MPSSAS); + free(probe, M_MPSSAS); + return; + } + + if (probe->state == MPSSAS_PROBE_PHY2) { + phy = params->buffer; + mps_print_sasphy0(sc, phy); + probe->target.linkrate = phy->NegotiatedLinkRate & 0xf; + } else { + exp = params->buffer; + mps_print_expander1(sc, exp); + probe->target.linkrate = exp->NegotiatedLinkRate & 0xf; + } + free(params->buffer, M_MPSSAS); + + sassc = sc->sassc; + handle = probe->target.handle; + if ((targ = mpssas_find_target(sassc, 0, handle)) != NULL) { + mps_printf(sc, "Ignoring dup device handle 0x%04x\n", + handle); + free(probe, M_MPSSAS); + return; + } + if ((targ = mpssas_alloc_target(sassc, &probe->target)) == NULL) { + mps_printf(sc, "Target table overflow, handle 0x%04x\n", + handle); + free(probe, M_MPSSAS); + return; + } + + *targ = probe->target; /* Copy the attributes */ + targ->tid = targ - sassc->targets; + mps_describe_devinfo(targ->devinfo, devstring, 80); + if (bootverbose) + mps_printf(sc, "Found device <%s> <%s> <0x%04x> " + "<%d/%d>\n", devstring, + mps_describe_table(mps_linkrate_names, + targ->linkrate), targ->handle, targ->encl_handle, + targ->encl_slot); + + free(probe, M_MPSSAS); + mpssas_announce_device(sassc, targ); + break; + } + default: + printf("what?\n"); + } +} + +/* + * The MPT2 firmware performs debounce on the link to avoid transient link errors + * and false removals. When it does decide that link has been lost and a device + * need to go away, it expects that the host will perform a target reset and then + * an op remove. The reset has the side-effect of aborting any outstanding + * requests for the device, which is required for the op-remove to succeed. It's + * not clear if the host should check for the device coming back alive after the + * reset. + */ +static void +mpssas_prepare_remove(struct mpssas_softc *sassc, MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mps_softc *sc; + struct mps_command *cm; + struct mpssas_target *targ = NULL; + uint16_t handle; + + mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); + + handle = phy->AttachedDevHandle; + targ = mpssas_find_target(sassc, 0, handle); + if (targ == NULL) + /* We don't know about this device? */ + return; + + sc = sassc->sc; + cm = mps_alloc_command(sc); + if (cm == NULL) { + mps_printf(sc, "comand alloc failure in mpssas_prepare_remove\n"); + return; + } + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + req->DevHandle = targ->handle; + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + + /* SAS Hard Link Reset / SATA Link Reset */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + + cm->cm_data = NULL; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_complete = mpssas_remove_device; + cm->cm_targ = targ; + mpssas_issue_tm_request(sc, cm); +} + +static void +mpssas_remove_device(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *reply; + MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; + struct mpssas_target *targ; + uint16_t handle; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; + handle = cm->cm_targ->handle; + + mpssas_complete_tm_request(sc, cm, /*free_cm*/ 0); + + if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { + mps_printf(sc, "Failure 0x%x reseting device 0x%04x\n", + reply->IOCStatus, handle); + mps_free_command(sc, cm); + return; + } + + mps_printf(sc, "Reset aborted %d commands\n", reply->TerminationCount); + mps_free_reply(sc, cm->cm_reply_data); + + /* Reuse the existing command */ + req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)cm->cm_req; + req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; + req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; + req->DevHandle = handle; + cm->cm_data = NULL; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + cm->cm_flags &= ~MPS_CM_FLAGS_COMPLETE; + cm->cm_complete = mpssas_remove_complete; + + mps_map_command(sc, cm); + + mps_dprint(sc, MPS_INFO, "clearing target handle 0x%04x\n", handle); + targ = mpssas_find_target(sc->sassc, 0, handle); + if (targ != NULL) { + targ->handle = 0x0; + mpssas_announce_device(sc->sassc, targ); + } +} + +static void +mpssas_remove_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)cm->cm_reply; + + mps_printf(sc, "mpssas_remove_complete on target 0x%04x," + " IOCStatus= 0x%x\n", cm->cm_targ->tid, reply->IOCStatus); + + mps_free_command(sc, cm); +} + +static void +mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, + MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + struct mpssas_softc *sassc; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + sassc = sc->sassc; + mps_print_evt_sas(sc, event); + + switch (event->Event) { + case MPI2_EVENT_SAS_DISCOVERY: + { + MPI2_EVENT_DATA_SAS_DISCOVERY *data; + + data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData; + + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED) + mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n"); + if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) { + mps_dprint(sc, MPS_TRACE, "SAS discovery end event\n"); + sassc->flags &= ~MPSSAS_IN_DISCOVERY; + mpssas_discovery_end(sassc); + } + break; + } + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; + int i; + + data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) + &event->EventData; + + if (data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) { + if (bootverbose) + printf("Expander found at enclosure %d\n", + data->EnclosureHandle); + mpssas_probe_device(sc, data->ExpanderDevHandle); + } + + for (i = 0; i < data->NumEntries; i++) { + phy = &data->PHY[i]; + switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) { + case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: + mpssas_probe_device(sc, phy->AttachedDevHandle); + break; + case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: + mpssas_prepare_remove(sassc, phy); + break; + case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: + case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: + case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: + default: + break; + } + } + + break; + } + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + break; + default: + break; + } + + mps_free_reply(sc, data); +} + +static int +mpssas_register_events(struct mps_softc *sc) +{ + uint8_t events[16]; + + bzero(events, 16); + setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_SAS_DISCOVERY); + setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); + setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); + setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); + setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); + setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); + + mps_register_events(sc, events, mpssas_evt_handler, NULL, + &sc->sassc->mpssas_eh); + + return (0); +} + +int +mps_attach_sas(struct mps_softc *sc) +{ + struct mpssas_softc *sassc; + int error = 0; + int num_sim_reqs; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + sassc = malloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO); + sassc->targets = malloc(sizeof(struct mpssas_target) * + sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO); + sc->sassc = sassc; + sassc->sc = sc; + + /* + * Tell CAM that we can handle 5 fewer requests than we have + * allocated. If we allow the full number of requests, all I/O + * will halt when we run out of resources. Things work fine with + * just 1 less request slot given to CAM than we have allocated. + * We also need a couple of extra commands so that we can send down + * abort, reset, etc. requests when commands time out. Otherwise + * we could wind up in a situation with sc->num_reqs requests down + * on the card and no way to send an abort. + * + * XXX KDM need to figure out why I/O locks up if all commands are + * used. + */ + num_sim_reqs = sc->num_reqs - 5; + + if ((sassc->devq = cam_simq_alloc(num_sim_reqs)) == NULL) { + mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n"); + error = ENOMEM; + goto out; + } + + sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc, + device_get_unit(sc->mps_dev), &sc->mps_mtx, num_sim_reqs, + num_sim_reqs, sassc->devq); + if (sassc->sim == NULL) { + mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n"); + error = EINVAL; + goto out; + } + + /* + * XXX There should be a bus for every port on the adapter, but since + * we're just going to fake the topology for now, we'll pretend that + * everything is just a target on a single bus. + */ + mps_lock(sc); + if ((error = xpt_bus_register(sassc->sim, sc->mps_dev, 0)) != 0) { + mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n", + error); + mps_unlock(sc); + goto out; + } + + /* + * Assume that discovery events will start right away. Freezing + * the simq will prevent the CAM boottime scanner from running + * before discovery is complete. + */ + sassc->flags = MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY; + xpt_freeze_simq(sassc->sim, 1); + + mps_unlock(sc); + + callout_init(&sassc->discovery_callout, 1 /*mpsafe*/); + sassc->discovery_timeouts = 0; + + mpssas_register_events(sc); +out: + if (error) + mps_detach_sas(sc); + return (error); +} + +int +mps_detach_sas(struct mps_softc *sc) +{ + struct mpssas_softc *sassc; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if (sc->sassc == NULL) + return (0); + + sassc = sc->sassc; + + /* Make sure CAM doesn't wedge if we had to bail out early. */ + mps_lock(sc); + if (sassc->flags & MPSSAS_IN_STARTUP) + xpt_release_simq(sassc->sim, 1); + mps_unlock(sc); + + if (sassc->mpssas_eh != NULL) + mps_deregister_events(sc, sassc->mpssas_eh); + + mps_lock(sc); + + if (sassc->sim != NULL) { + xpt_bus_deregister(cam_sim_path(sassc->sim)); + cam_sim_free(sassc->sim, FALSE); + } + mps_unlock(sc); + + if (sassc->devq != NULL) + cam_simq_free(sassc->devq); + + free(sassc->targets, M_MPT2); + free(sassc, M_MPT2); + sc->sassc = NULL; + + return (0); +} + +static void +mpssas_discovery_end(struct mpssas_softc *sassc) +{ + struct mps_softc *sc = sassc->sc; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING) + callout_stop(&sassc->discovery_callout); + + if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) { + mps_dprint(sc, MPS_INFO, + "mpssas_discovery_end: removing confighook\n"); + sassc->flags &= ~MPSSAS_IN_STARTUP; + xpt_release_simq(sassc->sim, 1); + } +#if 0 + mpssas_announce_device(sassc, NULL); +#endif + +} + +static void +mpssas_announce_device(struct mpssas_softc *sassc, struct mpssas_target *targ) +{ + union ccb *ccb; + int bus, tid, lun; + + /* + * Force a rescan, a hackish way to announce devices. + * XXX Doing a scan on an individual device is hackish in that it + * won't scan the LUNs. + * XXX Does it matter if any of this fails? + */ + bus = cam_sim_path(sassc->sim); + if (targ != NULL) { + tid = targ->tid; + lun = 0; + } else { + tid = CAM_TARGET_WILDCARD; + lun = CAM_LUN_WILDCARD; + } + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) + return; + if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, bus, tid, + CAM_LUN_WILDCARD) != CAM_REQ_CMP) { + xpt_free_ccb(ccb); + return; + } + mps_dprint(sassc->sc, MPS_INFO, "Triggering rescan of %d:%d:-1\n", + bus, tid); + xpt_rescan(ccb); +} + +static void +mpssas_startup(void *data) +{ + struct mpssas_softc *sassc = data; + + mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); + + mps_lock(sassc->sc); + if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) { + mpssas_discovery_end(sassc); + } else { + if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) { + sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING; + callout_reset(&sassc->discovery_callout, + MPSSAS_DISCOVERY_TIMEOUT * hz, + mpssas_discovery_timeout, sassc); + sassc->discovery_timeouts++; + } else { + mps_dprint(sassc->sc, MPS_FAULT, + "Discovery timed out, continuing.\n"); + sassc->flags &= ~MPSSAS_IN_DISCOVERY; + mpssas_discovery_end(sassc); + } + } + mps_unlock(sassc->sc); + + return; +} + +static void +mpssas_discovery_timeout(void *data) +{ + struct mpssas_softc *sassc = data; + struct mps_softc *sc; + + sc = sassc->sc; + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + mps_lock(sc); + mps_printf(sc, + "Timeout waiting for discovery, interrupts may not be working!\n"); + sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING; + + /* Poll the hardware for events in case interrupts aren't working */ + mps_intr_locked(sc); + mps_unlock(sc); + + /* Check the status of discovery and re-arm the timeout if needed */ + mpssas_startup(sassc); +} + +static void +mpssas_action(struct cam_sim *sim, union ccb *ccb) +{ + struct mpssas_softc *sassc; + + sassc = cam_sim_softc(sim); + + mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__, + ccb->ccb_h.func_code); + + switch (ccb->ccb_h.func_code) { + case XPT_PATH_INQ: + { + struct ccb_pathinq *cpi = &ccb->cpi; + + cpi->version_num = 1; + cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; + cpi->target_sprt = 0; + cpi->hba_misc = PIM_NOBUSRESET; + cpi->hba_eng_cnt = 0; + cpi->max_target = sassc->sc->facts->MaxTargets - 1; + cpi->max_lun = 0; + cpi->initiator_id = 255; + strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); + strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); + strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); + cpi->unit_number = cam_sim_unit(sim); + cpi->bus_id = cam_sim_bus(sim); + cpi->base_transfer_speed = 150000; + cpi->transport = XPORT_SAS; + cpi->transport_version = 0; + cpi->protocol = PROTO_SCSI; + cpi->protocol_version = SCSI_REV_SPC; + cpi->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_GET_TRAN_SETTINGS: + { + struct ccb_trans_settings *cts; + struct ccb_trans_settings_sas *sas; + struct ccb_trans_settings_scsi *scsi; + struct mpssas_target *targ; + + cts = &ccb->cts; + sas = &cts->xport_specific.sas; + scsi = &cts->proto_specific.scsi; + + targ = &sassc->targets[cts->ccb_h.target_id]; + if (targ->handle == 0x0) { + cts->ccb_h.status = CAM_TID_INVALID; + break; + } + + cts->protocol_version = SCSI_REV_SPC2; + cts->transport = XPORT_SAS; + cts->transport_version = 0; + + sas->valid = CTS_SAS_VALID_SPEED; + switch (targ->linkrate) { + case 0x08: + sas->bitrate = 150000; + break; + case 0x09: + sas->bitrate = 300000; + break; + case 0x0a: + sas->bitrate = 600000; + break; + default: + sas->valid = 0; + } + + cts->protocol = PROTO_SCSI; + scsi->valid = CTS_SCSI_VALID_TQ; + scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; + + cts->ccb_h.status = CAM_REQ_CMP; + break; + } + case XPT_CALC_GEOMETRY: + cam_calc_geometry(&ccb->ccg, /*extended*/1); + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_RESET_DEV: + mpssas_action_resetdev(sassc, ccb); + return; + case XPT_RESET_BUS: + case XPT_ABORT: + case XPT_TERM_IO: + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case XPT_SCSI_IO: + mpssas_action_scsiio(sassc, ccb); + return; + default: + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + break; + } + xpt_done(ccb); + +} + +#if 0 +static void +mpssas_resettimeout_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *resp; + uint16_t code; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; + code = resp->ResponseCode; + + mps_free_command(sc, cm); + mpssas_unfreeze_device(sassc, targ); + + if (code != MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { + mps_reset_controller(sc); + } + + return; +} +#endif + +static void +mpssas_scsiio_timeout(void *data) +{ + union ccb *ccb; + struct mps_softc *sc; + struct mps_command *cm; + struct mpssas_target *targ; +#if 0 + char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1]; +#endif + + cm = (struct mps_command *)data; + sc = cm->cm_sc; + + /* + * Run the interrupt handler to make sure it's not pending. This + * isn't perfect because the command could have already completed + * and been re-used, though this is unlikely. + */ + mps_lock(sc); + mps_intr_locked(sc); + if (cm->cm_state == MPS_CM_STATE_FREE) { + mps_unlock(sc); + return; + } + + ccb = cm->cm_complete_data; + targ = cm->cm_targ; + if (targ == 0x00) + /* Driver bug */ + targ = &sc->sassc->targets[ccb->ccb_h.target_id]; + + xpt_print(ccb->ccb_h.path, "SCSI command timeout on device handle " + "0x%04x SMID %d\n", targ->handle, cm->cm_desc.Default.SMID); + /* + * XXX KDM this is useful for debugging purposes, but the existing + * scsi_op_desc() implementation can't handle a NULL value for + * inq_data. So this will remain commented out until I bring in + * those changes as well. + */ +#if 0 + xpt_print(ccb->ccb_h.path, "Timed out command: %s. CDB %s\n", + scsi_op_desc((ccb->ccb_h.flags & CAM_CDB_POINTER) ? + ccb->csio.cdb_io.cdb_ptr[0] : + ccb->csio.cdb_io.cdb_bytes[0], NULL), + scsi_cdb_string((ccb->ccb_h.flags & CAM_CDB_POINTER) ? + ccb->csio.cdb_io.cdb_ptr : + ccb->csio.cdb_io.cdb_bytes, cdb_str, + sizeof(cdb_str))); +#endif + + /* Inform CAM about the timeout and that recovery is starting. */ +#if 0 + if ((targ->flags & MPSSAS_TARGET_INRECOVERY) == 0) { + mpssas_freeze_device(sc->sassc, targ); + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + xpt_done(ccb); + } +#endif + mpssas_freeze_device(sc->sassc, targ); + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + + /* + * recycle the command into recovery so that there's no risk of + * command allocation failure. + */ + cm->cm_state = MPS_CM_STATE_TIMEDOUT; + mpssas_recovery(sc, cm); + mps_unlock(sc); +} + +static void +mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + + mps_printf(sc, "%s: abort request on handle %#04x SMID %d " + "complete\n", __func__, req->DevHandle, req->TaskMID); + + mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1); +} + +static void +mpssas_recovery(struct mps_softc *sc, struct mps_command *abort_cm) +{ + struct mps_command *cm; + MPI2_SCSI_TASK_MANAGE_REQUEST *req, *orig_req; + + cm = mps_alloc_command(sc); + if (cm == NULL) { + mps_printf(sc, "%s: command allocation failure\n", __func__); + return; + } + + cm->cm_targ = abort_cm->cm_targ; + cm->cm_complete = mpssas_abort_complete; + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + orig_req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)abort_cm->cm_req; + req->DevHandle = abort_cm->cm_targ->handle; + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; + memcpy(req->LUN, orig_req->LUN, sizeof(req->LUN)); + req->TaskMID = abort_cm->cm_desc.Default.SMID; + + cm->cm_data = NULL; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + mpssas_issue_tm_request(sc, cm); + +} + +/* + * Can return 0 or EINPROGRESS on success. Any other value means failure. + */ +static int +mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm) +{ + int error; + + error = 0; + + cm->cm_flags |= MPS_CM_FLAGS_ACTIVE; + error = mps_map_command(sc, cm); + if ((error == 0) + || (error == EINPROGRESS)) + sc->tm_cmds_active++; + + return (error); +} + +static void +mpssas_issue_tm_request(struct mps_softc *sc, struct mps_command *cm) +{ + int freeze_queue, send_command, error; + + freeze_queue = 0; + send_command = 0; + error = 0; + + mtx_assert(&sc->mps_mtx, MA_OWNED); + + /* + * If there are no other pending task management commands, go + * ahead and send this one. There is a small amount of anecdotal + * evidence that sending lots of task management commands at once + * may cause the controller to lock up. Or, if the user has + * configured the driver (via the allow_multiple_tm_cmds variable) to + * not serialize task management commands, go ahead and send the + * command if even other task management commands are pending. + */ + if (TAILQ_FIRST(&sc->tm_list) == NULL) { + send_command = 1; + freeze_queue = 1; + } else if (sc->allow_multiple_tm_cmds != 0) + send_command = 1; + + TAILQ_INSERT_TAIL(&sc->tm_list, cm, cm_link); + if (send_command != 0) { + /* + * Freeze the SIM queue while we issue the task management + * command. According to the Fusion-MPT 2.0 spec, task + * management requests are serialized, and so the host + * should not send any I/O requests while task management + * requests are pending. + */ + if (freeze_queue != 0) + xpt_freeze_simq(sc->sassc->sim, 1); + + error = mpssas_map_tm_request(sc, cm); + + /* + * At present, there is no error path back from + * mpssas_map_tm_request() (which calls mps_map_command()) + * when cm->cm_data == NULL. But since there is a return + * value, we check it just in case the implementation + * changes later. + */ + if ((error != 0) + && (error != EINPROGRESS)) + mpssas_tm_complete(sc, cm, + MPI2_SCSITASKMGMT_RSP_TM_FAILED); + } +} + +static void +mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, int error) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *resp; + + resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; + + resp->ResponseCode = error; + + /* + * Call the callback for this command, it will be + * removed from the list and freed via the callback. + */ + cm->cm_complete(sc, cm); +} + +/* + * Complete a task management request. The basic completion operation will + * always succeed. Returns status for sending any further task management + * commands that were queued. + */ +static int +mpssas_complete_tm_request(struct mps_softc *sc, struct mps_command *cm, + int free_cm) +{ + int error; + + error = 0; + + mtx_assert(&sc->mps_mtx, MA_OWNED); + + TAILQ_REMOVE(&sc->tm_list, cm, cm_link); + cm->cm_flags &= ~MPS_CM_FLAGS_ACTIVE; + sc->tm_cmds_active--; + + if (free_cm != 0) + mps_free_command(sc, cm); + + if (TAILQ_FIRST(&sc->tm_list) == NULL) { + /* + * Release the SIM queue, we froze it when we sent the first + * task management request. + */ + xpt_release_simq(sc->sassc->sim, 1); + } else if ((sc->tm_cmds_active == 0) + || (sc->allow_multiple_tm_cmds != 0)) { + int error; + struct mps_command *cm2; + +restart_traversal: + + /* + * We don't bother using TAILQ_FOREACH_SAFE here, but + * rather use the standard version and just restart the + * list traversal if we run into the error case. + * TAILQ_FOREACH_SAFE allows safe removal of the current + * list element, but if you have a queue of task management + * commands, all of which have mapping errors, you'll end + * up with recursive calls to this routine and so you could + * wind up removing more than just the current list element. + */ + TAILQ_FOREACH(cm2, &sc->tm_list, cm_link) { + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + + /* This command is active, no need to send it again */ + if (cm2->cm_flags & MPS_CM_FLAGS_ACTIVE) + continue; + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm2->cm_req; + + mps_printf(sc, "%s: sending deferred task management " + "request for handle %#04x SMID %d\n", __func__, + req->DevHandle, req->TaskMID); + + error = mpssas_map_tm_request(sc, cm2); + + /* + * Check for errors. If we had an error, complete + * this command with an error, and keep going through + * the list until we are able to send at least one + * command or all of them are completed with errors. + * + * We don't want to wind up in a situation where + * we're stalled out with no way for queued task + * management commands to complete. + * + * Note that there is not currently an error path + * back from mpssas_map_tm_request() (which calls + * mps_map_command()) when cm->cm_data == NULL. + * But we still want to check for errors here in + * case the implementation changes, or in case + * there is some reason for a data payload here. + */ + if ((error != 0) + && (error != EINPROGRESS)) { + mpssas_tm_complete(sc, cm, + MPI2_SCSITASKMGMT_RSP_TM_FAILED); + + /* + * If we don't currently have any commands + * active, go back to the beginning and see + * if there are any more that can be started. + * Otherwise, we're done here. + */ + if (sc->tm_cmds_active == 0) + goto restart_traversal; + else + break; + } + + /* + * If the user only wants one task management command + * active at a time, we're done, since we've + * already successfully sent a command at this point. + */ + if (sc->allow_multiple_tm_cmds == 0) + break; + } + } + + return (error); +} + +static void +mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb) +{ + MPI2_SCSI_IO_REQUEST *req; + struct ccb_scsiio *csio; + struct mps_softc *sc; + struct mpssas_target *targ; + struct mps_command *cm; + + mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); + + sc = sassc->sc; + + csio = &ccb->csio; + targ = &sassc->targets[csio->ccb_h.target_id]; + if (targ->handle == 0x0) { + csio->ccb_h.status = CAM_SEL_TIMEOUT; + xpt_done(ccb); + return; + } + + cm = mps_alloc_command(sc); + if (cm == NULL) { + if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) { + xpt_freeze_simq(sassc->sim, 1); + sassc->flags |= MPSSAS_QUEUE_FROZEN; + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; + ccb->ccb_h.status |= CAM_REQUEUE_REQ; + xpt_done(ccb); + return; + } + + req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; + req->DevHandle = targ->handle; + req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + req->MsgFlags = 0; + req->SenseBufferLowAddress = cm->cm_sense_busaddr; + req->SenseBufferLength = MPS_SENSE_LEN; + req->SGLFlags = 0; + req->ChainOffset = 0; + req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ + req->SGLOffset1= 0; + req->SGLOffset2= 0; + req->SGLOffset3= 0; + req->SkipCount = 0; + req->DataLength = csio->dxfer_len; + req->BidirectionalDataLength = 0; + req->IoFlags = csio->cdb_len; + req->EEDPFlags = 0; + + /* Note: BiDirectional transfers are not supported */ + switch (csio->ccb_h.flags & CAM_DIR_MASK) { + case CAM_DIR_IN: + req->Control = MPI2_SCSIIO_CONTROL_READ; + cm->cm_flags |= MPS_CM_FLAGS_DATAIN; + break; + case CAM_DIR_OUT: + req->Control = MPI2_SCSIIO_CONTROL_WRITE; + cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; + break; + case CAM_DIR_NONE: + default: + req->Control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; + break; + } + + /* + * It looks like the hardware doesn't require an explicit tag + * number for each transaction. SAM Task Management not supported + * at the moment. + */ + switch (csio->tag_action) { + case MSG_HEAD_OF_Q_TAG: + req->Control |= MPI2_SCSIIO_CONTROL_HEADOFQ; + break; + case MSG_ORDERED_Q_TAG: + req->Control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; + break; + case MSG_ACA_TASK: + req->Control |= MPI2_SCSIIO_CONTROL_ACAQ; + break; + case CAM_TAG_ACTION_NONE: + case MSG_SIMPLE_Q_TAG: + default: + req->Control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; + break; + } + + /* XXX Need to handle multi-level LUNs */ + if (csio->ccb_h.target_lun > 255) { + mps_free_command(sc, cm); + ccb->ccb_h.status = CAM_LUN_INVALID; + xpt_done(ccb); + return; + } + req->LUN[1] = csio->ccb_h.target_lun; + + if (csio->ccb_h.flags & CAM_CDB_POINTER) + bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); + else + bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); + req->IoFlags = csio->cdb_len; + + cm->cm_data = csio->data_ptr; + cm->cm_length = csio->dxfer_len; + cm->cm_sge = &req->SGL; + cm->cm_sglsize = (32 - 24) * 4; + cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + cm->cm_desc.SCSIIO.DevHandle = targ->handle; + cm->cm_complete = mpssas_scsiio_complete; + cm->cm_complete_data = ccb; + cm->cm_targ = targ; + + callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, + mpssas_scsiio_timeout, cm); + + mps_map_command(sc, cm); + return; +} + +static void +mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_IO_REPLY *rep; + union ccb *ccb; + struct mpssas_softc *sassc; + u_int sense_len; + int dir = 0; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + callout_stop(&cm->cm_callout); + + sassc = sc->sassc; + ccb = cm->cm_complete_data; + rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; + + if (cm->cm_data != NULL) { + if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) + dir = BUS_DMASYNC_POSTREAD; + else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) + dir = BUS_DMASYNC_POSTWRITE;; + bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); + bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); + } + + if (sassc->flags & MPSSAS_QUEUE_FROZEN) { + ccb->ccb_h.flags |= CAM_RELEASE_SIMQ; + sassc->flags &= ~MPSSAS_QUEUE_FROZEN; + } + + /* Take the fast path to completion */ + if (cm->cm_reply == NULL) { + ccb->ccb_h.status = CAM_REQ_CMP; + ccb->csio.scsi_status = SCSI_STATUS_OK; + mps_free_command(sc, cm); + xpt_done(ccb); + return; + } + + mps_dprint(sc, MPS_INFO, "(%d:%d:%d) IOCStatus= 0x%x, " + "ScsiStatus= 0x%x, SCSIState= 0x%x TransferCount= 0x%x\n", + xpt_path_path_id(ccb->ccb_h.path), + xpt_path_target_id(ccb->ccb_h.path), + xpt_path_lun_id(ccb->ccb_h.path), rep->IOCStatus, + rep->SCSIStatus, rep->SCSIState, rep->TransferCount); + + switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) { + case MPI2_IOCSTATUS_BUSY: + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + /* + * The controller is overloaded, try waiting a bit for it + * to free up. + */ + ccb->ccb_h.status = CAM_BUSY; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + ccb->csio.resid = cm->cm_length - rep->TransferCount; + /* FALLTHROUGH */ + case MPI2_IOCSTATUS_SUCCESS: + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + ccb->ccb_h.status = CAM_REQ_CMP; + break; + case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: + /* resid is ignored for this condition */ + ccb->csio.resid = 0; + ccb->ccb_h.status = CAM_DATA_RUN_ERR; + break; + case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: + case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: + ccb->ccb_h.status = CAM_DEV_NOT_THERE; + break; + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + /* + * This is one of the responses that comes back when an I/O + * has been aborted. If it is because of a timeout that we + * initiated, just set the status to CAM_CMD_TIMEOUT. + * Otherwise set it to CAM_REQ_ABORTED. The effect on the + * command is the same (it gets retried, subject to the + * retry counter), the only difference is what gets printed + * on the console. + */ + if (cm->cm_state == MPS_CM_STATE_TIMEDOUT) + ccb->ccb_h.status = CAM_CMD_TIMEOUT; + else + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + case MPI2_IOCSTATUS_INVALID_SGL: + mps_print_scsiio_cmd(sc, cm); + ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; + break; + case MPI2_IOCSTATUS_INVALID_FUNCTION: + case MPI2_IOCSTATUS_INTERNAL_ERROR: + case MPI2_IOCSTATUS_INVALID_VPID: + case MPI2_IOCSTATUS_INVALID_FIELD: + case MPI2_IOCSTATUS_INVALID_STATE: + case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: + case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: + default: + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + } + + + if ((rep->SCSIState & MPI2_SCSI_STATE_NO_SCSI_STATUS) == 0) { + ccb->csio.scsi_status = rep->SCSIStatus; + + switch (rep->SCSIStatus) { + case MPI2_SCSI_STATUS_TASK_SET_FULL: + case MPI2_SCSI_STATUS_CHECK_CONDITION: + ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; + break; + case MPI2_SCSI_STATUS_COMMAND_TERMINATED: + case MPI2_SCSI_STATUS_TASK_ABORTED: + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + case MPI2_SCSI_STATUS_GOOD: + default: + break; + } + } + + if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { + sense_len = MIN(rep->SenseCount, + sizeof(struct scsi_sense_data)); + if (sense_len < rep->SenseCount) + ccb->csio.sense_resid = rep->SenseCount - sense_len; + bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len); + ccb->ccb_h.status |= CAM_AUTOSNS_VALID; + } + + if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) + ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; + + if (rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + + mps_free_command(sc, cm); + xpt_done(ccb); +} + +static void +mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb) +{ + struct mps_softc *sc; + struct mps_command *cm; + struct mpssas_target *targ; + + sc = sassc->sc; + targ = &sassc->targets[ccb->ccb_h.target_id]; + + if (targ->flags & MPSSAS_TARGET_INRECOVERY) { + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + cm = mps_alloc_command(sc); + if (cm == NULL) { + mps_printf(sc, "%s: cannot alloc command\n", __func__); + ccb->ccb_h.status = CAM_RESRC_UNAVAIL; + xpt_done(ccb); + return; + } + + cm->cm_targ = targ; + cm->cm_complete = mpssas_resetdev_complete; + cm->cm_complete_data = ccb; + + mpssas_resetdev(sassc, cm); +} + +static void +mpssas_resetdev(struct mpssas_softc *sassc, struct mps_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REQUEST *req; + struct mps_softc *sc; + + mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__); + + sc = sassc->sc; + + req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; + req->DevHandle = cm->cm_targ->handle; + req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + + /* SAS Hard Link Reset / SATA Link Reset */ + req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + + cm->cm_data = NULL; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + mpssas_issue_tm_request(sc, cm); +} + +static void +mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_TASK_MANAGE_REPLY *resp; + union ccb *ccb; + + mps_dprint(sc, MPS_TRACE, "%s\n", __func__); + + resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply; + ccb = cm->cm_complete_data; + + printf("resetdev complete IOCStatus= 0x%x ResponseCode= 0x%x\n", + resp->IOCStatus, resp->ResponseCode); + + if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) + ccb->ccb_h.status = CAM_REQ_CMP; + else + ccb->ccb_h.status = CAM_REQ_CMP_ERR; + + mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1); + + xpt_done(ccb); +} + +static void +mpssas_poll(struct cam_sim *sim) +{ + struct mpssas_softc *sassc; + + sassc = cam_sim_softc(sim); + mps_intr_locked(sassc->sc); +} + +static void +mpssas_freeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ) +{ +} + +static void +mpssas_unfreeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ) +{ +} + diff --git a/sys/dev/mps/mps_table.c b/sys/dev/mps/mps_table.c new file mode 100644 index 00000000000..55110a182e6 --- /dev/null +++ b/sys/dev/mps/mps_table.c @@ -0,0 +1,493 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* Debugging tables for MPT2 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +char * +mps_describe_table(struct mps_table_lookup *table, u_int code) +{ + int i; + + for (i = 0; table[i].string != NULL; i++) { + if (table[i].code == code) + return(table[i].string); + } + return(table[i+1].string); +} + +struct mps_table_lookup mps_event_names[] = { + {"LogData", 0x01}, + {"StateChange", 0x02}, + {"HardResetReceived", 0x05}, + {"EventChange", 0x0a}, + {"TaskSetFull", 0x0e}, + {"SasDeviceStatusChange", 0x0f}, + {"IrOperationStatus", 0x14}, + {"SasDiscovery", 0x16}, + {"SasBroadcastPrimitive", 0x17}, + {"SasInitDeviceStatusChange", 0x18}, + {"SasInitTableOverflow", 0x19}, + {"SasTopologyChangeList", 0x1c}, + {"SasEnclDeviceStatusChange", 0x1d}, + {"IrVolume", 0x1e}, + {"IrPhysicalDisk", 0x1f}, + {"IrConfigurationChangeList", 0x20}, + {"LogEntryAdded", 0x21}, + {"SasPhyCounter", 0x22}, + {"GpioInterrupt", 0x23}, + {"HbdPhyEvent", 0x24}, + {NULL, 0}, + {"Unknown Event", 0} +}; + +struct mps_table_lookup mps_phystatus_names[] = { + {"NewTargetAdded", 0x01}, + {"TargetGone", 0x02}, + {"PHYLinkStatusChange", 0x03}, + {"PHYLinkStatusUnchanged", 0x04}, + {"TargetMissing", 0x05}, + {NULL, 0}, + {"Unknown Status", 0} +}; + +struct mps_table_lookup mps_linkrate_names[] = { + {"PHY disabled", 0x01}, + {"Speed Negotiation Failed", 0x02}, + {"SATA OOB Complete", 0x03}, + {"SATA Port Selector", 0x04}, + {"SMP Reset in Progress", 0x05}, + {"1.5Gbps", 0x08}, + {"3.0Gbps", 0x09}, + {"6.0Gbps", 0x0a}, + {NULL, 0}, + {"LinkRate Unknown", 0x00} +}; + +struct mps_table_lookup mps_sasdev0_devtype[] = { + {"End Device", 0x01}, + {"Edge Expander", 0x02}, + {"Fanout Expander", 0x03}, + {NULL, 0}, + {"No Device", 0x00} +}; + +struct mps_table_lookup mps_phyinfo_reason_names[] = { + {"Power On", 0x01}, + {"Hard Reset", 0x02}, + {"SMP Phy Control Link Reset", 0x03}, + {"Loss DWORD Sync", 0x04}, + {"Multiplex Sequence", 0x05}, + {"I-T Nexus Loss Timer", 0x06}, + {"Break Timeout Timer", 0x07}, + {"PHY Test Function", 0x08}, + {NULL, 0}, + {"Unknown Reason", 0x00} +}; + +struct mps_table_lookup mps_whoinit_names[] = { + {"System BIOS", 0x01}, + {"ROM BIOS", 0x02}, + {"PCI Peer", 0x03}, + {"Host Driver", 0x04}, + {"Manufacturing", 0x05}, + {NULL, 0}, + {"Not Initialized", 0x00} +}; + +struct mps_table_lookup mps_sasdisc_reason[] = { + {"Discovery Started", 0x01}, + {"Discovery Complete", 0x02}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +struct mps_table_lookup mps_sastopo_exp[] = { + {"Added", 0x01}, + {"Not Responding", 0x02}, + {"Responding", 0x03}, + {"Delay Not Responding", 0x04}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +struct mps_table_lookup mps_sasdev_reason[] = { + {"SMART Data", 0x05}, + {"Unsupported", 0x07}, + {"Internal Device Reset", 0x08}, + {"Task Abort Internal", 0x09}, + {"Abort Task Set Internal", 0x0a}, + {"Clear Task Set Internal", 0x0b}, + {"Query Task Internal", 0x0c}, + {"Async Notification", 0x0d}, + {"Cmp Internal Device Reset", 0x0e}, + {"Cmp Task Abort Internal", 0x0f}, + {"Sata Init Failure", 0x10}, + {NULL, 0}, + {"Unknown", 0x00} +}; + +void +mps_describe_devinfo(uint32_t devinfo, char *string, int len) +{ + snprintf(string, len, "%b,%s", devinfo, + "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit" + "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct" + "\15LsiDev" "\16AtapiDev" "\17SepDev", + mps_describe_table(mps_sasdev0_devtype, devinfo & 0x03)); +} + +void +mps_print_iocfacts(struct mps_softc *sc, MPI2_IOC_FACTS_REPLY *facts) +{ + + MPS_PRINTFIELD_START(sc, "IOCFacts"); + MPS_PRINTFIELD(sc, facts, MsgVersion, 0x%x); + MPS_PRINTFIELD(sc, facts, HeaderVersion, 0x%x); + MPS_PRINTFIELD(sc, facts, IOCNumber, %d); + MPS_PRINTFIELD(sc, facts, IOCExceptions, 0x%x); + MPS_PRINTFIELD(sc, facts, MaxChainDepth, %d); + mps_dprint_field(sc, MPS_INFO, "WhoInit: %s\n", + mps_describe_table(mps_whoinit_names, facts->WhoInit)); + MPS_PRINTFIELD(sc, facts, NumberOfPorts, %d); + MPS_PRINTFIELD(sc, facts, RequestCredit, %d); + MPS_PRINTFIELD(sc, facts, ProductID, 0x%x); + mps_dprint_field(sc, MPS_INFO, "IOCCapabilities: %b\n", + facts->IOCCapabilities, "\20" "\3ScsiTaskFull" "\4DiagTrace" + "\5SnapBuf" "\6ExtBuf" "\7EEDP" "\10BiDirTarg" "\11Multicast" + "\14TransRetry" "\15IR" "\16EventReplay" "\17RaidAccel" + "\20MSIXIndex" "\21HostDisc"); + mps_dprint_field(sc, MPS_INFO, "FWVersion= %d-%d-%d-%d\n", + facts->FWVersion.Struct.Major, + facts->FWVersion.Struct.Minor, + facts->FWVersion.Struct.Unit, + facts->FWVersion.Struct.Dev); + MPS_PRINTFIELD(sc, facts, IOCRequestFrameSize, %d); + MPS_PRINTFIELD(sc, facts, MaxInitiators, %d); + MPS_PRINTFIELD(sc, facts, MaxTargets, %d); + MPS_PRINTFIELD(sc, facts, MaxSasExpanders, %d); + MPS_PRINTFIELD(sc, facts, MaxEnclosures, %d); + mps_dprint_field(sc, MPS_INFO, "ProtocolFlags: %b\n", + facts->ProtocolFlags, "\20" "\1ScsiTarg" "\2ScsiInit"); + MPS_PRINTFIELD(sc, facts, HighPriorityCredit, %d); + MPS_PRINTFIELD(sc, facts, MaxReplyDescriptorPostQueueDepth, %d); + MPS_PRINTFIELD(sc, facts, ReplyFrameSize, %d); + MPS_PRINTFIELD(sc, facts, MaxVolumes, %d); + MPS_PRINTFIELD(sc, facts, MaxDevHandle, %d); + MPS_PRINTFIELD(sc, facts, MaxPersistentEntries, %d); +} + +void +mps_print_portfacts(struct mps_softc *sc, MPI2_PORT_FACTS_REPLY *facts) +{ + + MPS_PRINTFIELD_START(sc, "PortFacts"); + MPS_PRINTFIELD(sc, facts, PortNumber, %d); + MPS_PRINTFIELD(sc, facts, PortType, 0x%x); + MPS_PRINTFIELD(sc, facts, MaxPostedCmdBuffers, %d); +} + +void +mps_print_event(struct mps_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + + MPS_EVENTFIELD_START(sc, "EventReply"); + MPS_EVENTFIELD(sc, event, EventDataLength, %d); + MPS_EVENTFIELD(sc, event, AckRequired, %d); + mps_dprint_field(sc, MPS_EVENT, "Event: %s (0x%x)\n", + mps_describe_table(mps_event_names, event->Event), event->Event); + MPS_EVENTFIELD(sc, event, EventContext, 0x%x); +} + +void +mps_print_sasdev0(struct mps_softc *sc, MPI2_CONFIG_PAGE_SAS_DEV_0 *buf) +{ + MPS_PRINTFIELD_START(sc, "SAS Device Page 0"); + MPS_PRINTFIELD(sc, buf, Slot, %d); + MPS_PRINTFIELD(sc, buf, EnclosureHandle, 0x%x); + mps_dprint_field(sc, MPS_INFO, "SASAddress: 0x%jx\n", + mps_to_u64(&buf->SASAddress)); + MPS_PRINTFIELD(sc, buf, ParentDevHandle, 0x%x); + MPS_PRINTFIELD(sc, buf, PhyNum, %d); + MPS_PRINTFIELD(sc, buf, AccessStatus, 0x%x); + MPS_PRINTFIELD(sc, buf, DevHandle, 0x%x); + MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, 0x%x); + MPS_PRINTFIELD(sc, buf, ZoneGroup, %d); + mps_dprint_field(sc, MPS_INFO, "DeviceInfo: %b,%s\n", buf->DeviceInfo, + "\20" "\4SataHost" "\5SmpInit" "\6StpInit" "\7SspInit" + "\10SataDev" "\11SmpTarg" "\12StpTarg" "\13SspTarg" "\14Direct" + "\15LsiDev" "\16AtapiDev" "\17SepDev", + mps_describe_table(mps_sasdev0_devtype, buf->DeviceInfo & 0x03)); + MPS_PRINTFIELD(sc, buf, Flags, 0x%x); + MPS_PRINTFIELD(sc, buf, PhysicalPort, %d); + MPS_PRINTFIELD(sc, buf, MaxPortConnections, %d); + mps_dprint_field(sc, MPS_INFO, "DeviceName: 0x%jx\n", + mps_to_u64(&buf->DeviceName)); + MPS_PRINTFIELD(sc, buf, PortGroups, %d); + MPS_PRINTFIELD(sc, buf, DmaGroup, %d); + MPS_PRINTFIELD(sc, buf, ControlGroup, %d); +} + +void +mps_print_evt_sas(struct mps_softc *sc, MPI2_EVENT_NOTIFICATION_REPLY *event) +{ + + mps_print_event(sc, event); + + switch(event->Event) { + case MPI2_EVENT_SAS_DISCOVERY: + { + MPI2_EVENT_DATA_SAS_DISCOVERY *data; + + data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData; + mps_dprint_field(sc, MPS_EVENT, "Flags: %b\n", data->Flags, + "\20" "\1InProgress" "\2DeviceChange"); + mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n", + mps_describe_table(mps_sasdisc_reason, data->ReasonCode)); + MPS_EVENTFIELD(sc, data, PhysicalPort, %d); + mps_dprint_field(sc, MPS_EVENT, "DiscoveryStatus: %b\n", + data->DiscoveryStatus, "\20" + "\1Loop" "\2UnaddressableDev" "\3DupSasAddr" "\5SmpTimeout" + "\6ExpRouteFull" "\7RouteIndexError" "\10SmpFailed" + "\11SmpCrcError" "\12SubSubLink" "\13TableTableLink" + "\14UnsupDevice" "\15TableSubLink" "\16MultiDomain" + "\17MultiSub" "\20MultiSubSub" "\34DownstreamInit" + "\35MaxPhys" "\36MaxTargs" "\37MaxExpanders" + "\40MaxEnclosures"); + break; + } + case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: + { + MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data; + MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy; + int i, phynum; + + data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *) + &event->EventData; + MPS_EVENTFIELD(sc, data, EnclosureHandle, 0x%x); + MPS_EVENTFIELD(sc, data, ExpanderDevHandle, 0x%x); + MPS_EVENTFIELD(sc, data, NumPhys, %d); + MPS_EVENTFIELD(sc, data, NumEntries, %d); + MPS_EVENTFIELD(sc, data, StartPhyNum, %d); + mps_dprint_field(sc, MPS_EVENT, "ExpStatus: %s (0x%x)\n", + mps_describe_table(mps_sastopo_exp, data->ExpStatus), + data->ExpStatus); + MPS_EVENTFIELD(sc, data, PhysicalPort, %d); + for (i = 0; i < data->NumEntries; i++) { + phy = &data->PHY[i]; + phynum = data->StartPhyNum + i; + mps_dprint_field(sc, MPS_EVENT, + "PHY[%d].AttachedDevHandle: 0x%04x\n", phynum, + phy->AttachedDevHandle); + mps_dprint_field(sc, MPS_EVENT, + "PHY[%d].LinkRate: %s (0x%x)\n", phynum, + mps_describe_table(mps_linkrate_names, + (phy->LinkRate >> 4) & 0xf), phy->LinkRate); + mps_dprint_field(sc,MPS_EVENT,"PHY[%d].PhyStatus: %s\n", + phynum, mps_describe_table(mps_phystatus_names, + phy->PhyStatus)); + } + break; + } + case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: + { + MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *data; + + data = (MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE *) + &event->EventData; + MPS_EVENTFIELD(sc, data, EnclosureHandle, 0x%x); + mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n", + mps_describe_table(mps_sastopo_exp, data->ReasonCode)); + MPS_EVENTFIELD(sc, data, PhysicalPort, %d); + MPS_EVENTFIELD(sc, data, NumSlots, %d); + MPS_EVENTFIELD(sc, data, StartSlot, %d); + MPS_EVENTFIELD(sc, data, PhyBits, 0x%x); + break; + } + case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *data; + + data = (MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *) + &event->EventData; + MPS_EVENTFIELD(sc, data, TaskTag, 0x%x); + mps_dprint_field(sc, MPS_EVENT, "ReasonCode: %s\n", + mps_describe_table(mps_sasdev_reason, data->ReasonCode)); + MPS_EVENTFIELD(sc, data, ASC, 0x%x); + MPS_EVENTFIELD(sc, data, ASCQ, 0x%x); + MPS_EVENTFIELD(sc, data, DevHandle, 0x%x); + mps_dprint_field(sc, MPS_EVENT, "SASAddress: 0x%jx\n", + mps_to_u64(&data->SASAddress)); + } + default: + break; + } +} + +void +mps_print_expander1(struct mps_softc *sc, MPI2_CONFIG_PAGE_EXPANDER_1 *buf) +{ + MPS_PRINTFIELD_START(sc, "SAS Expander Page 1 #%d", buf->Phy); + MPS_PRINTFIELD(sc, buf, PhysicalPort, %d); + MPS_PRINTFIELD(sc, buf, NumPhys, %d); + MPS_PRINTFIELD(sc, buf, Phy, %d); + MPS_PRINTFIELD(sc, buf, NumTableEntriesProgrammed, %d); + mps_dprint_field(sc, MPS_INFO, "ProgrammedLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate); + mps_dprint_field(sc, MPS_INFO, "HwLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate); + MPS_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x); + mps_dprint_field(sc, MPS_INFO, "PhyInfo Reason: %s (0x%x)\n", + mps_describe_table(mps_phyinfo_reason_names, + (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo); + mps_dprint_field(sc, MPS_INFO, "AttachedDeviceInfo: %b,%s\n", + buf->AttachedDeviceInfo, "\20" "\4SATAhost" "\5SMPinit" "\6STPinit" + "\7SSPinit" "\10SATAdev" "\11SMPtarg" "\12STPtarg" "\13SSPtarg" + "\14Direct" "\15LSIdev" "\16ATAPIdev" "\17SEPdev", + mps_describe_table(mps_sasdev0_devtype, + buf->AttachedDeviceInfo & 0x03)); + MPS_PRINTFIELD(sc, buf, ExpanderDevHandle, 0x%04x); + MPS_PRINTFIELD(sc, buf, ChangeCount, %d); + mps_dprint_field(sc, MPS_INFO, "NegotiatedLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate); + MPS_PRINTFIELD(sc, buf, PhyIdentifier, %d); + MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d); + MPS_PRINTFIELD(sc, buf, DiscoveryInfo, 0x%x); + MPS_PRINTFIELD(sc, buf, AttachedPhyInfo, 0x%x); + mps_dprint_field(sc, MPS_INFO, "AttachedPhyInfo Reason: %s (0x%x)\n", + mps_describe_table(mps_phyinfo_reason_names, + buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo); + MPS_PRINTFIELD(sc, buf, ZoneGroup, %d); + MPS_PRINTFIELD(sc, buf, SelfConfigStatus, 0x%x); +} + +void +mps_print_sasphy0(struct mps_softc *sc, MPI2_CONFIG_PAGE_SAS_PHY_0 *buf) +{ + MPS_PRINTFIELD_START(sc, "SAS PHY Page 0"); + MPS_PRINTFIELD(sc, buf, OwnerDevHandle, 0x%04x); + MPS_PRINTFIELD(sc, buf, AttachedDevHandle, 0x%04x); + MPS_PRINTFIELD(sc, buf, AttachedPhyIdentifier, %d); + mps_dprint_field(sc, MPS_INFO, "AttachedPhyInfo Reason: %s (0x%x)\n", + mps_describe_table(mps_phyinfo_reason_names, + buf->AttachedPhyInfo & 0xf), buf->AttachedPhyInfo); + mps_dprint_field(sc, MPS_INFO, "ProgrammedLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + (buf->ProgrammedLinkRate >> 4) & 0xf), buf->ProgrammedLinkRate); + mps_dprint_field(sc, MPS_INFO, "HwLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + (buf->HwLinkRate >> 4) & 0xf), buf->HwLinkRate); + MPS_PRINTFIELD(sc, buf, ChangeCount, %d); + MPS_PRINTFIELD(sc, buf, Flags, 0x%x); + mps_dprint_field(sc, MPS_INFO, "PhyInfo Reason: %s (0x%x)\n", + mps_describe_table(mps_phyinfo_reason_names, + (buf->PhyInfo >> 16) & 0xf), buf->PhyInfo); + mps_dprint_field(sc, MPS_INFO, "NegotiatedLinkRate: %s (0x%x)\n", + mps_describe_table(mps_linkrate_names, + buf->NegotiatedLinkRate & 0xf), buf->NegotiatedLinkRate); +} + +void +mps_print_sgl(struct mps_softc *sc, struct mps_command *cm, int offset) +{ + MPI2_SGE_SIMPLE64 *sge; + MPI2_SGE_CHAIN32 *sgc; + MPI2_REQUEST_HEADER *req; + struct mps_chain *chain = NULL; + char *frame; + u_int i = 0, flags; + + req = (MPI2_REQUEST_HEADER *)cm->cm_req; + frame = (char *)cm->cm_req; + sge = (MPI2_SGE_SIMPLE64 *)&frame[offset * 4]; + printf("SGL for command %p\n", cm); + + while (frame != NULL) { + flags = sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT; + printf("seg%d flags=0x%x len=0x%x addr=0x%jx\n", i, flags, + sge->FlagsLength & 0xffffff, mps_to_u64(&sge->Address)); + if (flags & (MPI2_SGE_FLAGS_END_OF_LIST | + MPI2_SGE_FLAGS_END_OF_BUFFER)) + break; + sge++; + i++; + if (flags & MPI2_SGE_FLAGS_LAST_ELEMENT) { + sgc = (MPI2_SGE_CHAIN32 *)sge; + printf("chain flags=0x%x len=0x%x Offset=0x%x " + "Address=0x%x\n", sgc->Flags, sgc->Length, + sgc->NextChainOffset, sgc->Address); + if (chain == NULL) + chain = TAILQ_FIRST(&cm->cm_chain_list); + else + chain = TAILQ_NEXT(chain, chain_link); + frame = (char *)chain->chain; + sge = (MPI2_SGE_SIMPLE64 *)frame; + hexdump(frame, 128, NULL, 0); + } + } +} + +void +mps_print_scsiio_cmd(struct mps_softc *sc, struct mps_command *cm) +{ + MPI2_SCSI_IO_REQUEST *req; + + req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; + mps_print_sgl(sc, cm, req->SGLOffset0); +} + diff --git a/sys/dev/mps/mps_table.h b/sys/dev/mps/mps_table.h new file mode 100644 index 00000000000..88aa2c38546 --- /dev/null +++ b/sys/dev/mps/mps_table.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MPS_TABLE_H +#define _MPS_TABLE_H + +struct mps_table_lookup { + char *string; + u_int code; +}; + +char * mps_describe_table(struct mps_table_lookup *table, u_int code); +void mps_describe_devinfo(uint32_t devinfo, char *string, int len); + +extern struct mps_table_lookup mps_event_names[]; +extern struct mps_table_lookup mps_phystatus_names[]; +extern struct mps_table_lookup mps_linkrate_names[]; + +void mps_print_iocfacts(struct mps_softc *, MPI2_IOC_FACTS_REPLY *); +void mps_print_portfacts(struct mps_softc *, MPI2_PORT_FACTS_REPLY *); +void mps_print_event(struct mps_softc *, MPI2_EVENT_NOTIFICATION_REPLY *); +void mps_print_sasdev0(struct mps_softc *, MPI2_CONFIG_PAGE_SAS_DEV_0 *); +void mps_print_evt_sas(struct mps_softc *, MPI2_EVENT_NOTIFICATION_REPLY *); +void mps_print_expander1(struct mps_softc *, MPI2_CONFIG_PAGE_EXPANDER_1 *); +void mps_print_sasphy0(struct mps_softc *, MPI2_CONFIG_PAGE_SAS_PHY_0 *); +void mps_print_sgl(struct mps_softc *, struct mps_command *, int); +void mps_print_scsiio_cmd(struct mps_softc *, struct mps_command *); +#endif diff --git a/sys/dev/mps/mps_user.c b/sys/dev/mps/mps_user.c new file mode 100644 index 00000000000..ede4c0268eb --- /dev/null +++ b/sys/dev/mps/mps_user.c @@ -0,0 +1,944 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * LSI MPS-Fusion Host Adapter FreeBSD userland interface + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +static d_open_t mps_open; +static d_close_t mps_close; +static d_ioctl_t mps_ioctl_devsw; + +static struct cdevsw mps_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = mps_open, + .d_close = mps_close, + .d_ioctl = mps_ioctl_devsw, + .d_name = "mps", +}; + +typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *); +static mps_user_f mpi_pre_ioc_facts; +static mps_user_f mpi_pre_port_facts; +static mps_user_f mpi_pre_fw_download; +static mps_user_f mpi_pre_fw_upload; +static mps_user_f mpi_pre_sata_passthrough; +static mps_user_f mpi_pre_smp_passthrough; +static mps_user_f mpi_pre_config; +static mps_user_f mpi_pre_sas_io_unit_control; + +static int mps_user_read_cfg_header(struct mps_softc *, + struct mps_cfg_page_req *); +static int mps_user_read_cfg_page(struct mps_softc *, + struct mps_cfg_page_req *, void *); +static int mps_user_read_extcfg_header(struct mps_softc *, + struct mps_ext_cfg_page_req *); +static int mps_user_read_extcfg_page(struct mps_softc *, + struct mps_ext_cfg_page_req *, void *); +static int mps_user_write_cfg_page(struct mps_softc *, + struct mps_cfg_page_req *, void *); +static int mps_user_setup_request(struct mps_command *, + struct mps_usr_command *); +static int mps_user_command(struct mps_softc *, struct mps_usr_command *); + +static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); + +int +mps_attach_user(struct mps_softc *sc) +{ + int unit; + + unit = device_get_unit(sc->mps_dev); + sc->mps_cdev = make_dev(&mps_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640, + "mps%d", unit); + if (sc->mps_cdev == NULL) { + return (ENOMEM); + } + sc->mps_cdev->si_drv1 = sc; + return (0); +} + +void +mps_detach_user(struct mps_softc *sc) +{ + + /* XXX: do a purge of pending requests? */ + destroy_dev(sc->mps_cdev); + +} + +static int +mps_open(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +static int +mps_close(struct cdev *dev, int flags, int fmt, struct thread *td) +{ + + return (0); +} + +static int +mps_user_read_cfg_header(struct mps_softc *sc, + struct mps_cfg_page_req *page_req) +{ + MPI2_CONFIG_PAGE_HEADER *hdr; + struct mps_config_params params; + int error; + + hdr = ¶ms.hdr.Struct; + params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; + params.page_address = le32toh(page_req->page_address); + hdr->PageVersion = 0; + hdr->PageLength = 0; + hdr->PageNumber = page_req->header.PageNumber; + hdr->PageType = page_req->header.PageType; + params.buffer = NULL; + params.length = 0; + params.callback = NULL; + + if ((error = mps_read_config_page(sc, ¶ms)) != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mps_printf(sc, "read_cfg_header timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) == + MPI2_IOCSTATUS_SUCCESS) { + bcopy(hdr, &page_req->header, sizeof(page_req->header)); + } + + return (0); +} + +static int +mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req, + void *buf) +{ + MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; + struct mps_config_params params; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Struct; + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageLength = reqhdr->PageLength; + hdr->PageNumber = reqhdr->PageNumber; + hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK; + params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + params.page_address = le32toh(page_req->page_address); + params.buffer = buf; + params.length = le32toh(page_req->len); + params.callback = NULL; + + if ((error = mps_read_config_page(sc, ¶ms)) != 0) { + mps_printf(sc, "mps_user_read_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + return (0); +} + +static int +mps_user_read_extcfg_header(struct mps_softc *sc, + struct mps_ext_cfg_page_req *ext_page_req) +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr; + struct mps_config_params params; + int error; + + hdr = ¶ms.hdr.Ext; + params.action = MPI2_CONFIG_ACTION_PAGE_HEADER; + hdr->PageVersion = ext_page_req->header.PageVersion; + hdr->ExtPageLength = 0; + hdr->PageNumber = ext_page_req->header.PageNumber; + hdr->ExtPageType = ext_page_req->header.ExtPageType; + params.page_address = le32toh(ext_page_req->page_address); + if ((error = mps_read_config_page(sc, ¶ms)) != 0) { + /* + * Leave the request. Without resetting the chip, it's + * still owned by it and we'll just get into trouble + * freeing it now. Mark it as abandoned so that if it + * shows up later it can be freed. + */ + mps_printf(sc, "mps_user_read_extcfg_header timed out\n"); + return (ETIMEDOUT); + } + + ext_page_req->ioc_status = htole16(params.status); + if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) == + MPI2_IOCSTATUS_SUCCESS) { + ext_page_req->header.PageVersion = hdr->PageVersion; + ext_page_req->header.PageNumber = hdr->PageNumber; + ext_page_req->header.PageType = hdr->PageType; + ext_page_req->header.ExtPageLength = hdr->ExtPageLength; + ext_page_req->header.ExtPageType = hdr->ExtPageType; + } + + return (0); +} + +static int +mps_user_read_extcfg_page(struct mps_softc *sc, + struct mps_ext_cfg_page_req *ext_page_req, void *buf) +{ + MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr; + struct mps_config_params params; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Ext; + params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + params.page_address = le32toh(ext_page_req->page_address); + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageNumber = reqhdr->PageNumber; + hdr->ExtPageType = reqhdr->ExtPageType; + hdr->ExtPageLength = reqhdr->ExtPageLength; + params.buffer = buf; + params.length = le32toh(ext_page_req->len); + params.callback = NULL; + + if ((error = mps_read_config_page(sc, ¶ms)) != 0) { + mps_printf(sc, "mps_user_read_extcfg_page timed out\n"); + return (ETIMEDOUT); + } + + ext_page_req->ioc_status = htole16(params.status); + return (0); +} + +static int +mps_user_write_cfg_page(struct mps_softc *sc, + struct mps_cfg_page_req *page_req, void *buf) +{ + MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr; + struct mps_config_params params; + u_int hdr_attr; + int error; + + reqhdr = buf; + hdr = ¶ms.hdr.Struct; + hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK; + if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE && + hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) { + mps_printf(sc, "page type 0x%x not changeable\n", + reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK); + return (EINVAL); + } + + /* + * There isn't any point in restoring stripped out attributes + * if you then mask them going down to issue the request. + */ + + hdr->PageVersion = reqhdr->PageVersion; + hdr->PageLength = reqhdr->PageLength; + hdr->PageNumber = reqhdr->PageNumber; + hdr->PageType = reqhdr->PageType; + params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + params.page_address = le32toh(page_req->page_address); + params.buffer = buf; + params.length = le32toh(page_req->len); + params.callback = NULL; + + if ((error = mps_write_config_page(sc, ¶ms)) != 0) { + mps_printf(sc, "mps_write_cfg_page timed out\n"); + return (ETIMEDOUT); + } + + page_req->ioc_status = htole16(params.status); + return (0); +} + +static void +mpi_init_sge(struct mps_command *cm, void *req, void *sge) +{ + int off, space; + + space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4; + off = (uintptr_t)sge - (uintptr_t)req; + + KASSERT(off < space, ("bad pointers %p %p, off %d, space %d", + req, sge, off, space)); + + cm->cm_sge = sge; + cm->cm_sglsize = space - off; +} + +/* + * Prepare the mps_command for an IOC_FACTS request. + */ +static int +mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req; + MPI2_IOC_FACTS_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * Prepare the mps_command for a PORT_FACTS request. + */ +static int +mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req; + MPI2_PORT_FACTS_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * Prepare the mps_command for a FW_DOWNLOAD request. + */ +static int +mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req; + MPI2_FW_DOWNLOAD_REPLY *rpl; + MPI2_FW_DOWNLOAD_TCSGE tc; + int error; + + /* + * This code assumes there is room in the request's SGL for + * the TransactionContext plus at least a SGL chain element. + */ + CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + if (cmd->len == 0) + return (EINVAL); + + error = copyin(cmd->buf, cm->cm_data, cmd->len); + if (error != 0) + return (error); + + mpi_init_sge(cm, req, &req->SGL); + bzero(&tc, sizeof tc); + + /* + * For now, the F/W image must be provided in a single request. + */ + if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0) + return (EINVAL); + if (req->TotalImageSize != cmd->len) + return (EINVAL); + + /* + * The value of the first two elements is specified in the + * Fusion-MPT Message Passing Interface document. + */ + tc.ContextSize = 0; + tc.DetailsLength = 12; + tc.ImageOffset = 0; + tc.ImageSize = cmd->len; + + cm->cm_flags |= MPS_CM_FLAGS_DATAOUT; + + return (mps_push_sge(cm, &tc, sizeof tc, 0)); +} + +/* + * Prepare the mps_command for a FW_UPLOAD request. + */ +static int +mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req; + MPI2_FW_UPLOAD_REPLY *rpl; + MPI2_FW_UPLOAD_TCSGE tc; + + /* + * This code assumes there is room in the request's SGL for + * the TransactionContext plus at least a SGL chain element. + */ + CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE); + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpi_init_sge(cm, req, &req->SGL); + if (cmd->len == 0) { + /* Perhaps just asking what the size of the fw is? */ + return (0); + } + + bzero(&tc, sizeof tc); + + /* + * The value of the first two elements is specified in the + * Fusion-MPT Message Passing Interface document. + */ + tc.ContextSize = 0; + tc.DetailsLength = 12; + /* + * XXX Is there any reason to fetch a partial image? I.e. to + * set ImageOffset to something other than 0? + */ + tc.ImageOffset = 0; + tc.ImageSize = cmd->len; + + return (mps_push_sge(cm, &tc, sizeof tc, 0)); +} + +/* + * Prepare the mps_command for a SATA_PASSTHROUGH request. + */ +static int +mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; + MPI2_SATA_PASSTHROUGH_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpi_init_sge(cm, req, &req->SGL); + return (0); +} + +/* + * Prepare the mps_command for a SMP_PASSTHROUGH request. + */ +static int +mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req; + MPI2_SMP_PASSTHROUGH_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpi_init_sge(cm, req, &req->SGL); + return (0); +} + +/* + * Prepare the mps_command for a CONFIG request. + */ +static int +mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req; + MPI2_CONFIG_REPLY *rpl; + + if (cmd->req_len != sizeof *req) + return (EINVAL); + if (cmd->rpl_len != sizeof *rpl) + return (EINVAL); + + mpi_init_sge(cm, req, &req->PageBufferSGE); + return (0); +} + +/* + * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request. + */ +static int +mpi_pre_sas_io_unit_control(struct mps_command *cm, + struct mps_usr_command *cmd) +{ + + cm->cm_sge = NULL; + cm->cm_sglsize = 0; + return (0); +} + +/* + * A set of functions to prepare an mps_command for the various + * supported requests. + */ +struct mps_user_func { + U8 Function; + mps_user_f *f_pre; +} mps_user_func_list[] = { + { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts }, + { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts }, + { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download }, + { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload }, + { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough }, + { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough}, + { MPI2_FUNCTION_CONFIG, mpi_pre_config}, + { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control }, + { 0xFF, NULL } /* list end */ +}; + +static int +mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd) +{ + MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; + struct mps_user_func *f; + + for (f = mps_user_func_list; f->f_pre != NULL; f++) { + if (hdr->Function == f->Function) + return (f->f_pre(cm, cmd)); + } + return (EINVAL); +} + +static int +mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd) +{ + MPI2_REQUEST_HEADER *hdr; + MPI2_DEFAULT_REPLY *rpl; + void *buf = NULL; + struct mps_command *cm = NULL; + int err = 0; + int sz; + + mps_lock(sc); + cm = mps_alloc_command(sc); + + if (cm == NULL) { + mps_printf(sc, "mps_user_command: no mps requests\n"); + err = ENOMEM; + goto Ret; + } + mps_unlock(sc); + + hdr = (MPI2_REQUEST_HEADER *)cm->cm_req; + + mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d rpl %p %d\n", + cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len ); + + if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) { + err = EINVAL; + goto RetFreeUnlocked; + } + err = copyin(cmd->req, hdr, cmd->req_len); + if (err != 0) + goto RetFreeUnlocked; + + mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X " + "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags ); + + err = mps_user_setup_request(cm, cmd); + if (err != 0) { + mps_printf(sc, "mps_user_command: unsupported function 0x%X\n", + hdr->Function ); + goto RetFreeUnlocked; + } + + if (cmd->len > 0) { + buf = malloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO); + cm->cm_data = buf; + cm->cm_length = cmd->len; + } else { + cm->cm_data = NULL; + cm->cm_length = 0; + } + + cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP; + cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + + mps_lock(sc); + err = mps_map_command(sc, cm); + + if (err != 0 && err != EINPROGRESS) { + mps_printf(sc, "%s: invalid request: error %d\n", + __func__, err); + goto Ret; + } + msleep(cm, &sc->mps_mtx, 0, "mpsuser", 0); + + rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply; + sz = rpl->MsgLength * 4; + + if (sz > cmd->rpl_len) { + mps_printf(sc, + "mps_user_command: reply buffer too small %d required %d\n", + cmd->rpl_len, sz ); + err = EINVAL; + sz = cmd->rpl_len; + } + + mps_unlock(sc); + copyout(rpl, cmd->rpl, sz); + if (buf != NULL) + copyout(buf, cmd->buf, cmd->len); + mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz ); + +RetFreeUnlocked: + mps_lock(sc); + if (cm != NULL) + mps_free_command(sc, cm); +Ret: + mps_unlock(sc); + if (buf != NULL) + free(buf, M_MPSUSER); + return (err); +} + +static int +mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag, + struct thread *td) +{ + struct mps_softc *sc; + struct mps_cfg_page_req *page_req; + struct mps_ext_cfg_page_req *ext_page_req; + void *mps_page; + int error; + + mps_page = NULL; + sc = dev->si_drv1; + page_req = (void *)arg; + ext_page_req = (void *)arg; + + switch (cmd) { + case MPSIO_READ_CFG_HEADER: + mps_lock(sc); + error = mps_user_read_cfg_header(sc, page_req); + mps_unlock(sc); + break; + case MPSIO_READ_CFG_PAGE: + mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO); + error = copyin(page_req->buf, mps_page, + sizeof(MPI2_CONFIG_PAGE_HEADER)); + if (error) + break; + mps_lock(sc); + error = mps_user_read_cfg_page(sc, page_req, mps_page); + mps_unlock(sc); + if (error) + break; + error = copyout(mps_page, page_req->buf, page_req->len); + break; + case MPSIO_READ_EXT_CFG_HEADER: + mps_lock(sc); + error = mps_user_read_extcfg_header(sc, ext_page_req); + mps_unlock(sc); + break; + case MPSIO_READ_EXT_CFG_PAGE: + mps_page = malloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); + error = copyin(ext_page_req->buf, mps_page, + sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); + if (error) + break; + mps_lock(sc); + error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page); + mps_unlock(sc); + if (error) + break; + error = copyout(mps_page, ext_page_req->buf, ext_page_req->len); + break; + case MPSIO_WRITE_CFG_PAGE: + mps_page = malloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO); + error = copyin(page_req->buf, mps_page, page_req->len); + if (error) + break; + mps_lock(sc); + error = mps_user_write_cfg_page(sc, page_req, mps_page); + mps_unlock(sc); + break; + case MPSIO_MPS_COMMAND: + error = mps_user_command(sc, (struct mps_usr_command *)arg); + break; + default: + error = ENOIOCTL; + break; + } + + if (mps_page != NULL) + free(mps_page, M_MPSUSER); + + return (error); +} + +#ifdef COMPAT_FREEBSD32 + +/* Macros from compat/freebsd32/freebsd32.h */ +#define PTRIN(v) (void *)(uintptr_t)(v) +#define PTROUT(v) (uint32_t)(uintptr_t)(v) + +#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0) +#define PTRIN_CP(src,dst,fld) \ + do { (dst).fld = PTRIN((src).fld); } while (0) +#define PTROUT_CP(src,dst,fld) \ + do { (dst).fld = PTROUT((src).fld); } while (0) + +struct mps_cfg_page_req32 { + MPI2_CONFIG_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mps_ext_cfg_page_req32 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER header; + uint32_t page_address; + uint32_t buf; + int len; + uint16_t ioc_status; +}; + +struct mps_raid_action32 { + uint8_t action; + uint8_t volume_bus; + uint8_t volume_id; + uint8_t phys_disk_num; + uint32_t action_data_word; + uint32_t buf; + int len; + uint32_t volume_status; + uint32_t action_data[4]; + uint16_t action_status; + uint16_t ioc_status; + uint8_t write; +}; + +struct mps_usr_command32 { + uint32_t req; + uint32_t req_len; + uint32_t rpl; + uint32_t rpl_len; + uint32_t buf; + int len; + uint32_t flags; +}; + +#define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32) +#define MPSIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mps_cfg_page_req32) +#define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32) +#define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32) +#define MPSIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mps_cfg_page_req32) +#define MPSIO_RAID_ACTION32 _IOWR('M', 205, struct mps_raid_action32) +#define MPSIO_MPS_COMMAND32 _IOWR('M', 210, struct mps_usr_command32) + +static int +mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag, + struct thread *td) +{ + struct mps_cfg_page_req32 *page32 = _arg; + struct mps_ext_cfg_page_req32 *ext32 = _arg; + struct mps_raid_action32 *raid32 = _arg; + struct mps_usr_command32 *user32 = _arg; + union { + struct mps_cfg_page_req page; + struct mps_ext_cfg_page_req ext; + struct mps_raid_action raid; + struct mps_usr_command user; + } arg; + u_long cmd; + int error; + + switch (cmd32) { + case MPSIO_READ_CFG_HEADER32: + case MPSIO_READ_CFG_PAGE32: + case MPSIO_WRITE_CFG_PAGE32: + if (cmd32 == MPSIO_READ_CFG_HEADER32) + cmd = MPSIO_READ_CFG_HEADER; + else if (cmd32 == MPSIO_READ_CFG_PAGE32) + cmd = MPSIO_READ_CFG_PAGE; + else + cmd = MPSIO_WRITE_CFG_PAGE; + CP(*page32, arg.page, header); + CP(*page32, arg.page, page_address); + PTRIN_CP(*page32, arg.page, buf); + CP(*page32, arg.page, len); + CP(*page32, arg.page, ioc_status); + break; + + case MPSIO_READ_EXT_CFG_HEADER32: + case MPSIO_READ_EXT_CFG_PAGE32: + if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32) + cmd = MPSIO_READ_EXT_CFG_HEADER; + else + cmd = MPSIO_READ_EXT_CFG_PAGE; + CP(*ext32, arg.ext, header); + CP(*ext32, arg.ext, page_address); + PTRIN_CP(*ext32, arg.ext, buf); + CP(*ext32, arg.ext, len); + CP(*ext32, arg.ext, ioc_status); + break; + + case MPSIO_RAID_ACTION32: + cmd = MPSIO_RAID_ACTION; + CP(*raid32, arg.raid, action); + CP(*raid32, arg.raid, volume_bus); + CP(*raid32, arg.raid, volume_id); + CP(*raid32, arg.raid, phys_disk_num); + CP(*raid32, arg.raid, action_data_word); + PTRIN_CP(*raid32, arg.raid, buf); + CP(*raid32, arg.raid, len); + CP(*raid32, arg.raid, volume_status); + bcopy(raid32->action_data, arg.raid.action_data, + sizeof arg.raid.action_data); + CP(*raid32, arg.raid, ioc_status); + CP(*raid32, arg.raid, write); + break; + + case MPSIO_MPS_COMMAND32: + cmd = MPSIO_MPS_COMMAND; + PTRIN_CP(*user32, arg.user, req); + CP(*user32, arg.user, req_len); + PTRIN_CP(*user32, arg.user, rpl); + CP(*user32, arg.user, rpl_len); + PTRIN_CP(*user32, arg.user, buf); + CP(*user32, arg.user, len); + CP(*user32, arg.user, flags); + break; + default: + return (ENOIOCTL); + } + + error = mps_ioctl(dev, cmd, &arg, flag, td); + if (error == 0 && (cmd32 & IOC_OUT) != 0) { + switch (cmd32) { + case MPSIO_READ_CFG_HEADER32: + case MPSIO_READ_CFG_PAGE32: + case MPSIO_WRITE_CFG_PAGE32: + CP(arg.page, *page32, header); + CP(arg.page, *page32, page_address); + PTROUT_CP(arg.page, *page32, buf); + CP(arg.page, *page32, len); + CP(arg.page, *page32, ioc_status); + break; + + case MPSIO_READ_EXT_CFG_HEADER32: + case MPSIO_READ_EXT_CFG_PAGE32: + CP(arg.ext, *ext32, header); + CP(arg.ext, *ext32, page_address); + PTROUT_CP(arg.ext, *ext32, buf); + CP(arg.ext, *ext32, len); + CP(arg.ext, *ext32, ioc_status); + break; + + case MPSIO_RAID_ACTION32: + CP(arg.raid, *raid32, action); + CP(arg.raid, *raid32, volume_bus); + CP(arg.raid, *raid32, volume_id); + CP(arg.raid, *raid32, phys_disk_num); + CP(arg.raid, *raid32, action_data_word); + PTROUT_CP(arg.raid, *raid32, buf); + CP(arg.raid, *raid32, len); + CP(arg.raid, *raid32, volume_status); + bcopy(arg.raid.action_data, raid32->action_data, + sizeof arg.raid.action_data); + CP(arg.raid, *raid32, ioc_status); + CP(arg.raid, *raid32, write); + break; + + case MPSIO_MPS_COMMAND32: + PTROUT_CP(arg.user, *user32, req); + CP(arg.user, *user32, req_len); + PTROUT_CP(arg.user, *user32, rpl); + CP(arg.user, *user32, rpl_len); + PTROUT_CP(arg.user, *user32, buf); + CP(arg.user, *user32, len); + CP(arg.user, *user32, flags); + break; + } + } + + return (error); +} +#endif /* COMPAT_FREEBSD32 */ + +static int +mps_ioctl_devsw(struct cdev *dev, u_long com, caddr_t arg, int flag, + struct thread *td) +{ +#ifdef COMPAT_FREEBSD32 + if (SV_CURPROC_FLAG(SV_ILP32)) + return (mps_ioctl32(dev, com, arg, flag, td)); +#endif + return (mps_ioctl(dev, com, arg, flag, td)); +} diff --git a/sys/dev/mps/mpsvar.h b/sys/dev/mps/mpsvar.h new file mode 100644 index 00000000000..db910307d5f --- /dev/null +++ b/sys/dev/mps/mpsvar.h @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 2009 Yahoo! Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MPSVAR_H +#define _MPSVAR_H + +#define MPS_DB_MAX_WAIT 2500 + +#define MPS_REQ_FRAMES 1024 +#define MPS_EVT_REPLY_FRAMES 32 +#define MPS_REPLY_FRAMES MPS_REQ_FRAMES +#define MPS_CHAIN_FRAMES 1024 +#define MPS_SENSE_LEN SSD_FULL_SIZE +#define MPS_MSI_COUNT 1 +#define MPS_SGE64_SIZE 12 +#define MPS_SGE32_SIZE 8 +#define MPS_SGC_SIZE 8 + +#define MPS_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */ + +struct mps_softc; +struct mps_command; +struct mpssas_softc; +struct mpssas_target; + +MALLOC_DECLARE(M_MPT2); + +typedef void mps_evt_callback_t(struct mps_softc *, uintptr_t, + MPI2_EVENT_NOTIFICATION_REPLY *reply); +typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm); + +struct mps_chain { + TAILQ_ENTRY(mps_chain) chain_link; + MPI2_SGE_IO_UNION *chain; + uint32_t chain_busaddr; +}; + +struct mps_command { + TAILQ_ENTRY(mps_command) cm_link; + struct mps_softc *cm_sc; + void *cm_data; + u_int cm_length; + u_int cm_sglsize; + MPI2_SGE_IO_UNION *cm_sge; + uint8_t *cm_req; + uint8_t *cm_reply; + uint32_t cm_reply_data; + mps_command_callback_t *cm_complete; + void *cm_complete_data; + struct mpssas_target *cm_targ; + MPI2_REQUEST_DESCRIPTOR_UNION cm_desc; + u_int cm_flags; +#define MPS_CM_FLAGS_POLLED (1 << 0) +#define MPS_CM_FLAGS_COMPLETE (1 << 1) +#define MPS_CM_FLAGS_SGE_SIMPLE (1 << 2) +#define MPS_CM_FLAGS_DATAOUT (1 << 3) +#define MPS_CM_FLAGS_DATAIN (1 << 4) +#define MPS_CM_FLAGS_WAKEUP (1 << 5) +#define MPS_CM_FLAGS_ACTIVE (1 << 6) + u_int cm_state; +#define MPS_CM_STATE_FREE 0 +#define MPS_CM_STATE_BUSY 1 +#define MPS_CM_STATE_TIMEDOUT 2 + bus_dmamap_t cm_dmamap; + struct scsi_sense_data *cm_sense; + TAILQ_HEAD(, mps_chain) cm_chain_list; + uint32_t cm_req_busaddr; + uint32_t cm_sense_busaddr; + struct callout cm_callout; +}; + +struct mps_event_handle { + TAILQ_ENTRY(mps_event_handle) eh_list; + mps_evt_callback_t *callback; + void *data; + uint8_t mask[16]; +}; + +struct mps_softc { + device_t mps_dev; + struct cdev *mps_cdev; + u_int mps_flags; +#define MPS_FLAGS_INTX (1 << 0) +#define MPS_FLAGS_MSI (1 << 1) +#define MPS_FLAGS_BUSY (1 << 2) +#define MPS_FLAGS_SHUTDOWN (1 << 3) + u_int mps_debug; + u_int allow_multiple_tm_cmds; + int tm_cmds_active; + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + struct mps_command *commands; + struct mps_chain *chains; + struct callout periodic; + + struct mpssas_softc *sassc; + + TAILQ_HEAD(, mps_command) req_list; + TAILQ_HEAD(, mps_chain) chain_list; + TAILQ_HEAD(, mps_command) tm_list; + int replypostindex; + int replyfreeindex; + int replycurindex; + + struct resource *mps_regs_resource; + bus_space_handle_t mps_bhandle; + bus_space_tag_t mps_btag; + int mps_regs_rid; + + bus_dma_tag_t mps_parent_dmat; + bus_dma_tag_t buffer_dmat; + + MPI2_IOC_FACTS_REPLY *facts; + MPI2_PORT_FACTS_REPLY *pfacts; + int num_reqs; + int num_replies; + int fqdepth; /* Free queue */ + int pqdepth; /* Post queue */ + + uint8_t event_mask[16]; + TAILQ_HEAD(, mps_event_handle) event_list; + struct mps_event_handle *mps_log_eh; + + struct mtx mps_mtx; + struct intr_config_hook mps_ich; + struct resource *mps_irq[MPS_MSI_COUNT]; + void *mps_intrhand[MPS_MSI_COUNT]; + int mps_irq_rid[MPS_MSI_COUNT]; + + uint8_t *req_frames; + bus_addr_t req_busaddr; + bus_dma_tag_t req_dmat; + bus_dmamap_t req_map; + + uint8_t *reply_frames; + bus_addr_t reply_busaddr; + bus_dma_tag_t reply_dmat; + bus_dmamap_t reply_map; + + struct scsi_sense_data *sense_frames; + bus_addr_t sense_busaddr; + bus_dma_tag_t sense_dmat; + bus_dmamap_t sense_map; + + uint8_t *chain_frames; + bus_addr_t chain_busaddr; + bus_dma_tag_t chain_dmat; + bus_dmamap_t chain_map; + + MPI2_REPLY_DESCRIPTORS_UNION *post_queue; + bus_addr_t post_busaddr; + uint32_t *free_queue; + bus_addr_t free_busaddr; + bus_dma_tag_t queues_dmat; + bus_dmamap_t queues_map; +}; + +struct mps_config_params { + MPI2_CONFIG_EXT_PAGE_HEADER_UNION hdr; + u_int action; + u_int page_address; /* Attributes, not a phys address */ + u_int status; + void *buffer; + u_int length; + int timeout; + void (*callback)(struct mps_softc *, struct mps_config_params *); + void *cbdata; +}; + +static __inline uint32_t +mps_regread(struct mps_softc *sc, uint32_t offset) +{ + return (bus_space_read_4(sc->mps_btag, sc->mps_bhandle, offset)); +} + +static __inline void +mps_regwrite(struct mps_softc *sc, uint32_t offset, uint32_t val) +{ + bus_space_write_4(sc->mps_btag, sc->mps_bhandle, offset, val); +} + +static __inline void +mps_free_reply(struct mps_softc *sc, uint32_t busaddr) +{ + + if (++sc->replyfreeindex >= sc->fqdepth) + sc->replyfreeindex = 0; + sc->free_queue[sc->replyfreeindex] = busaddr; + mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex); +} + +static __inline struct mps_chain * +mps_alloc_chain(struct mps_softc *sc) +{ + struct mps_chain *chain; + + if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL) + TAILQ_REMOVE(&sc->chain_list, chain, chain_link); + return (chain); +} + +static __inline void +mps_free_chain(struct mps_softc *sc, struct mps_chain *chain) +{ +#if 0 + bzero(chain->chain, 128); +#endif + TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link); +} + +static __inline void +mps_free_command(struct mps_softc *sc, struct mps_command *cm) +{ + struct mps_chain *chain, *chain_temp; + + if (cm->cm_reply != NULL) + mps_free_reply(sc, cm->cm_reply_data); + cm->cm_flags = 0; + cm->cm_complete = NULL; + cm->cm_complete_data = NULL; + cm->cm_targ = 0; + cm->cm_state = MPS_CM_STATE_FREE; + TAILQ_FOREACH_SAFE(chain, &cm->cm_chain_list, chain_link, chain_temp) { + TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link); + mps_free_chain(sc, chain); + } + TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link); +} + +static __inline struct mps_command * +mps_alloc_command(struct mps_softc *sc) +{ + struct mps_command *cm; + + cm = TAILQ_FIRST(&sc->req_list); + if (cm == NULL) + return (NULL); + + TAILQ_REMOVE(&sc->req_list, cm, cm_link); + KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n")); + cm->cm_state = MPS_CM_STATE_BUSY; + return (cm); +} + +static __inline void +mps_lock(struct mps_softc *sc) +{ + mtx_lock(&sc->mps_mtx); +} + +static __inline void +mps_unlock(struct mps_softc *sc) +{ + mtx_unlock(&sc->mps_mtx); +} + +#define MPS_INFO (1 << 0) +#define MPS_TRACE (1 << 1) +#define MPS_FAULT (1 << 2) +#define MPS_EVENT (1 << 3) +#define MPS_LOG (1 << 4) + +#define mps_printf(sc, args...) \ + device_printf((sc)->mps_dev, ##args) + +#define mps_dprint(sc, level, msg, args...) \ +do { \ + if (sc->mps_debug & level) \ + device_printf(sc->mps_dev, msg, ##args); \ +} while (0) + +#define mps_dprint_field(sc, level, msg, args...) \ +do { \ + if (sc->mps_debug & level) \ + printf("\t" msg, ##args); \ +} while (0) + +#define MPS_PRINTFIELD_START(sc, tag...) \ + mps_dprint((sc), MPS_INFO, ##tag); \ + mps_dprint_field((sc), MPS_INFO, ":\n") +#define MPS_PRINTFIELD_END(sc, tag) \ + mps_dprint((sc), MPS_INFO, tag "\n") +#define MPS_PRINTFIELD(sc, facts, attr, fmt) \ + mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr) + +#define MPS_EVENTFIELD_START(sc, tag...) \ + mps_dprint((sc), MPS_EVENT, ##tag); \ + mps_dprint_field((sc), MPS_EVENT, ":\n") +#define MPS_EVENTFIELD(sc, facts, attr, fmt) \ + mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr) + +static __inline void +mps_from_u64(uint64_t data, U64 *mps) +{ + (mps)->High = (uint32_t)((data) >> 32); + (mps)->Low = (uint32_t)((data) & 0xffffffff); +} + +static __inline uint64_t +mps_to_u64(U64 *data) +{ + + return (((uint64_t)data->High << 32) | data->Low); +} + +static __inline void +mps_mask_intr(struct mps_softc *sc) +{ + uint32_t mask; + + mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET); + mask |= MPI2_HIM_REPLY_INT_MASK; + mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); +} + +static __inline void +mps_unmask_intr(struct mps_softc *sc) +{ + uint32_t mask; + + mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET); + mask &= ~MPI2_HIM_REPLY_INT_MASK; + mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask); +} + +int mps_pci_setup_interrupts(struct mps_softc *); +int mps_attach(struct mps_softc *sc); +int mps_free(struct mps_softc *sc); +void mps_intr(void *); +void mps_intr_msi(void *); +void mps_intr_locked(void *); +int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *, + void *, struct mps_event_handle **); +int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *); +int mps_deregister_events(struct mps_softc *, struct mps_event_handle *); +int mps_request_polled(struct mps_softc *sc, struct mps_command *cm); +void mps_enqueue_request(struct mps_softc *, struct mps_command *); +int mps_push_sge(struct mps_command *, void *, size_t, int); +int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int); +int mps_attach_sas(struct mps_softc *sc); +int mps_detach_sas(struct mps_softc *sc); +int mps_map_command(struct mps_softc *sc, struct mps_command *cm); +int mps_read_config_page(struct mps_softc *, struct mps_config_params *); +int mps_write_config_page(struct mps_softc *, struct mps_config_params *); +void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int ); +int mps_attach_user(struct mps_softc *); +void mps_detach_user(struct mps_softc *); + +SYSCTL_DECL(_hw_mps); + +#endif + diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index 75fa564cd41..1ca4ef92cd0 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -844,13 +844,14 @@ mpt_complete_request_chain(struct mpt_softc *mpt, struct req_queue *chain, MSG_REQUEST_HEADER *msg_hdr; u_int cb_index; - TAILQ_REMOVE(chain, req, links); msg_hdr = (MSG_REQUEST_HEADER *)req->req_vbuf; ioc_status_frame.Function = msg_hdr->Function; ioc_status_frame.MsgContext = msg_hdr->MsgContext; cb_index = MPT_CONTEXT_TO_CBI(le32toh(msg_hdr->MsgContext)); mpt_reply_handlers[cb_index](mpt, req, msg_hdr->MsgContext, &ioc_status_frame); + if (mpt_req_on_pending_list(mpt, req) != 0) + TAILQ_REMOVE(chain, req, links); } } diff --git a/sys/dev/mpt/mpt.h b/sys/dev/mpt/mpt.h index 9026142b9a1..f095bbf7354 100644 --- a/sys/dev/mpt/mpt.h +++ b/sys/dev/mpt/mpt.h @@ -1157,19 +1157,13 @@ mpt_tag_2_req(struct mpt_softc *mpt, uint32_t tag) KASSERT(mpt->tgt_cmd_ptrs[rtg], ("no cmd backpointer")); return (mpt->tgt_cmd_ptrs[rtg]); } - +#endif static __inline int mpt_req_on_free_list(struct mpt_softc *, request_t *); static __inline int mpt_req_on_pending_list(struct mpt_softc *, request_t *); -static __inline void -mpt_req_spcl(struct mpt_softc *, request_t *, const char *, int); -static __inline void -mpt_req_not_spcl(struct mpt_softc *, request_t *, const char *, int); - - /* * Is request on freelist? */ @@ -1202,6 +1196,12 @@ mpt_req_on_pending_list(struct mpt_softc *mpt, request_t *req) return (0); } +#ifdef INVARIANTS +static __inline void +mpt_req_spcl(struct mpt_softc *, request_t *, const char *, int); +static __inline void +mpt_req_not_spcl(struct mpt_softc *, request_t *, const char *, int); + /* * Make sure that req *is* part of one of the special lists */ diff --git a/sys/dev/msk/if_msk.c b/sys/dev/msk/if_msk.c index 3f97c3a9f5c..4c144fdf127 100644 --- a/sys/dev/msk/if_msk.c +++ b/sys/dev/msk/if_msk.c @@ -401,9 +401,6 @@ msk_miibus_readreg(device_t dev, int phy, int reg) { struct msk_if_softc *sc_if; - if (phy != PHY_ADDR_MARV) - return (0); - sc_if = device_get_softc(dev); return (msk_phy_readreg(sc_if, phy, reg)); @@ -442,9 +439,6 @@ msk_miibus_writereg(device_t dev, int phy, int reg, int val) { struct msk_if_softc *sc_if; - if (phy != PHY_ADDR_MARV) - return (0); - sc_if = device_get_softc(dev); return (msk_phy_writereg(sc_if, phy, reg, val)); @@ -1334,7 +1328,7 @@ mskc_reset(struct msk_softc *sc) pci_write_config(sc->msk_dev, PCIR_STATUS, status | PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT | - PCIM_STATUS_RTABORT | PCIM_STATUS_PERRREPORT, 2); + PCIM_STATUS_RTABORT | PCIM_STATUS_MDPERR, 2); CSR_WRITE_2(sc, B0_CTST, CS_MRST_CLR); switch (sc->msk_bustype) { @@ -1647,10 +1641,11 @@ msk_attach(device_t dev) * Do miibus setup. */ MSK_IF_UNLOCK(sc_if); - error = mii_phy_probe(dev, &sc_if->msk_miibus, msk_mediachange, - msk_mediastatus); + error = mii_attach(dev, &sc_if->msk_miibus, ifp, msk_mediachange, + msk_mediastatus, BMSR_DEFCAPMASK, PHY_ADDR_MARV, MII_OFFSET_ANY, + mmd->mii_flags); if (error != 0) { - device_printf(sc_if->msk_if_dev, "no PHY found!\n"); + device_printf(sc_if->msk_if_dev, "attaching PHYs failed\n"); ether_ifdetach(ifp); error = ENXIO; goto fail; @@ -1891,8 +1886,10 @@ mskc_attach(device_t dev) } mmd->port = MSK_PORT_A; mmd->pmd = sc->msk_pmd; - if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S' || sc->msk_pmd == 'P') + if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S') mmd->mii_flags |= MIIF_HAVEFIBER; + if (sc->msk_pmd == 'P') + mmd->mii_flags |= MIIF_HAVEFIBER | MIIF_MACPRIV0; device_set_ivars(sc->msk_devs[MSK_PORT_A], mmd); if (sc->msk_num_port > 1) { @@ -1911,8 +1908,10 @@ mskc_attach(device_t dev) } mmd->port = MSK_PORT_B; mmd->pmd = sc->msk_pmd; - if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S' || sc->msk_pmd == 'P') + if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S') mmd->mii_flags |= MIIF_HAVEFIBER; + if (sc->msk_pmd == 'P') + mmd->mii_flags |= MIIF_HAVEFIBER | MIIF_MACPRIV0; device_set_ivars(sc->msk_devs[MSK_PORT_B], mmd); } @@ -3405,7 +3404,7 @@ msk_intr_hwerr(struct msk_softc *sc) CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON); pci_write_config(sc->msk_dev, PCIR_STATUS, v16 | PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT | - PCIM_STATUS_RTABORT | PCIM_STATUS_PERRREPORT, 2); + PCIM_STATUS_RTABORT | PCIM_STATUS_MDPERR, 2); CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } diff --git a/sys/dev/mvs/mvs.c b/sys/dev/mvs/mvs.c index 6b08222de6a..99689380d86 100644 --- a/sys/dev/mvs/mvs.c +++ b/sys/dev/mvs/mvs.c @@ -57,7 +57,8 @@ static int mvs_ch_deinit(device_t dev); static int mvs_ch_suspend(device_t dev); static int mvs_ch_resume(device_t dev); static void mvs_dmainit(device_t dev); -static void mvs_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); +static void mvs_dmasetupc_cb(void *xsc, + bus_dma_segment_t *segs, int nsegs, int error); static void mvs_dmafini(device_t dev); static void mvs_slotsalloc(device_t dev); static void mvs_slotsfree(device_t dev); @@ -79,7 +80,8 @@ static void mvs_crbq_intr(device_t dev); static void mvs_begin_transaction(device_t dev, union ccb *ccb); static void mvs_legacy_execute_transaction(struct mvs_slot *slot); static void mvs_timeout(struct mvs_slot *slot); -static void mvs_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error); +static void mvs_dmasetprd(void *arg, + bus_dma_segment_t *segs, int nsegs, int error); static void mvs_requeue_frozen(device_t dev); static void mvs_execute_transaction(struct mvs_slot *slot); static void mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et); @@ -314,9 +316,11 @@ mvs_dmainit(device_t dev) if (bus_dmamem_alloc(ch->dma.workrq_tag, (void **)&ch->dma.workrq, 0, &ch->dma.workrq_map)) goto error; - if (bus_dmamap_load(ch->dma.workrq_tag, ch->dma.workrq_map, ch->dma.workrq, - MVS_WORKRQ_SIZE, mvs_dmasetupc_cb, &dcba, 0) || dcba.error) { - bus_dmamem_free(ch->dma.workrq_tag, ch->dma.workrq, ch->dma.workrq_map); + if (bus_dmamap_load(ch->dma.workrq_tag, ch->dma.workrq_map, + ch->dma.workrq, MVS_WORKRQ_SIZE, mvs_dmasetupc_cb, &dcba, 0) || + dcba.error) { + bus_dmamem_free(ch->dma.workrq_tag, + ch->dma.workrq, ch->dma.workrq_map); goto error; } ch->dma.workrq_bus = dcba.maddr; @@ -329,9 +333,11 @@ mvs_dmainit(device_t dev) if (bus_dmamem_alloc(ch->dma.workrp_tag, (void **)&ch->dma.workrp, 0, &ch->dma.workrp_map)) goto error; - if (bus_dmamap_load(ch->dma.workrp_tag, ch->dma.workrp_map, ch->dma.workrp, - MVS_WORKRP_SIZE, mvs_dmasetupc_cb, &dcba, 0) || dcba.error) { - bus_dmamem_free(ch->dma.workrp_tag, ch->dma.workrp, ch->dma.workrp_map); + if (bus_dmamap_load(ch->dma.workrp_tag, ch->dma.workrp_map, + ch->dma.workrp, MVS_WORKRP_SIZE, mvs_dmasetupc_cb, &dcba, 0) || + dcba.error) { + bus_dmamem_free(ch->dma.workrp_tag, + ch->dma.workrp, ch->dma.workrp_map); goto error; } ch->dma.workrp_bus = dcba.maddr; @@ -371,7 +377,8 @@ mvs_dmafini(device_t dev) } if (ch->dma.workrp_bus) { bus_dmamap_unload(ch->dma.workrp_tag, ch->dma.workrp_map); - bus_dmamem_free(ch->dma.workrp_tag, ch->dma.workrp, ch->dma.workrp_map); + bus_dmamem_free(ch->dma.workrp_tag, + ch->dma.workrp, ch->dma.workrp_map); ch->dma.workrp_bus = 0; ch->dma.workrp_map = NULL; ch->dma.workrp = NULL; @@ -382,7 +389,8 @@ mvs_dmafini(device_t dev) } if (ch->dma.workrq_bus) { bus_dmamap_unload(ch->dma.workrq_tag, ch->dma.workrq_map); - bus_dmamem_free(ch->dma.workrq_tag, ch->dma.workrq, ch->dma.workrq_map); + bus_dmamem_free(ch->dma.workrq_tag, + ch->dma.workrq, ch->dma.workrq_map); ch->dma.workrq_bus = 0; ch->dma.workrq_map = NULL; ch->dma.workrq = NULL; @@ -444,14 +452,16 @@ mvs_setup_edma_queues(device_t dev) ATA_OUTL(ch->r_mem, EDMA_REQQBAH, work >> 32); ATA_OUTL(ch->r_mem, EDMA_REQQIP, work & 0xffffffff); ATA_OUTL(ch->r_mem, EDMA_REQQOP, work & 0xffffffff); - bus_dmamap_sync(ch->dma.workrq_tag, ch->dma.workrq_map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(ch->dma.workrq_tag, ch->dma.workrq_map, + BUS_DMASYNC_PREWRITE); /* Reponses queue. */ - bzero(ch->dma.workrp, 256); + memset(ch->dma.workrp, 0xff, MVS_WORKRP_SIZE); work = ch->dma.workrp_bus; ATA_OUTL(ch->r_mem, EDMA_RESQBAH, work >> 32); ATA_OUTL(ch->r_mem, EDMA_RESQIP, work & 0xffffffff); ATA_OUTL(ch->r_mem, EDMA_RESQOP, work & 0xffffffff); - bus_dmamap_sync(ch->dma.workrp_tag, ch->dma.workrp_map, BUS_DMASYNC_PREREAD); + bus_dmamap_sync(ch->dma.workrp_tag, ch->dma.workrp_map, + BUS_DMASYNC_PREREAD); ch->out_idx = 0; ch->in_idx = 0; } @@ -678,20 +688,15 @@ mvs_ch_intr(void *data) int i, ccs, port = -1, selfdis = 0; int edma = (ch->numtslots != 0 || ch->numdslots != 0); -//device_printf(dev, "irq cause %02x EDMA %d IEC %08x\n", -// arg->cause, edma, ATA_INL(ch->r_mem, EDMA_IEC)); /* New item in response queue. */ if ((arg->cause & 2) && edma) mvs_crbq_intr(dev); /* Some error or special event. */ if (arg->cause & 1) { iec = ATA_INL(ch->r_mem, EDMA_IEC); -//device_printf(dev, "irq cause %02x EDMA %d IEC %08x\n", -// arg->cause, edma, iec); if (iec & EDMA_IE_SERRINT) { serr = ATA_INL(ch->r_mem, SATA_SE); ATA_OUTL(ch->r_mem, SATA_SE, serr); -//device_printf(dev, "SERR %08x\n", serr); } /* EDMA self-disabled due to error. */ if (iec & EDMA_IE_ESELFDIS) @@ -706,7 +711,6 @@ mvs_ch_intr(void *data) fisic = SATA_FISC_FISWAIT4HOSTRDYEN_B1; else /* For Gen-IIe - read FIS interrupt cause. */ fisic = ATA_INL(ch->r_mem, SATA_FISIC); -//device_printf(dev, "FISIC %08x\n", fisic); } if (selfdis) ch->curr_mode = MVS_EDMA_UNKNOWN; @@ -745,7 +749,6 @@ mvs_ch_intr(void *data) } } } -//device_printf(dev, "err slot %d port %d\n", ccs, port); mvs_requeue_frozen(dev); for (i = 0; i < MVS_MAX_SLOTS; i++) { /* XXX: reqests in loading state. */ @@ -771,7 +774,8 @@ mvs_ch_intr(void *data) ch->fatalerr = 1; } } else if (iec & 0xfc1e9000) { - if (ch->numtslots == 0 && i != ccs && port != -2) + if (ch->numtslots == 0 && + i != ccs && port != -2) et = MVS_ERR_INNOCENT; else et = MVS_ERR_SATA; @@ -823,8 +827,6 @@ mvs_legacy_intr(device_t dev) /* Clear interrupt and get status. */ status = mvs_getstatus(dev, 1); -// device_printf(dev, "Legacy intr status %02x\n", -// status); if (slot->state < MVS_SLOT_RUNNING) return; port = ccb->ccb_h.target_id & 0x0f; @@ -867,7 +869,8 @@ mvs_legacy_intr(device_t dev) /* If data write command - put them */ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { if (mvs_wait(dev, ATA_S_DRQ, ATA_S_BUSY, 1000) < 0) { - device_printf(dev, "timeout waiting for write DRQ\n"); + device_printf(dev, + "timeout waiting for write DRQ\n"); et = MVS_ERR_TIMEOUT; goto end_finished; } @@ -890,19 +893,18 @@ mvs_legacy_intr(device_t dev) ATA_OUTL(ch->r_mem, DMA_C, 0); goto end_finished; } else { /* ATAPI PIO */ - length = ATA_INB(ch->r_mem,ATA_CYL_LSB) | (ATA_INB(ch->r_mem,ATA_CYL_MSB) << 8); + length = ATA_INB(ch->r_mem,ATA_CYL_LSB) | + (ATA_INB(ch->r_mem,ATA_CYL_MSB) << 8); ireason = ATA_INB(ch->r_mem,ATA_IREASON); -//device_printf(dev, "status %02x, ireason %02x, length %d\n", status, ireason, length); switch ((ireason & (ATA_I_CMD | ATA_I_IN)) | (status & ATA_S_DRQ)) { case ATAPI_P_CMDOUT: -device_printf(dev, "ATAPI CMDOUT\n"); + device_printf(dev, "ATAPI CMDOUT\n"); /* Return wait for interrupt */ return; case ATAPI_P_WRITE: -//device_printf(dev, "ATAPI WRITE\n"); if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { device_printf(dev, "trying to write on read buffer\n"); et = MVS_ERR_TFE; @@ -920,7 +922,6 @@ device_printf(dev, "ATAPI CMDOUT\n"); return; case ATAPI_P_READ: -//device_printf(dev, "ATAPI READ\n"); if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { device_printf(dev, "trying to read on write buffer\n"); et = MVS_ERR_TFE; @@ -937,7 +938,6 @@ device_printf(dev, "ATAPI CMDOUT\n"); return; case ATAPI_P_DONEDRQ: -device_printf(dev, "ATAPI DONEDRQ\n"); device_printf(dev, "WARNING - DONEDRQ non conformant device\n"); if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) { @@ -958,13 +958,13 @@ device_printf(dev, "ATAPI DONEDRQ\n"); case ATAPI_P_ABORT: case ATAPI_P_DONE: -//device_printf(dev, "ATAPI ABORT/DONE\n"); if (status & (ATA_S_ERROR | ATA_S_DWF)) et = MVS_ERR_TFE; goto end_finished; default: - device_printf(dev, "unknown transfer phase (status %02x, ireason %02x)\n", + device_printf(dev, "unknown transfer phase" + " (status %02x, ireason %02x)\n", status, ireason); et = MVS_ERR_TFE; } @@ -980,38 +980,54 @@ mvs_crbq_intr(device_t dev) struct mvs_channel *ch = device_get_softc(dev); struct mvs_crpb *crpb; union ccb *ccb; - int in_idx, cin_idx, slot; + int in_idx, fin_idx, cin_idx, slot; + uint32_t val; uint16_t flags; - in_idx = (ATA_INL(ch->r_mem, EDMA_RESQIP) & EDMA_RESQP_ERPQP_MASK) >> + val = ATA_INL(ch->r_mem, EDMA_RESQIP); + if (val == 0) + val = ATA_INL(ch->r_mem, EDMA_RESQIP); + in_idx = (val & EDMA_RESQP_ERPQP_MASK) >> EDMA_RESQP_ERPQP_SHIFT; bus_dmamap_sync(ch->dma.workrp_tag, ch->dma.workrp_map, BUS_DMASYNC_POSTREAD); - cin_idx = ch->in_idx; + fin_idx = cin_idx = ch->in_idx; ch->in_idx = in_idx; while (in_idx != cin_idx) { crpb = (struct mvs_crpb *) - (ch->dma.workrp + MVS_CRPB_OFFSET + (MVS_CRPB_SIZE * cin_idx)); + (ch->dma.workrp + MVS_CRPB_OFFSET + + (MVS_CRPB_SIZE * cin_idx)); slot = le16toh(crpb->id) & MVS_CRPB_TAG_MASK; flags = le16toh(crpb->rspflg); -//device_printf(dev, "CRPB %d %d %04x\n", cin_idx, slot, flags); /* * Handle only successfull completions here. * Errors will be handled by main intr handler. */ - if (ch->numtslots != 0 || (flags & EDMA_IE_EDEVERR) == 0) { -if ((flags >> 8) & ATA_S_ERROR) -device_printf(dev, "ERROR STATUS CRPB %d %d %04x\n", cin_idx, slot, flags); + if (crpb->id == 0xffff && crpb->rspflg == 0xffff) { + device_printf(dev, "Unfilled CRPB " + "%d (%d->%d) tag %d flags %04x rs %08x\n", + cin_idx, fin_idx, in_idx, slot, flags, ch->rslots); + } else if (ch->numtslots != 0 || + (flags & EDMA_IE_EDEVERR) == 0) { + crpb->id = 0xffff; + crpb->rspflg = 0xffff; if (ch->slot[slot].state >= MVS_SLOT_RUNNING) { ccb = ch->slot[slot].ccb; - ccb->ataio.res.status = (flags & MVS_CRPB_ATASTS_MASK) >> + ccb->ataio.res.status = + (flags & MVS_CRPB_ATASTS_MASK) >> MVS_CRPB_ATASTS_SHIFT; mvs_end_transaction(&ch->slot[slot], MVS_ERR_NONE); - } else -device_printf(dev, "EMPTY CRPB %d (->%d) %d %04x\n", cin_idx, in_idx, slot, flags); - } else -device_printf(dev, "ERROR FLAGS CRPB %d %d %04x\n", cin_idx, slot, flags); - + } else { + device_printf(dev, "Unused tag in CRPB " + "%d (%d->%d) tag %d flags %04x rs %08x\n", + cin_idx, fin_idx, in_idx, slot, flags, + ch->rslots); + } + } else { + device_printf(dev, + "CRPB with error %d tag %d flags %04x\n", + cin_idx, slot, flags); + } cin_idx = (cin_idx + 1) & (MVS_MAX_SLOTS - 1); } bus_dmamap_sync(ch->dma.workrp_tag, ch->dma.workrp_map, @@ -1266,8 +1282,6 @@ mvs_legacy_execute_transaction(struct mvs_slot *slot) ch->rslots |= (1 << slot->slot); ATA_OUTB(ch->r_mem, SATA_SATAICTL, port << SATA_SATAICTL_PMPTX_SHIFT); if (ccb->ccb_h.func_code == XPT_ATA_IO) { -// device_printf(dev, "%d Legacy command %02x size %d\n", -// port, ccb->ataio.cmd.command, ccb->ataio.dxfer_len); mvs_tfd_write(dev, ccb); /* Device reset doesn't interrupt. */ if (ccb->ataio.cmd.command == ATA_DEVICE_RESET) { @@ -1287,7 +1301,8 @@ mvs_legacy_execute_transaction(struct mvs_slot *slot) /* If data write command - output the data */ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { if (mvs_wait(dev, ATA_S_DRQ, ATA_S_BUSY, 1000) < 0) { - device_printf(dev, "timeout waiting for write DRQ\n"); + device_printf(dev, + "timeout waiting for write DRQ\n"); mvs_end_transaction(slot, MVS_ERR_TIMEOUT); return; } @@ -1296,9 +1311,6 @@ mvs_legacy_execute_transaction(struct mvs_slot *slot) ch->transfersize / 2); } } else { -// device_printf(dev, "%d ATAPI command %02x size %d dma %d\n", -// port, ccb->csio.cdb_io.cdb_bytes[0], ccb->csio.dxfer_len, -// ch->basic_dma); ch->donecount = 0; ch->transfersize = min(ccb->csio.dxfer_len, ch->curr[port].bytecount); @@ -1331,7 +1343,8 @@ mvs_legacy_execute_transaction(struct mvs_slot *slot) DELAY(20); } if (timeout <= 0) { - device_printf(dev, "timeout waiting for ATAPI command ready\n"); + device_printf(dev, + "timeout waiting for ATAPI command ready\n"); mvs_end_transaction(slot, MVS_ERR_TIMEOUT); return; } @@ -1371,8 +1384,6 @@ mvs_execute_transaction(struct mvs_slot *slot) int port = ccb->ccb_h.target_id & 0x0f; int i; -// device_printf(dev, "%d EDMA command %02x size %d slot %d tag %d\n", -// port, ccb->ataio.cmd.command, ccb->ataio.dxfer_len, slot->slot, slot->tag); /* Get address of the prepared EPRD */ eprd = ch->dma.workrq_bus + MVS_EPRD_OFFSET + (MVS_EPRD_SIZE * slot->slot); /* Prepare CRQB. Gen IIe uses different CRQB format. */ @@ -1552,8 +1563,8 @@ mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et) device_t dev = slot->dev; struct mvs_channel *ch = device_get_softc(dev); union ccb *ccb = slot->ccb; + int lastto; -//device_printf(dev, "cmd done status %d\n", et); bus_dmamap_sync(ch->dma.workrq_tag, ch->dma.workrq_map, BUS_DMASYNC_POSTWRITE); /* Read result registers to the result struct @@ -1634,11 +1645,6 @@ mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et) ch->oslots &= ~(1 << slot->slot); ch->rslots &= ~(1 << slot->slot); ch->aslots &= ~(1 << slot->slot); - if (et != MVS_ERR_TIMEOUT) { - if (ch->toslots == (1 << slot->slot)) - xpt_release_simq(ch->sim, TRUE); - ch->toslots &= ~(1 << slot->slot); - } slot->state = MVS_SLOT_EMPTY; slot->ccb = NULL; /* Update channel stats. */ @@ -1658,6 +1664,13 @@ mvs_end_transaction(struct mvs_slot *slot, enum mvs_err_type et) ch->numpslots--; ch->basic_dma = 0; } + /* Cancel timeout state if request completed normally. */ + if (et != MVS_ERR_TIMEOUT) { + lastto = (ch->toslots == (1 << slot->slot)); + ch->toslots &= ~(1 << slot->slot); + if (lastto) + xpt_release_simq(ch->sim, TRUE); + } /* If it was our READ LOG command - process it. */ if (ch->readlog) { mvs_process_read_log(dev, ccb); @@ -1789,7 +1802,8 @@ mvs_process_read_log(device_t dev, union ccb *ccb) if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) device_printf(dev, "Error while READ LOG EXT\n"); else if ((data[0] & 0x80) == 0) { - device_printf(dev, "Non-queued command error in READ LOG EXT\n"); + device_printf(dev, + "Non-queued command error in READ LOG EXT\n"); } for (i = 0; i < MVS_MAX_SLOTS; i++) { if (!ch->hold[i]) diff --git a/sys/dev/mvs/mvs_pci.c b/sys/dev/mvs/mvs_pci.c index 6b18e2c8ef6..e2e37daf595 100644 --- a/sys/dev/mvs/mvs_pci.c +++ b/sys/dev/mvs/mvs_pci.c @@ -339,7 +339,6 @@ mvs_intr(void *data) u_int32_t ic, aic; ic = ATA_INL(ctlr->r_mem, CHIP_MIC); -//device_printf(ctlr->dev, "irq MIC:%08x\n", ic); if (ctlr->msi) { /* We have to to mask MSI during processing. */ mtx_lock(&ctlr->mtx); diff --git a/sys/dev/mvs/mvs_soc.c b/sys/dev/mvs/mvs_soc.c index 03029c25624..ed861f29db8 100644 --- a/sys/dev/mvs/mvs_soc.c +++ b/sys/dev/mvs/mvs_soc.c @@ -295,7 +295,6 @@ mvs_intr(void *data) u_int32_t ic, aic; ic = ATA_INL(ctlr->r_mem, CHIP_SOC_MIC); -//device_printf(ctlr->dev, "irq MIC:%08x\n", ic); if ((ic & IC_HC0) == 0) return; /* Acknowledge interrupts of this HC. */ diff --git a/sys/dev/mwl/if_mwl_pci.c b/sys/dev/mwl/if_mwl_pci.c index 33666d40f12..d800a5470c2 100644 --- a/sys/dev/mwl/if_mwl_pci.c +++ b/sys/dev/mwl/if_mwl_pci.c @@ -313,4 +313,4 @@ static devclass_t mwl_devclass; DRIVER_MODULE(mwl, pci, mwl_pci_driver, mwl_devclass, 0, 0); MODULE_VERSION(mwl, 1); MODULE_DEPEND(mwl, wlan, 1, 1, 1); /* 802.11 media layer */ -MODULE_DEPEND(mwl, mwlfw_fw, 1, 1, 1); /* firmware */ +MODULE_DEPEND(mwl, firmware, 1, 1, 1); diff --git a/sys/dev/nfe/if_nfe.c b/sys/dev/nfe/if_nfe.c index 7d77754b90c..bb4f3bcc2aa 100644 --- a/sys/dev/nfe/if_nfe.c +++ b/sys/dev/nfe/if_nfe.c @@ -600,10 +600,10 @@ nfe_attach(device_t dev) #endif /* Do MII setup */ - if (mii_phy_probe(dev, &sc->nfe_miibus, nfe_ifmedia_upd, - nfe_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->nfe_miibus, ifp, nfe_ifmedia_upd, + nfe_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } ether_ifattach(ifp, sc->eaddr); diff --git a/sys/dev/nge/if_nge.c b/sys/dev/nge/if_nge.c index 1b346dd1d58..aef2269921b 100644 --- a/sys/dev/nge/if_nge.c +++ b/sys/dev/nge/if_nge.c @@ -1079,10 +1079,10 @@ nge_attach(device_t dev) /* * Do MII setup. */ - error = mii_phy_probe(dev, &sc->nge_miibus, nge_mediachange, - nge_mediastatus); + error = mii_attach(dev, &sc->nge_miibus, ifp, nge_mediachange, + nge_mediastatus, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); if (error != 0) { - device_printf(dev, "no PHY found!\n"); + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/nve/if_nve.c b/sys/dev/nve/if_nve.c index 6179869757b..b04ac190d4e 100644 --- a/sys/dev/nve/if_nve.c +++ b/sys/dev/nve/if_nve.c @@ -541,11 +541,12 @@ nve_attach(device_t dev) ifp->if_capabilities |= IFCAP_VLAN_MTU; ifp->if_capenable |= IFCAP_VLAN_MTU; - /* Probe device for MII interface to PHY */ - DEBUGOUT(NVE_DEBUG_INIT, "nve: do mii_phy_probe\n"); - if (mii_phy_probe(dev, &sc->miibus, nve_ifmedia_upd, nve_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + /* Attach device for MII interface to PHY */ + DEBUGOUT(NVE_DEBUG_INIT, "nve: do mii_attach\n"); + error = mii_attach(dev, &sc->miibus, ifp, nve_ifmedia_upd, + nve_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -553,10 +554,10 @@ nve_attach(device_t dev) ether_ifattach(ifp, eaddr); /* Activate our interrupt handler. - attach last to avoid lock */ - error = bus_setup_intr(sc->dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, + error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, nve_intr, sc, &sc->sc_ih); if (error) { - device_printf(sc->dev, "couldn't set up interrupt handler\n"); + device_printf(dev, "couldn't set up interrupt handler\n"); goto fail; } DEBUGOUT(NVE_DEBUG_INIT, "nve: nve_attach - exit\n"); diff --git a/sys/dev/ofw/ofw_fdt.c b/sys/dev/ofw/ofw_fdt.c index 0ec0830dee3..d67b2e5602d 100644 --- a/sys/dev/ofw/ofw_fdt.c +++ b/sys/dev/ofw/ofw_fdt.c @@ -66,7 +66,7 @@ static ssize_t ofw_fdt_canon(ofw_t, const char *, char *, size_t); static phandle_t ofw_fdt_finddevice(ofw_t, const char *); static ssize_t ofw_fdt_instance_to_path(ofw_t, ihandle_t, char *, size_t); static ssize_t ofw_fdt_package_to_path(ofw_t, phandle_t, char *, size_t); -static int ofw_fdt_interpret(ofw_t, const char *, int, unsigned long *); +static int ofw_fdt_interpret(ofw_t, const char *, int, cell_t *); static ofw_method_t ofw_fdt_methods[] = { OFWMETHOD(ofw_init, ofw_fdt_init), @@ -435,7 +435,7 @@ ofw_fdt_fixup(ofw_t ofw) } static int -ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, unsigned long *retvals) +ofw_fdt_interpret(ofw_t ofw, const char *cmd, int nret, cell_t *retvals) { int rv; diff --git a/sys/dev/ofw/ofw_if.m b/sys/dev/ofw/ofw_if.m index eff85a21c81..6017a69e7bd 100644 --- a/sys/dev/ofw/ofw_if.m +++ b/sys/dev/ofw/ofw_if.m @@ -244,7 +244,7 @@ METHOD int interpret { ofw_t _ofw; const char *_cmd; int _nreturns; - unsigned long *_returns; + cell_t *_returns; }; # Device I/O Functions (optional) diff --git a/sys/dev/ofw/ofw_iicbus.c b/sys/dev/ofw/ofw_iicbus.c index 2ee9a728318..875e4ddb13b 100644 --- a/sys/dev/ofw/ofw_iicbus.c +++ b/sys/dev/ofw/ofw_iicbus.c @@ -46,8 +46,8 @@ __FBSDID("$FreeBSD$"); /* Methods */ static device_probe_t ofw_iicbus_probe; static device_attach_t ofw_iicbus_attach; -static device_t ofw_iicbus_add_child(device_t dev, int order, const char *name, - int unit); +static device_t ofw_iicbus_add_child(device_t dev, u_int order, + const char *name, int unit); static const struct ofw_bus_devinfo *ofw_iicbus_get_devinfo(device_t bus, device_t dev); @@ -147,7 +147,7 @@ ofw_iicbus_attach(device_t dev) } static device_t -ofw_iicbus_add_child(device_t dev, int order, const char *name, int unit) +ofw_iicbus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct ofw_iicbus_devinfo *devi; diff --git a/sys/dev/ofw/ofw_standard.c b/sys/dev/ofw/ofw_standard.c index e3f8bcc87fa..b514a94f335 100644 --- a/sys/dev/ofw/ofw_standard.c +++ b/sys/dev/ofw/ofw_standard.c @@ -73,7 +73,7 @@ __FBSDID("$FreeBSD$"); static int ofw_std_init(ofw_t ofw, void *openfirm); static int ofw_std_test(ofw_t ofw, const char *name); static int ofw_std_interpret(ofw_t ofw, const char *cmd, int nreturns, - unsigned long *returns); + cell_t *returns); static phandle_t ofw_std_peer(ofw_t ofw, phandle_t node); static phandle_t ofw_std_child(ofw_t ofw, phandle_t node); static phandle_t ofw_std_parent(ofw_t ofw, phandle_t node); @@ -94,8 +94,7 @@ static ssize_t ofw_std_instance_to_path(ofw_t ofw, ihandle_t instance, static ssize_t ofw_std_package_to_path(ofw_t ofw, phandle_t package, char *buf, size_t len); static int ofw_std_call_method(ofw_t ofw, ihandle_t instance, - const char *method, int nargs, int nreturns, - cell_t *args_and_returns); + const char *method, int nargs, int nreturns, cell_t *args_and_returns); static ihandle_t ofw_std_open(ofw_t ofw, const char *device); static void ofw_std_close(ofw_t ofw, ihandle_t instance); static ssize_t ofw_std_read(ofw_t ofw, ihandle_t instance, void *addr, @@ -185,8 +184,7 @@ ofw_std_test(ofw_t ofw, const char *name) } static int -ofw_std_interpret(ofw_t ofw, const char *cmd, int nreturns, - unsigned long *returns) +ofw_std_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns) { struct { cell_t name; @@ -529,7 +527,7 @@ ofw_std_call_method(ofw_t ofw, ihandle_t instance, const char *method, 2, 1, }; - cell_t *cp, *ap; + cell_t *ap, *cp; int n; if (nargs > 6) diff --git a/sys/dev/ofw/openfirm.c b/sys/dev/ofw/openfirm.c index 241ce8a6369..8424fc20375 100644 --- a/sys/dev/ofw/openfirm.c +++ b/sys/dev/ofw/openfirm.c @@ -165,7 +165,7 @@ int OF_interpret(const char *cmd, int nreturns, ...) { va_list ap; - unsigned long slots[16]; + cell_t slots[16]; int i = 0; int status; diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index e1c7645821b..ef80f815d94 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -69,13 +69,6 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" #include "pci_if.h" -#ifdef __HAVE_ACPI -#include -#include "acpi_if.h" -#else -#define ACPI_PWR_FOR_SLEEP(x, y, z) -#endif - static pci_addr_t pci_mapbase(uint64_t mapreg); static const char *pci_maptype(uint64_t mapreg); static int pci_mapsize(uint64_t testval); @@ -189,6 +182,7 @@ struct pci_quirk { int type; #define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */ #define PCI_QUIRK_DISABLE_MSI 2 /* MSI/MSI-X doesn't work */ +#define PCI_QUIRK_ENABLE_MSI_VM 3 /* Older chipset in VM where MSI works */ int arg1; int arg2; }; @@ -225,6 +219,12 @@ struct pci_quirk pci_quirks[] = { */ { 0x74501022, PCI_QUIRK_DISABLE_MSI, 0, 0 }, + /* + * Some virtualization environments emulate an older chipset + * but support MSI just fine. QEMU uses the Intel 82440. + */ + { 0x12378086, PCI_QUIRK_ENABLE_MSI_VM, 0, 0 }, + { 0 } }; @@ -264,6 +264,12 @@ SYSCTL_INT(_hw_pci, OID_AUTO, do_power_resume, CTLFLAG_RW, &pci_do_power_resume, 1, "Transition from D3 -> D0 on resume."); +int pci_do_power_suspend = 1; +TUNABLE_INT("hw.pci.do_power_suspend", &pci_do_power_suspend); +SYSCTL_INT(_hw_pci, OID_AUTO, do_power_suspend, CTLFLAG_RW, + &pci_do_power_suspend, 1, + "Transition from D0 -> D3 on suspend."); + static int pci_do_msi = 1; TUNABLE_INT("hw.pci.enable_msi", &pci_do_msi); SYSCTL_INT(_hw_pci, OID_AUTO, enable_msi, CTLFLAG_RW, &pci_do_msi, 1, @@ -601,7 +607,7 @@ pci_read_extcap(device_t pcib, pcicfgregs *cfg) if (cfg->pp.pp_cap == 0) { cfg->pp.pp_cap = REG(ptr + PCIR_POWER_CAP, 2); cfg->pp.pp_status = ptr + PCIR_POWER_STATUS; - cfg->pp.pp_pmcsr = ptr + PCIR_POWER_PMCSR; + cfg->pp.pp_bse = ptr + PCIR_POWER_BSE; if ((nextptr - ptr) > PCIR_POWER_DATA) cfg->pp.pp_data = ptr + PCIR_POWER_DATA; } @@ -1834,6 +1840,23 @@ pci_msi_device_blacklisted(device_t dev) return (0); } +/* + * Returns true if a specified chipset supports MSI when it is + * emulated hardware in a virtual machine. + */ +static int +pci_msi_vm_chipset(device_t dev) +{ + struct pci_quirk *q; + + for (q = &pci_quirks[0]; q->devid; q++) { + if (q->devid == pci_get_devid(dev) && + q->type == PCI_QUIRK_ENABLE_MSI_VM) + return (1); + } + return (0); +} + /* * Determine if MSI is blacklisted globally on this sytem. Currently, * we just check for blacklisted chipsets as represented by the @@ -1850,8 +1873,14 @@ pci_msi_blacklisted(void) return (0); /* Blacklist all non-PCI-express and non-PCI-X chipsets. */ - if (!(pcie_chipset || pcix_chipset)) + if (!(pcie_chipset || pcix_chipset)) { + if (vm_guest != VM_GUEST_NO) { + dev = pci_find_bsf(0, 0, 0); + if (dev != NULL) + return (pci_msi_vm_chipset(dev) == 0); + } return (1); + } dev = pci_find_bsf(0, 0, 0); if (dev != NULL) @@ -2910,25 +2939,48 @@ pci_attach(device_t dev) return (bus_generic_attach(dev)); } +static void +pci_set_power_children(device_t dev, device_t *devlist, int numdevs, + int state) +{ + device_t child, pcib; + struct pci_devinfo *dinfo; + int dstate, i; + + /* + * Set the device to the given state. If the firmware suggests + * a different power state, use it instead. If power management + * is not present, the firmware is responsible for managing + * device power. Skip children who aren't attached since they + * are handled separately. + */ + pcib = device_get_parent(dev); + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = device_get_ivars(child); + dstate = state; + if (device_is_attached(child) && + PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) + pci_set_powerstate(child, dstate); + } +} + int pci_suspend(device_t dev) { - int dstate, error, i, numdevs; - device_t acpi_dev, child, *devlist; + device_t child, *devlist; struct pci_devinfo *dinfo; + int error, i, numdevs; /* * Save the PCI configuration space for each child and set the * device in the appropriate power state for this sleep state. */ - acpi_dev = NULL; - if (pci_do_power_resume) - acpi_dev = devclass_get_device(devclass_find("acpi"), 0); if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) return (error); for (i = 0; i < numdevs; i++) { child = devlist[i]; - dinfo = (struct pci_devinfo *) device_get_ivars(child); + dinfo = device_get_ivars(child); pci_cfg_save(child, dinfo, 0); } @@ -2938,25 +2990,9 @@ pci_suspend(device_t dev) free(devlist, M_TEMP); return (error); } - - /* - * Always set the device to D3. If ACPI suggests a different - * power state, use it instead. If ACPI is not present, the - * firmware is responsible for managing device power. Skip - * children who aren't attached since they are powered down - * separately. Only manage type 0 devices for now. - */ - for (i = 0; acpi_dev && i < numdevs; i++) { - child = devlist[i]; - dinfo = (struct pci_devinfo *) device_get_ivars(child); - if (device_is_attached(child) && - (dinfo->cfg.hdrtype & PCIM_HDRTYPE) == - PCIM_HDRTYPE_NORMAL) { - dstate = PCI_POWERSTATE_D3; - ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate); - pci_set_powerstate(child, dstate); - } - } + if (pci_do_power_suspend) + pci_set_power_children(dev, devlist, numdevs, + PCI_POWERSTATE_D3); free(devlist, M_TEMP); return (0); } @@ -2964,34 +3000,24 @@ pci_suspend(device_t dev) int pci_resume(device_t dev) { - int i, numdevs, error; - device_t acpi_dev, child, *devlist; + device_t child, *devlist; struct pci_devinfo *dinfo; + int error, i, numdevs; /* * Set each child to D0 and restore its PCI configuration space. */ - acpi_dev = NULL; - if (pci_do_power_resume) - acpi_dev = devclass_get_device(devclass_find("acpi"), 0); if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) return (error); - for (i = 0; i < numdevs; i++) { - /* - * Notify ACPI we're going to D0 but ignore the result. If - * ACPI is not present, the firmware is responsible for - * managing device power. Only manage type 0 devices for now. - */ - child = devlist[i]; - dinfo = (struct pci_devinfo *) device_get_ivars(child); - if (acpi_dev && device_is_attached(child) && - (dinfo->cfg.hdrtype & PCIM_HDRTYPE) == - PCIM_HDRTYPE_NORMAL) { - ACPI_PWR_FOR_SLEEP(acpi_dev, child, NULL); - pci_set_powerstate(child, PCI_POWERSTATE_D0); - } + if (pci_do_power_resume) + pci_set_power_children(dev, devlist, numdevs, + PCI_POWERSTATE_D0); + + /* Now the device is powered up, restore its config space. */ + for (i = 0; i < numdevs; i++) { + child = devlist[i]; + dinfo = device_get_ivars(child); - /* Now the device is powered up, restore its config space. */ pci_cfg_restore(child, dinfo); if (!device_is_attached(child)) pci_cfg_save(child, dinfo, 1); @@ -3349,7 +3375,7 @@ pci_probe_nomatch(device_t dev, device_t child) } printf(" at device %d.%d (no driver attached)\n", pci_get_slot(child), pci_get_function(child)); - pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1); + pci_cfg_save(child, device_get_ivars(child), 1); return; } @@ -3668,9 +3694,15 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, res = NULL; pci_read_bar(child, *rid, &map, &testval); - /* Ignore a BAR with a base of 0. */ - if ((*rid == PCIR_BIOS && pci_rombase(testval) == 0) || - pci_mapbase(testval) == 0) + /* + * Determine the size of the BAR and ignore BARs with a size + * of 0. Device ROM BARs use a different mask value. + */ + if (*rid == PCIR_BIOS) + mapsize = pci_romsize(testval); + else + mapsize = pci_mapsize(testval); + if (mapsize == 0) goto out; if (PCI_BAR_MEM(testval) || *rid == PCIR_BIOS) { @@ -3699,13 +3731,7 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid, * actually uses and we would otherwise have a * situation where we might allocate the excess to * another driver, which won't work. - * - * Device ROM BARs use a different mask value. */ - if (*rid == PCIR_BIOS) - mapsize = pci_romsize(testval); - else - mapsize = pci_mapsize(testval); count = 1UL << mapsize; if (RF_ALIGNMENT(flags) < mapsize) flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); @@ -4030,9 +4056,8 @@ pci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) * the noise on boot by doing nothing if we are already in * state D0. */ - if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { + if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) pci_set_powerstate(dev, PCI_POWERSTATE_D0); - } for (i = 0; i < dinfo->cfg.nummaps; i++) pci_write_config(dev, PCIR_BAR(i), dinfo->cfg.bar[i], 4); pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4); diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index 996d2745527..79158187cab 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -48,22 +48,16 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include "pcib_if.h" -#ifdef __HAVE_ACPI -#include -#include "acpi_if.h" -#else -#define ACPI_PWR_FOR_SLEEP(x, y, z) -#endif - -extern int pci_do_power_resume; - static int pcib_probe(device_t dev); static int pcib_suspend(device_t dev); static int pcib_resume(device_t dev); +static int pcib_power_for_sleep(device_t pcib, device_t dev, + int *pstate); static device_method_t pcib_methods[] = { /* Device interface */ @@ -95,6 +89,7 @@ static device_method_t pcib_methods[] = { DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), DEVMETHOD(pcib_release_msix, pcib_release_msix), DEVMETHOD(pcib_map_msi, pcib_map_msi), + DEVMETHOD(pcib_power_for_sleep, pcib_power_for_sleep), { 0, 0 } }; @@ -447,18 +442,16 @@ pcib_attach(device_t dev) int pcib_suspend(device_t dev) { - device_t acpi_dev; + device_t pcib; int dstate, error; pcib_cfg_save(device_get_softc(dev)); error = bus_generic_suspend(dev); - if (error == 0 && pci_do_power_resume) { - acpi_dev = devclass_get_device(devclass_find("acpi"), 0); - if (acpi_dev != NULL) { - dstate = PCI_POWERSTATE_D3; - ACPI_PWR_FOR_SLEEP(acpi_dev, dev, &dstate); + if (error == 0 && pci_do_power_suspend) { + dstate = PCI_POWERSTATE_D3; + pcib = device_get_parent(device_get_parent(dev)); + if (PCIB_POWER_FOR_SLEEP(pcib, dev, &dstate) == 0) pci_set_powerstate(dev, dstate); - } } return (error); } @@ -466,14 +459,12 @@ pcib_suspend(device_t dev) int pcib_resume(device_t dev) { - device_t acpi_dev; + device_t pcib; if (pci_do_power_resume) { - acpi_dev = devclass_get_device(devclass_find("acpi"), 0); - if (acpi_dev != NULL) { - ACPI_PWR_FOR_SLEEP(acpi_dev, dev, NULL); + pcib = device_get_parent(device_get_parent(dev)); + if (PCIB_POWER_FOR_SLEEP(pcib, dev, NULL) == 0) pci_set_powerstate(dev, PCI_POWERSTATE_D0); - } } pcib_cfg_restore(device_get_softc(dev)); return (bus_generic_resume(dev)); @@ -790,6 +781,16 @@ pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, return (0); } +/* Pass request for device power state up to parent bridge. */ +int +pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); +} + /* * Try to read the bus number of a host-PCI bridge using appropriate config * registers. diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h index 2240b4f2c0d..90866eff618 100644 --- a/sys/dev/pci/pci_private.h +++ b/sys/dev/pci/pci_private.h @@ -38,6 +38,9 @@ */ DECLARE_CLASS(pci_driver); +extern int pci_do_power_resume; +extern int pci_do_power_suspend; + void pci_add_children(device_t dev, int domain, int busno, size_t dinfo_size); void pci_add_child(device_t bus, struct pci_devinfo *dinfo); diff --git a/sys/dev/pci/pcib_if.m b/sys/dev/pci/pcib_if.m index 0b7e8bc62c9..b946c0f0541 100644 --- a/sys/dev/pci/pcib_if.m +++ b/sys/dev/pci/pcib_if.m @@ -144,3 +144,13 @@ METHOD int map_msi { uint64_t *addr; uint32_t *data; }; + +# +# Return the device power state to be used during a system sleep state +# transition such as suspend and resume. +# +METHOD int power_for_sleep { + device_t pcib; + device_t dev; + int *pstate; +}; diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index 5c747ec5350..02fa7ea2dce 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -36,6 +36,7 @@ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) * PCID_xxx: device ID * PCIY_xxx: capability identification number + * PCIZ_xxx: extended capability identification number */ /* some PCI bus constants */ @@ -66,7 +67,7 @@ #define PCIM_STATUS_CAPPRESENT 0x0010 #define PCIM_STATUS_66CAPABLE 0x0020 #define PCIM_STATUS_BACKTOBACK 0x0080 -#define PCIM_STATUS_PERRREPORT 0x0100 +#define PCIM_STATUS_MDPERR 0x0100 #define PCIM_STATUS_SEL_FAST 0x0000 #define PCIM_STATUS_SEL_MEDIMUM 0x0200 #define PCIM_STATUS_SEL_SLOW 0x0400 @@ -117,6 +118,28 @@ #define PCIY_SATA 0x12 /* SATA */ #define PCIY_PCIAF 0x13 /* PCI Advanced Features */ +/* Extended Capability Register Fields */ + +#define PCIR_EXTCAP 0x100 +#define PCIM_EXTCAP_ID 0x0000ffff +#define PCIM_EXTCAP_VER 0x000f0000 +#define PCIM_EXTCAP_NEXTPTR 0xfff00000 +#define PCI_EXTCAP_ID(ecap) ((ecap) & PCIM_EXTCAP_ID) +#define PCI_EXTCAP_VER(ecap) (((ecap) & PCIM_EXTCAP_VER) >> 16) +#define PCI_EXTCAP_NEXTPTR(ecap) (((ecap) & PCIM_EXTCAP_NEXTPTR) >> 20) + +/* Extended Capability Identification Numbers */ + +#define PCIZ_AER 0x0001 /* Advanced Error Reporting */ +#define PCIZ_VC 0x0002 /* Virtual Channel */ +#define PCIZ_SERNUM 0x0003 /* Device Serial Number */ +#define PCIZ_PWRBDGT 0x0004 /* Power Budgeting */ +#define PCIZ_VENDOR 0x000b /* Vendor Unique */ +#define PCIZ_ACS 0x000d /* Access Control Services */ +#define PCIZ_ARI 0x000e /* Alternative Routing-ID Interpretation */ +#define PCIZ_ATS 0x000f /* Address Translation Services */ +#define PCIZ_SRIOV 0x0010 /* Single Root IO Virtualization */ + /* config registers for header type 0 devices */ #define PCIR_BARS 0x10 @@ -404,12 +427,16 @@ #define PCIR_POWER_CAP 0x2 #define PCIM_PCAP_SPEC 0x0007 #define PCIM_PCAP_PMEREQCLK 0x0008 -#define PCIM_PCAP_PMEREQPWR 0x0010 #define PCIM_PCAP_DEVSPECINIT 0x0020 -#define PCIM_PCAP_DYNCLOCK 0x0040 -#define PCIM_PCAP_SECCLOCK 0x00c0 -#define PCIM_PCAP_CLOCKMASK 0x00c0 -#define PCIM_PCAP_REQFULLCLOCK 0x0100 +#define PCIM_PCAP_AUXPWR_0 0x0000 +#define PCIM_PCAP_AUXPWR_55 0x0040 +#define PCIM_PCAP_AUXPWR_100 0x0080 +#define PCIM_PCAP_AUXPWR_160 0x00c0 +#define PCIM_PCAP_AUXPWR_220 0x0100 +#define PCIM_PCAP_AUXPWR_270 0x0140 +#define PCIM_PCAP_AUXPWR_320 0x0180 +#define PCIM_PCAP_AUXPWR_375 0x01c0 +#define PCIM_PCAP_AUXPWRMASK 0x01c0 #define PCIM_PCAP_D1SUPP 0x0200 #define PCIM_PCAP_D2SUPP 0x0400 #define PCIM_PCAP_D0PME 0x0800 @@ -424,16 +451,17 @@ #define PCIM_PSTAT_D2 0x0002 #define PCIM_PSTAT_D3 0x0003 #define PCIM_PSTAT_DMASK 0x0003 -#define PCIM_PSTAT_REPENABLE 0x0010 +#define PCIM_PSTAT_NOSOFTRESET 0x0008 #define PCIM_PSTAT_PMEENABLE 0x0100 #define PCIM_PSTAT_D0POWER 0x0000 #define PCIM_PSTAT_D1POWER 0x0200 #define PCIM_PSTAT_D2POWER 0x0400 #define PCIM_PSTAT_D3POWER 0x0600 #define PCIM_PSTAT_D0HEAT 0x0800 -#define PCIM_PSTAT_D1HEAT 0x1000 -#define PCIM_PSTAT_D2HEAT 0x1200 -#define PCIM_PSTAT_D3HEAT 0x1400 +#define PCIM_PSTAT_D1HEAT 0x0a00 +#define PCIM_PSTAT_D2HEAT 0x0c00 +#define PCIM_PSTAT_D3HEAT 0x0e00 +#define PCIM_PSTAT_DATASELMASK 0x1e00 #define PCIM_PSTAT_DATAUNKN 0x0000 #define PCIM_PSTAT_DATADIV10 0x2000 #define PCIM_PSTAT_DATADIV100 0x4000 @@ -441,11 +469,10 @@ #define PCIM_PSTAT_DATADIVMASK 0x6000 #define PCIM_PSTAT_PME 0x8000 -#define PCIR_POWER_PMCSR 0x6 -#define PCIM_PMCSR_DCLOCK 0x10 -#define PCIM_PMCSR_B2SUPP 0x20 -#define PCIM_BMCSR_B3SUPP 0x40 -#define PCIM_BMCSR_BPCE 0x80 +#define PCIR_POWER_BSE 0x6 +#define PCIM_PMCSR_BSE_D3B3 0x00 +#define PCIM_PMCSR_BSE_D3B2 0x40 +#define PCIM_PMCSR_BSE_BPCCE 0x80 #define PCIR_POWER_DATA 0x7 @@ -663,3 +690,64 @@ #define PCIR_PCIAFCTRL_FLR 0x01 #define PCIR_PCIAF_STATUS 0x5 #define PCIR_PCIAFSTATUS_TP 0x01 + +/* Advanced Error Reporting */ +#define PCIR_AER_UC_STATUS 0x04 +#define PCIM_AER_UC_TRAINING_ERROR 0x00000001 +#define PCIM_AER_UC_DL_PROTOCOL_ERROR 0x00000010 +#define PCIM_AER_UC_POISONED_TLP 0x00001000 +#define PCIM_AER_UC_FC_PROTOCOL_ERROR 0x00002000 +#define PCIM_AER_UC_COMPLETION_TIMEOUT 0x00004000 +#define PCIM_AER_UC_COMPLETER_ABORT 0x00008000 +#define PCIM_AER_UC_UNEXPECTED_COMPLETION 0x00010000 +#define PCIM_AER_UC_RECEIVER_OVERFLOW 0x00020000 +#define PCIM_AER_UC_MALFORMED_TLP 0x00040000 +#define PCIM_AER_UC_ECRC_ERROR 0x00080000 +#define PCIM_AER_UC_UNSUPPORTED_REQUEST 0x00100000 +#define PCIM_AER_UC_ACS_VIOLATION 0x00200000 +#define PCIR_AER_UC_MASK 0x08 /* Shares bits with UC_STATUS */ +#define PCIR_AER_UC_SEVERITY 0x0c /* Shares bits with UC_STATUS */ +#define PCIR_AER_COR_STATUS 0x10 +#define PCIM_AER_COR_RECEIVER_ERROR 0x00000001 +#define PCIM_AER_COR_BAD_TLP 0x00000040 +#define PCIM_AER_COR_BAD_DLLP 0x00000080 +#define PCIM_AER_COR_REPLAY_ROLLOVER 0x00000100 +#define PCIM_AER_COR_REPLAY_TIMEOUT 0x00001000 +#define PCIR_AER_COR_MASK 0x14 /* Shares bits with COR_STATUS */ +#define PCIR_AER_CAP_CONTROL 0x18 +#define PCIM_AER_FIRST_ERROR_PTR 0x0000001f +#define PCIM_AER_ECRC_GEN_CAPABLE 0x00000020 +#define PCIM_AER_ECRC_GEN_ENABLE 0x00000040 +#define PCIM_AER_ECRC_CHECK_CAPABLE 0x00000080 +#define PCIM_AER_ECRC_CHECK_ENABLE 0x00000100 +#define PCIR_AER_HEADER_LOG 0x1c +#define PCIR_AER_ROOTERR_CMD 0x2c /* Only for root complex ports */ +#define PCIM_AER_ROOTERR_COR_ENABLE 0x00000001 +#define PCIM_AER_ROOTERR_NF_ENABLE 0x00000002 +#define PCIM_AER_ROOTERR_F_ENABLE 0x00000004 +#define PCIR_AER_ROOTERR_STATUS 0x30 /* Only for root complex ports */ +#define PCIM_AER_ROOTERR_COR_ERR 0x00000001 +#define PCIM_AER_ROOTERR_MULTI_COR_ERR 0x00000002 +#define PCIM_AER_ROOTERR_UC_ERR 0x00000004 +#define PCIM_AER_ROOTERR_MULTI_UC_ERR 0x00000008 +#define PCIM_AER_ROOTERR_FIRST_UC_FATAL 0x00000010 +#define PCIM_AER_ROOTERR_NF_ERR 0x00000020 +#define PCIM_AER_ROOTERR_F_ERR 0x00000040 +#define PCIM_AER_ROOTERR_INT_MESSAGE 0xf8000000 +#define PCIR_AER_COR_SOURCE_ID 0x34 /* Only for root complex ports */ +#define PCIR_AER_ERR_SOURCE_ID 0x36 /* Only for root complex ports */ + +/* Virtual Channel definitions */ +#define PCIR_VC_CAP1 0x04 +#define PCIM_VC_CAP1_EXT_COUNT 0x00000007 +#define PCIM_VC_CAP1_LOWPRI_EXT_COUNT 0x00000070 +#define PCIR_VC_CAP2 0x08 +#define PCIR_VC_CONTROL 0x0C +#define PCIR_VC_STATUS 0x0E +#define PCIR_VC_RESOURCE_CAP(n) (0x10 + (n) * 0x0C) +#define PCIR_VC_RESOURCE_CTL(n) (0x14 + (n) * 0x0C) +#define PCIR_VC_RESOURCE_STA(n) (0x18 + (n) * 0x0C) + +/* Serial Number definitions */ +#define PCIR_SERIAL_LOW 0x04 +#define PCIR_SERIAL_HIGH 0x08 diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index d6a2a0e9ba9..aee967a7957 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -42,9 +42,9 @@ typedef uint64_t pci_addr_t; /* Interesting values for PCI power management */ struct pcicfg_pp { uint16_t pp_cap; /* PCI power management capabilities */ - uint8_t pp_status; /* config space address of PCI power status reg */ - uint8_t pp_pmcsr; /* config space address of PMCSR reg */ - uint8_t pp_data; /* config space address of PCI power data reg */ + uint8_t pp_status; /* conf. space addr. of PM control/status reg */ + uint8_t pp_bse; /* conf. space addr. of PM BSE reg */ + uint8_t pp_data; /* conf. space addr. of PM data reg */ }; struct vpd_readonly { diff --git a/sys/dev/pcn/if_pcn.c b/sys/dev/pcn/if_pcn.c index 6295a46b5bd..d7314a9c6bb 100644 --- a/sys/dev/pcn/if_pcn.c +++ b/sys/dev/pcn/if_pcn.c @@ -634,13 +634,16 @@ pcn_attach(dev) ifp->if_snd.ifq_maxlen = PCN_TX_LIST_CNT - 1; /* - * Do MII setup. + * Do MII setup. Note that loopback support isn't implemented. + * See the comment in pcn_miibus_readreg() for why we can't + * universally pass MIIF_NOISOLATE here. */ sc->pcn_extphyaddr = -1; - if (mii_phy_probe(dev, &sc->pcn_miibus, - pcn_ifmedia_upd, pcn_ifmedia_sts)) { - device_printf(dev, "MII without any PHY!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->pcn_miibus, ifp, pcn_ifmedia_upd, + pcn_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_NOLOOP); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } /* diff --git a/sys/dev/powermac_nvram/powermac_nvram.c b/sys/dev/powermac_nvram/powermac_nvram.c index 22174f9e04b..0c7949f78fa 100644 --- a/sys/dev/powermac_nvram/powermac_nvram.c +++ b/sys/dev/powermac_nvram/powermac_nvram.c @@ -115,7 +115,10 @@ powermac_nvram_probe(device_t dev) if (type == NULL || compatible == NULL) return ENXIO; - if (strcmp(type, "nvram") != 0 || strcmp(compatible, "amd-0137") != 0) + if (strcmp(type, "nvram") != 0) + return ENXIO; + if (strcmp(compatible, "amd-0137") != 0 && + strcmp(compatible, "nvram,flash") != 0) return ENXIO; device_set_desc(dev, "Apple NVRAM"); @@ -126,6 +129,7 @@ static int powermac_nvram_attach(device_t dev) { struct powermac_nvram_softc *sc; + const char *compatible; phandle_t node; u_int32_t reg[3]; int gen0, gen1, i; @@ -139,6 +143,12 @@ powermac_nvram_attach(device_t dev) sc->sc_dev = dev; sc->sc_node = node; + compatible = ofw_bus_get_compat(dev); + if (strcmp(compatible, "amd-0137") == 0) + sc->sc_type = FLASH_TYPE_AMD; + else + sc->sc_type = FLASH_TYPE_SM; + /* * Find which byte of reg corresponds to the 32-bit physical address. * We should probably read #address-cells from /chosen instead. @@ -342,7 +352,7 @@ adler_checksum(uint8_t *data, int len) #define OUTB_DELAY(a, v) outb(a, v); DELAY(1); static int -wait_operation_complete(uint8_t *bank) +wait_operation_complete_amd(uint8_t *bank) { int i; @@ -353,7 +363,7 @@ wait_operation_complete(uint8_t *bank) } static int -erase_bank(device_t dev, uint8_t *bank) +erase_bank_amd(device_t dev, uint8_t *bank) { unsigned int i; @@ -368,7 +378,7 @@ erase_bank(device_t dev, uint8_t *bank) OUTB_DELAY(bank + 0x2aa, 0x55); OUTB_DELAY(bank, 0x30); - if (wait_operation_complete(bank) != 0) { + if (wait_operation_complete_amd(bank) != 0) { device_printf(dev, "flash erase timeout\n"); return -1; } @@ -386,7 +396,7 @@ erase_bank(device_t dev, uint8_t *bank) } static int -write_bank(device_t dev, uint8_t *bank, uint8_t *data) +write_bank_amd(device_t dev, uint8_t *bank, uint8_t *data) { unsigned int i; @@ -399,7 +409,7 @@ write_bank(device_t dev, uint8_t *bank, uint8_t *data) /* Write single word */ OUTB_DELAY(bank + 0x555, 0xa0); OUTB_DELAY(bank + i, data[i]); - if (wait_operation_complete(bank) != 0) { + if (wait_operation_complete_amd(bank) != 0) { device_printf(dev, "flash write timeout\n"); return -1; } @@ -416,3 +426,91 @@ write_bank(device_t dev, uint8_t *bank, uint8_t *data) } return 0; } + +static int +wait_operation_complete_sm(uint8_t *bank) +{ + int i; + + for (i = 1000000; i != 0; i--) { + outb(bank, SM_FLASH_CMD_READ_STATUS); + if (inb(bank) & SM_FLASH_STATUS_DONE) + return (0); + } + return (-1); +} + +static int +erase_bank_sm(device_t dev, uint8_t *bank) +{ + unsigned int i; + + outb(bank, SM_FLASH_CMD_ERASE_SETUP); + outb(bank, SM_FLASH_CMD_ERASE_CONFIRM); + + if (wait_operation_complete_sm(bank) != 0) { + device_printf(dev, "flash erase timeout\n"); + return (-1); + } + + outb(bank, SM_FLASH_CMD_CLEAR_STATUS); + outb(bank, SM_FLASH_CMD_RESET); + + for (i = 0; i < NVRAM_SIZE; i++) { + if (bank[i] != 0xff) { + device_printf(dev, "flash write has failed\n"); + return (-1); + } + } + return (0); +} + +static int +write_bank_sm(device_t dev, uint8_t *bank, uint8_t *data) +{ + unsigned int i; + + for (i = 0; i < NVRAM_SIZE; i++) { + OUTB_DELAY(bank + i, SM_FLASH_CMD_WRITE_SETUP); + outb(bank + i, data[i]); + if (wait_operation_complete_sm(bank) != 0) { + device_printf(dev, "flash write error/timeout\n"); + break; + } + } + + outb(bank, SM_FLASH_CMD_CLEAR_STATUS); + outb(bank, SM_FLASH_CMD_RESET); + + for (i = 0; i < NVRAM_SIZE; i++) { + if (bank[i] != data[i]) { + device_printf(dev, "flash write has failed\n"); + return (-1); + } + } + return (0); +} + +static int +erase_bank(device_t dev, uint8_t *bank) +{ + struct powermac_nvram_softc *sc; + + sc = device_get_softc(dev); + if (sc->sc_type == FLASH_TYPE_AMD) + return (erase_bank_amd(dev, bank)); + else + return (erase_bank_sm(dev, bank)); +} + +static int +write_bank(device_t dev, uint8_t *bank, uint8_t *data) +{ + struct powermac_nvram_softc *sc; + + sc = device_get_softc(dev); + if (sc->sc_type == FLASH_TYPE_AMD) + return (write_bank_amd(dev, bank, data)); + else + return (write_bank_sm(dev, bank, data)); +} diff --git a/sys/dev/powermac_nvram/powermac_nvramvar.h b/sys/dev/powermac_nvram/powermac_nvramvar.h index 6f4fb26e899..c326e3c5b5d 100644 --- a/sys/dev/powermac_nvram/powermac_nvramvar.h +++ b/sys/dev/powermac_nvram/powermac_nvramvar.h @@ -33,6 +33,16 @@ #define CORE99_SIGNATURE 0x5a +#define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 +#define SM_FLASH_CMD_ERASE_SETUP 0x20 +#define SM_FLASH_CMD_RESET 0xff +#define SM_FLASH_CMD_WRITE_SETUP 0x40 +#define SM_FLASH_CMD_CLEAR_STATUS 0x50 +#define SM_FLASH_CMD_READ_STATUS 0x70 + +#define SM_FLASH_STATUS_DONE 0x80 +#define SM_FLASH_STATUS_ERR 0x38 + #ifdef _KERNEL struct powermac_nvram_softc { @@ -44,6 +54,9 @@ struct powermac_nvram_softc { uint8_t sc_data[NVRAM_SIZE]; struct cdev * sc_cdev; + int sc_type; +#define FLASH_TYPE_SM 0 +#define FLASH_TYPE_AMD 1 int sc_isopen; int sc_rpos; int sc_wpos; diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c index a994355cfcf..9e21c67dcad 100644 --- a/sys/dev/ppbus/ppbconf.c +++ b/sys/dev/ppbus/ppbconf.c @@ -90,7 +90,7 @@ ppbus_probe(device_t dev) * Add a ppbus device, allocate/initialize the ivars */ static device_t -ppbus_add_child(device_t dev, int order, const char *name, int unit) +ppbus_add_child(device_t dev, u_int order, const char *name, int unit) { struct ppb_device *ppbdev; device_t child; diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c index 097771f46ed..cdf7badba8b 100644 --- a/sys/dev/ral/rt2560.c +++ b/sys/dev/ral/rt2560.c @@ -2667,8 +2667,7 @@ rt2560_init_locked(struct rt2560_softc *sc) RAL_WRITE(sc, RT2560_CSR1, RT2560_HOST_READY); if (rt2560_bbp_init(sc) != 0) { - rt2560_stop(sc); - RAL_UNLOCK(sc); + rt2560_stop_locked(sc); return; } diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index ef68f145af0..8fd20b6a832 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -409,9 +409,6 @@ re_gmii_readreg(device_t dev, int phy, int reg) u_int32_t rval; int i; - if (phy != 1) - return (0); - sc = device_get_softc(dev); /* Let the rgephy driver read the GMEDIASTAT register */ @@ -481,10 +478,6 @@ re_miibus_readreg(device_t dev, int phy, int reg) return (rval); } - /* Pretend the internal PHY is only at address 0 */ - if (phy) { - return (0); - } switch (reg) { case MII_BMCR: re8139_reg = RL_BMCR; @@ -539,10 +532,6 @@ re_miibus_writereg(device_t dev, int phy, int reg, int data) return (rval); } - /* Pretend the internal PHY is only at address 0 */ - if (phy) - return (0); - switch (reg) { case MII_BMCR: re8139_reg = RL_BMCR; @@ -1108,7 +1097,7 @@ re_attach(device_t dev) struct rl_hwrev *hw_rev; int hwrev; u_int16_t devid, re_did = 0; - int error = 0, rid, i; + int error = 0, i, phy, rid; int msic, reg; uint8_t cfg; @@ -1407,11 +1396,16 @@ re_attach(device_t dev) re_gmii_writereg(dev, 1, 0x0e, 0); } - /* Do MII setup */ - if (mii_phy_probe(dev, &sc->rl_miibus, - re_ifmedia_upd, re_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; +#define RE_PHYAD_INTERNAL 0 + + /* Do MII setup. */ + phy = RE_PHYAD_INTERNAL; + if (sc->rl_type == RL_8169) + phy = 1; + error = mii_attach(dev, &sc->rl_miibus, ifp, re_ifmedia_upd, + re_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/sf/if_sf.c b/sys/dev/sf/if_sf.c index 5238a271e84..7edb9768c4d 100644 --- a/sys/dev/sf/if_sf.c +++ b/sys/dev/sf/if_sf.c @@ -866,10 +866,10 @@ sf_attach(device_t dev) } /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->sf_miibus, sf_ifmedia_upd, - sf_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->sf_miibus, ifp, sf_ifmedia_upd, + sf_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1826,7 +1826,10 @@ sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) else if ((status & SF_ISR_DMAERR) != 0) { device_printf(sc->sf_dev, "DMA error, resetting\n"); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sf_init_locked(sc); + SF_UNLOCK(sc); + return (rx_npkts); } else if ((status & SF_ISR_NO_TX_CSUM) != 0) { sc->sf_statistics.sf_tx_gfp_stall++; #ifdef SF_GFP_DEBUG @@ -1894,8 +1897,10 @@ sf_intr(void *arg) else if ((status & SF_ISR_DMAERR) != 0) { device_printf(sc->sf_dev, "DMA error, resetting\n"); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sf_init_locked(sc); - break; + SF_UNLOCK(sc); + return; } else if ((status & SF_ISR_NO_TX_CSUM) != 0) { sc->sf_statistics.sf_tx_gfp_stall++; #ifdef SF_GFP_DEBUG @@ -1984,6 +1989,8 @@ sf_init_locked(struct sf_softc *sc) SF_LOCK_ASSERT(sc); ifp = sc->sf_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; mii = device_get_softc(sc->sf_miibus); sf_stop(sc); @@ -2547,6 +2554,7 @@ sf_watchdog(struct sf_softc *sc) if_printf(ifp, "watchdog timeout, %d Tx descs are active\n", sc->sf_cdata.sf_tx_cnt); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sf_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) diff --git a/sys/dev/sge/if_sge.c b/sys/dev/sge/if_sge.c index e294edd4cb7..f37959069da 100644 --- a/sys/dev/sge/if_sge.c +++ b/sys/dev/sge/if_sge.c @@ -627,10 +627,10 @@ sge_attach(device_t dev) /* * Do MII setup. */ - if (mii_phy_probe(dev, &sc->sge_miibus, sge_ifmedia_upd, - sge_ifmedia_sts)) { - device_printf(dev, "no PHY found!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->sge_miibus, ifp, sge_ifmedia_upd, + sge_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1457,7 +1457,9 @@ sge_encap(struct sge_softc *sc, struct mbuf **m_head) * Reset IP checksum and recompute TCP pseudo * checksum that NDIS specification requires. */ + ip = (struct ip *)(mtod(m, char *) + ip_off); ip->ip_sum = 0; + tcp = (struct tcphdr *)(mtod(m, char *) + poff); tcp->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, htons(IPPROTO_TCP)); *m_head = m; diff --git a/sys/dev/siba/siba.c b/sys/dev/siba/siba.c index 4ee11ca24a4..b2c49fb95c8 100644 --- a/sys/dev/siba/siba.c +++ b/sys/dev/siba/siba.c @@ -90,7 +90,7 @@ static struct siba_devid siba_devids[] = { static int siba_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t siba_add_child(device_t, int, const char *, int); +static device_t siba_add_child(device_t, u_int, const char *, int); static struct resource * siba_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -505,7 +505,7 @@ siba_destroy_devinfo(struct siba_devinfo *sdi) /* XXX is this needed? */ static device_t -siba_add_child(device_t dev, int order, const char *name, int unit) +siba_add_child(device_t dev, u_int order, const char *name, int unit) { #if 1 diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c index 34a77fc6a7a..0aef7757114 100644 --- a/sys/dev/siis/siis.c +++ b/sys/dev/siis/siis.c @@ -1179,6 +1179,7 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et) device_t dev = slot->dev; struct siis_channel *ch = device_get_softc(dev); union ccb *ccb = slot->ccb; + int lastto; mtx_assert(&ch->mtx, MA_OWNED); bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map, @@ -1262,11 +1263,6 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et) ch->oslots &= ~(1 << slot->slot); ch->rslots &= ~(1 << slot->slot); ch->aslots &= ~(1 << slot->slot); - if (et != SIIS_ERR_TIMEOUT) { - if (ch->toslots == (1 << slot->slot)) - xpt_release_simq(ch->sim, TRUE); - ch->toslots &= ~(1 << slot->slot); - } slot->state = SIIS_SLOT_EMPTY; slot->ccb = NULL; /* Update channel stats. */ @@ -1275,6 +1271,13 @@ siis_end_transaction(struct siis_slot *slot, enum siis_err_type et) (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) { ch->numtslots[ccb->ccb_h.target_id]--; } + /* Cancel timeout state if request completed normally. */ + if (et != SIIS_ERR_TIMEOUT) { + lastto = (ch->toslots == (1 << slot->slot)); + ch->toslots &= ~(1 << slot->slot); + if (lastto) + xpt_release_simq(ch->sim, TRUE); + } /* If it was our READ LOG command - process it. */ if (ch->readlog) { siis_process_read_log(dev, ccb); diff --git a/sys/dev/sis/if_sis.c b/sys/dev/sis/if_sis.c index 19833423c82..0957419a56f 100644 --- a/sys/dev/sis/if_sis.c +++ b/sys/dev/sis/if_sis.c @@ -64,12 +64,16 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include +#include +#include #include +#include +#include +#include #include #include +#include +#include #include #include @@ -127,17 +131,31 @@ static struct sis_type sis_devs[] = { }; static int sis_detach(device_t); +static __inline void sis_discard_rxbuf(struct sis_rxdesc *); +static int sis_dma_alloc(struct sis_softc *); +static void sis_dma_free(struct sis_softc *); +static int sis_dma_ring_alloc(struct sis_softc *, bus_size_t, bus_size_t, + bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *); +static void sis_dmamap_cb(void *, bus_dma_segment_t *, int, int); +#ifndef __NO_STRICT_ALIGNMENT +static __inline void sis_fixup_rx(struct mbuf *); +#endif static void sis_ifmedia_sts(struct ifnet *, struct ifmediareq *); static int sis_ifmedia_upd(struct ifnet *); static void sis_init(void *); static void sis_initl(struct sis_softc *); static void sis_intr(void *); static int sis_ioctl(struct ifnet *, u_long, caddr_t); -static int sis_newbuf(struct sis_softc *, struct sis_desc *, struct mbuf *); +static int sis_newbuf(struct sis_softc *, struct sis_rxdesc *); +static int sis_resume(device_t); +static int sis_rxeof(struct sis_softc *); static void sis_start(struct ifnet *); static void sis_startl(struct ifnet *); static void sis_stop(struct sis_softc *); +static int sis_suspend(device_t); +static void sis_add_sysctls(struct sis_softc *); static void sis_watchdog(struct sis_softc *); +static void sis_wol(struct sis_softc *); static struct resource_spec sis_res_spec[] = { @@ -164,33 +182,6 @@ static struct resource_spec sis_res_spec[] = { #define SIO_CLR(x) \ CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x) -static void -sis_dma_map_desc_next(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct sis_desc *r; - - r = arg; - r->sis_next = segs->ds_addr; -} - -static void -sis_dma_map_desc_ptr(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct sis_desc *r; - - r = arg; - r->sis_ptr = segs->ds_addr; -} - -static void -sis_dma_map_ring(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - u_int32_t *p; - - p = arg; - *p = segs->ds_addr; -} - /* * Routine to reverse the bits in a word. Stolen almost * verbatim from /usr/games/fortune. @@ -203,7 +194,7 @@ sis_reverse(uint16_t n) n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0); n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00); - return(n); + return (n); } static void @@ -273,7 +264,7 @@ static void sis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest) { int i; - u_int16_t word = 0; + uint16_t word = 0; /* Force EEPROM to idle state. */ sis_eeprom_idle(sc); @@ -316,11 +307,11 @@ static void sis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap) { int i; - u_int16_t word = 0, *ptr; + uint16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { sis_eeprom_getword(sc, off + i, &word); - ptr = (u_int16_t *)(dest + (i * 2)); + ptr = (uint16_t *)(dest + (i * 2)); if (swap) *ptr = ntohs(word); else @@ -342,7 +333,7 @@ sis_find_bridge(device_t dev) int i, j; if ((pci_devclass = devclass_find("pci")) == NULL) - return(NULL); + return (NULL); devclass_get_devices(pci_devclass, &pci_devices, &pci_count); @@ -363,14 +354,14 @@ sis_find_bridge(device_t dev) done: free(pci_devices, M_TEMP); - return(child); + return (child); } static void sis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt) { device_t bridge; - u_int8_t reg; + uint8_t reg; int i; bus_space_tag_t btag; @@ -393,32 +384,30 @@ sis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt } pci_write_config(bridge, 0x48, reg & ~0x40, 1); - return; } static void sis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest) { - u_int32_t filtsave, csrsave; + uint32_t filtsave, csrsave; filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); csrsave = CSR_READ_4(sc, SIS_CSR); CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave); CSR_WRITE_4(sc, SIS_CSR, 0); - + CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); - ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); - ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); - ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); + ((uint16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); CSR_WRITE_4(sc, SIS_CSR, csrsave); - return; } #endif @@ -429,9 +418,9 @@ static void sis_mii_sync(struct sis_softc *sc) { int i; - + SIO_SET(SIS_MII_DIR|SIS_MII_DATA); - + for (i = 0; i < 32; i++) { SIO_SET(SIS_MII_CLK); DELAY(1); @@ -439,7 +428,7 @@ sis_mii_sync(struct sis_softc *sc) DELAY(1); } } - + /* * Clock a series of bits through the MII. */ @@ -447,9 +436,9 @@ static void sis_mii_send(struct sis_softc *sc, uint32_t bits, int cnt) { int i; - + SIO_CLR(SIS_MII_CLK); - + for (i = (0x1 << (cnt - 1)); i; i >>= 1) { if (bits & i) { SIO_SET(SIS_MII_DATA); @@ -462,7 +451,7 @@ sis_mii_send(struct sis_softc *sc, uint32_t bits, int cnt) SIO_SET(SIS_MII_CLK); } } - + /* * Read an PHY register through the MII. */ @@ -470,7 +459,7 @@ static int sis_mii_readreg(struct sis_softc *sc, struct sis_mii_frame *frame) { int i, ack; - + /* * Set up frame for RX. */ @@ -478,14 +467,14 @@ sis_mii_readreg(struct sis_softc *sc, struct sis_mii_frame *frame) frame->mii_opcode = SIS_MII_READOP; frame->mii_turnaround = 0; frame->mii_data = 0; - + /* * Turn on data xmit. */ SIO_SET(SIS_MII_DIR); sis_mii_sync(sc); - + /* * Send command/address info. */ @@ -493,29 +482,29 @@ sis_mii_readreg(struct sis_softc *sc, struct sis_mii_frame *frame) sis_mii_send(sc, frame->mii_opcode, 2); sis_mii_send(sc, frame->mii_phyaddr, 5); sis_mii_send(sc, frame->mii_regaddr, 5); - + /* Idle bit */ SIO_CLR((SIS_MII_CLK|SIS_MII_DATA)); DELAY(1); SIO_SET(SIS_MII_CLK); DELAY(1); - + /* Turn off xmit. */ SIO_CLR(SIS_MII_DIR); - + /* Check for ack */ SIO_CLR(SIS_MII_CLK); DELAY(1); ack = CSR_READ_4(sc, SIS_EECTL) & SIS_MII_DATA; SIO_SET(SIS_MII_CLK); DELAY(1); - + /* * Now try reading data bits. If the ack failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ if (ack) { - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { SIO_CLR(SIS_MII_CLK); DELAY(1); SIO_SET(SIS_MII_CLK); @@ -523,7 +512,7 @@ sis_mii_readreg(struct sis_softc *sc, struct sis_mii_frame *frame) } goto fail; } - + for (i = 0x8000; i; i >>= 1) { SIO_CLR(SIS_MII_CLK); DELAY(1); @@ -544,51 +533,51 @@ fail: DELAY(1); if (ack) - return(1); - return(0); + return (1); + return (0); } - + /* * Write to a PHY register through the MII. */ static int sis_mii_writereg(struct sis_softc *sc, struct sis_mii_frame *frame) { - + /* * Set up frame for TX. */ - + frame->mii_stdelim = SIS_MII_STARTDELIM; frame->mii_opcode = SIS_MII_WRITEOP; frame->mii_turnaround = SIS_MII_TURNAROUND; - + /* * Turn on data output. */ SIO_SET(SIS_MII_DIR); - + sis_mii_sync(sc); - + sis_mii_send(sc, frame->mii_stdelim, 2); sis_mii_send(sc, frame->mii_opcode, 2); sis_mii_send(sc, frame->mii_phyaddr, 5); sis_mii_send(sc, frame->mii_regaddr, 5); sis_mii_send(sc, frame->mii_turnaround, 2); sis_mii_send(sc, frame->mii_data, 16); - + /* Idle bit. */ SIO_SET(SIS_MII_CLK); DELAY(1); SIO_CLR(SIS_MII_CLK); DELAY(1); - + /* * Turn off xmit. */ SIO_CLR(SIS_MII_DIR); - - return(0); + + return (0); } static int @@ -601,7 +590,7 @@ sis_miibus_readreg(device_t dev, int phy, int reg) if (sc->sis_type == SIS_TYPE_83815) { if (phy != 0) - return(0); + return (0); /* * The NatSemi chip can take a while after * a reset to come ready, during which the BMSR @@ -627,7 +616,7 @@ sis_miibus_readreg(device_t dev, int phy, int reg) int i, val = 0; if (phy != 0) - return(0); + return (0); CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ); @@ -640,15 +629,15 @@ sis_miibus_readreg(device_t dev, int phy, int reg) if (i == SIS_TIMEOUT) { device_printf(sc->sis_dev, "PHY failed to come ready\n"); - return(0); + return (0); } val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF; if (val == 0xFFFF) - return(0); + return (0); - return(val); + return (val); } else { bzero((char *)&frame, sizeof(frame)); @@ -656,7 +645,7 @@ sis_miibus_readreg(device_t dev, int phy, int reg) frame.mii_regaddr = reg; sis_mii_readreg(sc, &frame); - return(frame.mii_data); + return (frame.mii_data); } } @@ -670,9 +659,9 @@ sis_miibus_writereg(device_t dev, int phy, int reg, int data) if (sc->sis_type == SIS_TYPE_83815) { if (phy != 0) - return(0); + return (0); CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data); - return(0); + return (0); } /* @@ -685,7 +674,7 @@ sis_miibus_writereg(device_t dev, int phy, int reg, int data) int i; if (phy != 0) - return(0); + return (0); CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) | (reg << 6) | SIS_PHYOP_WRITE); @@ -706,17 +695,93 @@ sis_miibus_writereg(device_t dev, int phy, int reg, int data) frame.mii_data = data; sis_mii_writereg(sc, &frame); } - return(0); + return (0); } static void sis_miibus_statchg(device_t dev) { struct sis_softc *sc; + struct mii_data *mii; + struct ifnet *ifp; + uint32_t reg; sc = device_get_softc(dev); SIS_LOCK_ASSERT(sc); - sis_initl(sc); + + mii = device_get_softc(sc->sis_miibus); + ifp = sc->sis_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + sc->sis_flags &= ~SIS_FLAG_LINK; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); + sc->sis_flags |= SIS_FLAG_LINK; + break; + case IFM_100_TX: + CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); + sc->sis_flags |= SIS_FLAG_LINK; + break; + default: + break; + } + } + + if ((sc->sis_flags & SIS_FLAG_LINK) == 0) { + /* + * Stopping MACs seem to reset SIS_TX_LISTPTR and + * SIS_RX_LISTPTR which in turn requires resetting + * TX/RX buffers. So just don't do anything for + * lost link. + */ + return; + } + + /* Set full/half duplex mode. */ + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { + SIS_SETBIT(sc, SIS_TX_CFG, + (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); + SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); + } else { + SIS_CLRBIT(sc, SIS_TX_CFG, + (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); + SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); + } + + if (sc->sis_type == SIS_TYPE_83816) { + /* + * MPII03.D: Half Duplex Excessive Collisions. + * Also page 49 in 83816 manual + */ + SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D); + } + + if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A && + IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { + /* + * Short Cable Receive Errors (MP21.E) + */ + CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); + reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff; + CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000); + DELAY(100); + reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff; + if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) { + device_printf(sc->sis_dev, + "Applying short cable fix (reg=%x)\n", reg); + CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8); + SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20); + } + CSR_WRITE_4(sc, NS_PHY_PAGE, 0); + } + /* Enable TX/RX MACs. */ + SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE | SIS_CSR_RX_ENABLE); } static uint32_t @@ -747,7 +812,7 @@ sis_setmulti_ns(struct sis_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h = 0, i, filtsave; + uint32_t h = 0, i, filtsave; int bit, index; ifp = sc->sis_ifp; @@ -789,8 +854,6 @@ sis_setmulti_ns(struct sis_softc *sc) if_maddr_runlock(ifp); CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); - - return; } static void @@ -798,8 +861,8 @@ sis_setmulti_sis(struct sis_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; - u_int32_t h, i, n, ctl; - u_int16_t hashes[16]; + uint32_t h, i, n, ctl; + uint16_t hashes[16]; ifp = sc->sis_ifp; @@ -875,9 +938,10 @@ sis_reset(struct sis_softc *sc) if (sc->sis_type == SIS_TYPE_83815) { CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS); CSR_WRITE_4(sc, NS_CLKRUN, 0); + } else { + /* Disable WOL functions. */ + CSR_WRITE_4(sc, SIS_PWRMAN_CTL, 0); } - - return; } /* @@ -891,7 +955,7 @@ sis_probe(device_t dev) t = sis_devs; - while(t->sis_name != NULL) { + while (t->sis_name != NULL) { if ((pci_get_vendor(dev) == t->sis_vid) && (pci_get_device(dev) == t->sis_did)) { device_set_desc(dev, t->sis_name); @@ -900,7 +964,7 @@ sis_probe(device_t dev) t++; } - return(ENXIO); + return (ENXIO); } /* @@ -913,7 +977,7 @@ sis_attach(device_t dev) u_char eaddr[ETHER_ADDR_LEN]; struct sis_softc *sc; struct ifnet *ifp; - int error = 0, waittime = 0; + int error = 0, pmc, waittime = 0; waittime = 0; sc = device_get_softc(dev); @@ -947,8 +1011,8 @@ sis_attach(device_t dev) sis_reset(sc); if (sc->sis_type == SIS_TYPE_900 && - (sc->sis_rev == SIS_REV_635 || - sc->sis_rev == SIS_REV_900B)) { + (sc->sis_rev == SIS_REV_635 || + sc->sis_rev == SIS_REV_900B)) { SIO_SET(SIS_CFG_RND_CNT); SIO_SET(SIS_CFG_PERR_DETECT); } @@ -983,7 +1047,7 @@ sis_attach(device_t dev) * Why? Who the hell knows. */ { - u_int16_t tmp[4]; + uint16_t tmp[4]; sis_read_eeprom(sc, (caddr_t)&tmp, NS_EE_NODEADDR, 4, 0); @@ -1001,7 +1065,12 @@ sis_attach(device_t dev) tmp[2] = sis_reverse(tmp[2]); tmp[1] = sis_reverse(tmp[1]); - bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN); + eaddr[0] = (tmp[1] >> 0) & 0xFF; + eaddr[1] = (tmp[1] >> 8) & 0xFF; + eaddr[2] = (tmp[2] >> 0) & 0xFF; + eaddr[3] = (tmp[2] >> 8) & 0xFF; + eaddr[4] = (tmp[3] >> 0) & 0xFF; + eaddr[5] = (tmp[3] >> 8) & 0xFF; } break; case SIS_VENDORID: @@ -1061,127 +1130,12 @@ sis_attach(device_t dev) break; } - /* - * Allocate the parent bus DMA tag appropriate for PCI. - */ -#define SIS_NSEG_NEW 32 - error = bus_dma_tag_create(NULL, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MAXBSIZE, SIS_NSEG_NEW, /* maxsize, nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - NULL, NULL, /* lockfunc, lockarg */ - &sc->sis_parent_tag); - if (error) + sis_add_sysctls(sc); + + /* Allocate DMA'able memory. */ + if ((error = sis_dma_alloc(sc)) != 0) goto fail; - /* - * Now allocate a tag for the DMA descriptor lists and a chunk - * of DMA-able memory based on the tag. Also obtain the physical - * addresses of the RX and TX ring, which we'll need later. - * All of our lists are allocated as a contiguous block - * of memory. - */ - error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - SIS_RX_LIST_SZ, 1, /* maxsize,nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &Giant, /* lockarg */ - &sc->sis_rx_tag); - if (error) - goto fail; - - error = bus_dmamem_alloc(sc->sis_rx_tag, - (void **)&sc->sis_rx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO, - &sc->sis_rx_dmamap); - - if (error) { - device_printf(dev, "no memory for rx list buffers!\n"); - bus_dma_tag_destroy(sc->sis_rx_tag); - sc->sis_rx_tag = NULL; - goto fail; - } - - error = bus_dmamap_load(sc->sis_rx_tag, - sc->sis_rx_dmamap, &(sc->sis_rx_list[0]), - sizeof(struct sis_desc), sis_dma_map_ring, - &sc->sis_rx_paddr, 0); - - if (error) { - device_printf(dev, "cannot get address of the rx ring!\n"); - bus_dmamem_free(sc->sis_rx_tag, - sc->sis_rx_list, sc->sis_rx_dmamap); - bus_dma_tag_destroy(sc->sis_rx_tag); - sc->sis_rx_tag = NULL; - goto fail; - } - - error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &Giant, /* lockarg */ - &sc->sis_tx_tag); - if (error) - goto fail; - - error = bus_dmamem_alloc(sc->sis_tx_tag, - (void **)&sc->sis_tx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO, - &sc->sis_tx_dmamap); - - if (error) { - device_printf(dev, "no memory for tx list buffers!\n"); - bus_dma_tag_destroy(sc->sis_tx_tag); - sc->sis_tx_tag = NULL; - goto fail; - } - - error = bus_dmamap_load(sc->sis_tx_tag, - sc->sis_tx_dmamap, &(sc->sis_tx_list[0]), - sizeof(struct sis_desc), sis_dma_map_ring, - &sc->sis_tx_paddr, 0); - - if (error) { - device_printf(dev, "cannot get address of the tx ring!\n"); - bus_dmamem_free(sc->sis_tx_tag, - sc->sis_tx_list, sc->sis_tx_dmamap); - bus_dma_tag_destroy(sc->sis_tx_tag); - sc->sis_tx_tag = NULL; - goto fail; - } - - error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ - 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MCLBYTES, 1, /* maxsize,nsegments */ - BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ - 0, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &Giant, /* lockarg */ - &sc->sis_tag); - if (error) - goto fail; - - /* - * Obtain the physical addresses of the RX and TX - * rings which we'll need later in the init routine. - */ - ifp = sc->sis_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "can not if_alloc()\n"); @@ -1199,13 +1153,21 @@ sis_attach(device_t dev) ifp->if_snd.ifq_drv_maxlen = SIS_TX_LIST_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + if (pci_find_extcap(sc->sis_dev, PCIY_PMG, &pmc) == 0) { + if (sc->sis_type == SIS_TYPE_83815) + ifp->if_capabilities |= IFCAP_WOL; + else + ifp->if_capabilities |= IFCAP_WOL_MAGIC; + ifp->if_capenable = ifp->if_capabilities; + } + /* * Do MII setup. */ - if (mii_phy_probe(dev, &sc->sis_miibus, - sis_ifmedia_upd, sis_ifmedia_sts)) { - device_printf(dev, "MII without any PHY!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->sis_miibus, ifp, sis_ifmedia_upd, + sis_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1213,7 +1175,7 @@ sis_attach(device_t dev) * Call MI attach routine. */ ether_ifattach(ifp, eaddr); - + /* * Tell the upper layer(s) we support long frames. */ @@ -1238,7 +1200,7 @@ fail: if (error) sis_detach(dev); - return(error); + return (error); } /* @@ -1266,7 +1228,6 @@ sis_detach(device_t dev) /* These should only be active if attach succeeded. */ if (device_is_attached(dev)) { SIS_LOCK(sc); - sis_reset(sc); sis_stop(sc); SIS_UNLOCK(sc); callout_drain(&sc->sis_stat_ch); @@ -1283,28 +1244,204 @@ sis_detach(device_t dev) if (ifp) if_free(ifp); - if (sc->sis_rx_tag) { - bus_dmamap_unload(sc->sis_rx_tag, - sc->sis_rx_dmamap); - bus_dmamem_free(sc->sis_rx_tag, - sc->sis_rx_list, sc->sis_rx_dmamap); - bus_dma_tag_destroy(sc->sis_rx_tag); - } - if (sc->sis_tx_tag) { - bus_dmamap_unload(sc->sis_tx_tag, - sc->sis_tx_dmamap); - bus_dmamem_free(sc->sis_tx_tag, - sc->sis_tx_list, sc->sis_tx_dmamap); - bus_dma_tag_destroy(sc->sis_tx_tag); - } - if (sc->sis_parent_tag) - bus_dma_tag_destroy(sc->sis_parent_tag); - if (sc->sis_tag) - bus_dma_tag_destroy(sc->sis_tag); + sis_dma_free(sc); mtx_destroy(&sc->sis_mtx); - return(0); + return (0); +} + +struct sis_dmamap_arg { + bus_addr_t sis_busaddr; +}; + +static void +sis_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct sis_dmamap_arg *ctx; + + if (error != 0) + return; + + KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); + + ctx = (struct sis_dmamap_arg *)arg; + ctx->sis_busaddr = segs[0].ds_addr; +} + +static int +sis_dma_ring_alloc(struct sis_softc *sc, bus_size_t alignment, + bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, + bus_addr_t *paddr, const char *msg) +{ + struct sis_dmamap_arg ctx; + int error; + + error = bus_dma_tag_create(sc->sis_parent_tag, alignment, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, + maxsize, 0, NULL, NULL, tag); + if (error != 0) { + device_printf(sc->sis_dev, + "could not create %s dma tag\n", msg); + return (ENOMEM); + } + /* Allocate DMA'able memory for ring. */ + error = bus_dmamem_alloc(*tag, (void **)ring, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); + if (error != 0) { + device_printf(sc->sis_dev, + "could not allocate DMA'able memory for %s\n", msg); + return (ENOMEM); + } + /* Load the address of the ring. */ + ctx.sis_busaddr = 0; + error = bus_dmamap_load(*tag, *map, *ring, maxsize, sis_dmamap_cb, + &ctx, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sis_dev, + "could not load DMA'able memory for %s\n", msg); + return (ENOMEM); + } + *paddr = ctx.sis_busaddr; + return (0); +} + +static int +sis_dma_alloc(struct sis_softc *sc) +{ + struct sis_rxdesc *rxd; + struct sis_txdesc *txd; + int error, i; + + /* Allocate the parent bus DMA tag appropriate for PCI. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sis_dev), + 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, + NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, + 0, NULL, NULL, &sc->sis_parent_tag); + if (error != 0) { + device_printf(sc->sis_dev, + "could not allocate parent dma tag\n"); + return (ENOMEM); + } + + /* Create RX ring. */ + error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_RX_LIST_SZ, + &sc->sis_rx_list_tag, (uint8_t **)&sc->sis_rx_list, + &sc->sis_rx_list_map, &sc->sis_rx_paddr, "RX ring"); + if (error) + return (error); + + /* Create TX ring. */ + error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_TX_LIST_SZ, + &sc->sis_tx_list_tag, (uint8_t **)&sc->sis_tx_list, + &sc->sis_tx_list_map, &sc->sis_tx_paddr, "TX ring"); + if (error) + return (error); + + /* Create tag for RX mbufs. */ + error = bus_dma_tag_create(sc->sis_parent_tag, SIS_RX_BUF_ALIGN, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, + MCLBYTES, 0, NULL, NULL, &sc->sis_rx_tag); + if (error) { + device_printf(sc->sis_dev, "could not allocate RX dma tag\n"); + return (error); + } + + /* Create tag for TX mbufs. */ + error = bus_dma_tag_create(sc->sis_parent_tag, 1, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + MCLBYTES * SIS_MAXTXSEGS, SIS_MAXTXSEGS, MCLBYTES, 0, NULL, NULL, + &sc->sis_tx_tag); + if (error) { + device_printf(sc->sis_dev, "could not allocate TX dma tag\n"); + return (error); + } + + /* Create DMA maps for RX buffers. */ + error = bus_dmamap_create(sc->sis_rx_tag, 0, &sc->sis_rx_sparemap); + if (error) { + device_printf(sc->sis_dev, + "can't create spare DMA map for RX\n"); + return (error); + } + for (i = 0; i < SIS_RX_LIST_CNT; i++) { + rxd = &sc->sis_rxdesc[i]; + rxd->rx_m = NULL; + error = bus_dmamap_create(sc->sis_rx_tag, 0, &rxd->rx_dmamap); + if (error) { + device_printf(sc->sis_dev, + "can't create DMA map for RX\n"); + return (error); + } + } + + /* Create DMA maps for TX buffers. */ + for (i = 0; i < SIS_TX_LIST_CNT; i++) { + txd = &sc->sis_txdesc[i]; + txd->tx_m = NULL; + error = bus_dmamap_create(sc->sis_tx_tag, 0, &txd->tx_dmamap); + if (error) { + device_printf(sc->sis_dev, + "can't create DMA map for TX\n"); + return (error); + } + } + + return (0); +} + +static void +sis_dma_free(struct sis_softc *sc) +{ + struct sis_rxdesc *rxd; + struct sis_txdesc *txd; + int i; + + /* Destroy DMA maps for RX buffers. */ + for (i = 0; i < SIS_RX_LIST_CNT; i++) { + rxd = &sc->sis_rxdesc[i]; + if (rxd->rx_dmamap) + bus_dmamap_destroy(sc->sis_rx_tag, rxd->rx_dmamap); + } + if (sc->sis_rx_sparemap) + bus_dmamap_destroy(sc->sis_rx_tag, sc->sis_rx_sparemap); + + /* Destroy DMA maps for TX buffers. */ + for (i = 0; i < SIS_TX_LIST_CNT; i++) { + txd = &sc->sis_txdesc[i]; + if (txd->tx_dmamap) + bus_dmamap_destroy(sc->sis_tx_tag, txd->tx_dmamap); + } + + if (sc->sis_rx_tag) + bus_dma_tag_destroy(sc->sis_rx_tag); + if (sc->sis_tx_tag) + bus_dma_tag_destroy(sc->sis_tx_tag); + + /* Destroy RX ring. */ + if (sc->sis_rx_list_map) + bus_dmamap_unload(sc->sis_rx_list_tag, sc->sis_rx_list_map); + if (sc->sis_rx_list_map && sc->sis_rx_list) + bus_dmamem_free(sc->sis_rx_list_tag, sc->sis_rx_list, + sc->sis_rx_list_map); + + if (sc->sis_rx_list_tag) + bus_dma_tag_destroy(sc->sis_rx_list_tag); + + /* Destroy TX ring. */ + if (sc->sis_tx_list_map) + bus_dmamap_unload(sc->sis_tx_list_tag, sc->sis_tx_list_map); + + if (sc->sis_tx_list_map && sc->sis_tx_list) + bus_dmamem_free(sc->sis_tx_list_tag, sc->sis_tx_list, + sc->sis_tx_list_map); + + if (sc->sis_tx_list_tag) + bus_dma_tag_destroy(sc->sis_tx_list_tag); + + /* Destroy the parent tag. */ + if (sc->sis_parent_tag) + bus_dma_tag_destroy(sc->sis_parent_tag); } /* @@ -1315,81 +1452,110 @@ sis_detach(device_t dev) static int sis_ring_init(struct sis_softc *sc) { - int i, error; - struct sis_desc *dp; + struct sis_rxdesc *rxd; + struct sis_txdesc *txd; + bus_addr_t next; + int error, i; - dp = &sc->sis_tx_list[0]; - for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) { - if (i == (SIS_TX_LIST_CNT - 1)) - dp->sis_nextdesc = &sc->sis_tx_list[0]; + bzero(&sc->sis_tx_list[0], SIS_TX_LIST_SZ); + for (i = 0; i < SIS_TX_LIST_CNT; i++) { + txd = &sc->sis_txdesc[i]; + txd->tx_m = NULL; + if (i == SIS_TX_LIST_CNT - 1) + next = SIS_TX_RING_ADDR(sc, 0); else - dp->sis_nextdesc = dp + 1; - bus_dmamap_load(sc->sis_tx_tag, - sc->sis_tx_dmamap, - dp->sis_nextdesc, sizeof(struct sis_desc), - sis_dma_map_desc_next, dp, 0); - dp->sis_mbuf = NULL; - dp->sis_ptr = 0; - dp->sis_ctl = 0; + next = SIS_TX_RING_ADDR(sc, i + 1); + sc->sis_tx_list[i].sis_next = htole32(SIS_ADDR_LO(next)); } - sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0; + bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(sc->sis_tx_tag, - sc->sis_tx_dmamap, BUS_DMASYNC_PREWRITE); - - dp = &sc->sis_rx_list[0]; - for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) { - error = sis_newbuf(sc, dp, NULL); - if (error) - return(error); - if (i == (SIS_RX_LIST_CNT - 1)) - dp->sis_nextdesc = &sc->sis_rx_list[0]; + sc->sis_rx_cons = 0; + bzero(&sc->sis_rx_list[0], SIS_RX_LIST_SZ); + for (i = 0; i < SIS_RX_LIST_CNT; i++) { + rxd = &sc->sis_rxdesc[i]; + rxd->rx_desc = &sc->sis_rx_list[i]; + if (i == SIS_RX_LIST_CNT - 1) + next = SIS_RX_RING_ADDR(sc, 0); else - dp->sis_nextdesc = dp + 1; - bus_dmamap_load(sc->sis_rx_tag, - sc->sis_rx_dmamap, - dp->sis_nextdesc, sizeof(struct sis_desc), - sis_dma_map_desc_next, dp, 0); - } + next = SIS_RX_RING_ADDR(sc, i + 1); + rxd->rx_desc->sis_next = htole32(SIS_ADDR_LO(next)); + error = sis_newbuf(sc, rxd); + if (error) + return (error); + } + bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(sc->sis_rx_tag, - sc->sis_rx_dmamap, BUS_DMASYNC_PREWRITE); - - sc->sis_rx_pdsc = &sc->sis_rx_list[0]; - - return(0); + return (0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int -sis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m) +sis_newbuf(struct sis_softc *sc, struct sis_rxdesc *rxd) +{ + struct mbuf *m; + bus_dma_segment_t segs[1]; + bus_dmamap_t map; + int nsegs; + + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOBUFS); + m->m_len = m->m_pkthdr.len = SIS_RXLEN; +#ifndef __NO_STRICT_ALIGNMENT + m_adj(m, SIS_RX_BUF_ALIGN); +#endif + + if (bus_dmamap_load_mbuf_sg(sc->sis_rx_tag, sc->sis_rx_sparemap, m, + segs, &nsegs, 0) != 0) { + m_freem(m); + return (ENOBUFS); + } + KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); + + if (rxd->rx_m != NULL) { + bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); + } + map = rxd->rx_dmamap; + rxd->rx_dmamap = sc->sis_rx_sparemap; + sc->sis_rx_sparemap = map; + bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); + rxd->rx_m = m; + rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); + rxd->rx_desc->sis_ptr = htole32(SIS_ADDR_LO(segs[0].ds_addr)); + return (0); +} + +static __inline void +sis_discard_rxbuf(struct sis_rxdesc *rxd) { - if (c == NULL) - return(EINVAL); - - if (m == NULL) { - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); - if (m == NULL) - return(ENOBUFS); - } else - m->m_data = m->m_ext.ext_buf; - - c->sis_mbuf = m; - c->sis_ctl = SIS_RXLEN; - - bus_dmamap_create(sc->sis_tag, 0, &c->sis_map); - bus_dmamap_load(sc->sis_tag, c->sis_map, - mtod(m, void *), MCLBYTES, - sis_dma_map_desc_ptr, c, 0); - bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREREAD); - - return(0); + rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); } +#ifndef __NO_STRICT_ALIGNMENT +static __inline void +sis_fixup_rx(struct mbuf *m) +{ + uint16_t *src, *dst; + int i; + + src = mtod(m, uint16_t *); + dst = src - (SIS_RX_BUF_ALIGN - ETHER_ALIGN) / sizeof(*src); + + for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) + *dst++ = *src++; + + m->m_data -= SIS_RX_BUF_ALIGN - ETHER_ALIGN; +} +#endif + /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. @@ -1397,19 +1563,23 @@ sis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m) static int sis_rxeof(struct sis_softc *sc) { - struct mbuf *m, *m0; + struct mbuf *m; struct ifnet *ifp; + struct sis_rxdesc *rxd; struct sis_desc *cur_rx; - int total_len = 0, rx_npkts = 0; - u_int32_t rxstat; + int prog, rx_cons, rx_npkts = 0, total_len; + uint32_t rxstat; SIS_LOCK_ASSERT(sc); + bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + rx_cons = sc->sis_rx_cons; ifp = sc->sis_ifp; - for(cur_rx = sc->sis_rx_pdsc; SIS_OWNDESC(cur_rx); - cur_rx = cur_rx->sis_nextdesc) { - + for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; + SIS_INC(rx_cons, SIS_RX_LIST_CNT), prog++) { #ifdef DEVICE_POLLING if (ifp->if_capenable & IFCAP_POLLING) { if (sc->rxcycles <= 0) @@ -1417,21 +1587,13 @@ sis_rxeof(struct sis_softc *sc) sc->rxcycles--; } #endif - rxstat = cur_rx->sis_rxstat; - bus_dmamap_sync(sc->sis_tag, - cur_rx->sis_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map); - bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map); - m = cur_rx->sis_mbuf; - cur_rx->sis_mbuf = NULL; - total_len = SIS_RXBYTES(cur_rx); + cur_rx = &sc->sis_rx_list[rx_cons]; + rxstat = le32toh(cur_rx->sis_cmdsts); + if ((rxstat & SIS_CMDSTS_OWN) == 0) + break; + rxd = &sc->sis_rxdesc[rx_cons]; - /* - * If an error occurs, update stats, clear the - * status word and leave the mbuf cluster in place: - * it should simply get re-used next time this descriptor - * comes up in the ring. - */ + total_len = (rxstat & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN; if ((ifp->if_capenable & IFCAP_VLAN_MTU) != 0 && total_len <= (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN)) @@ -1440,36 +1602,29 @@ sis_rxeof(struct sis_softc *sc) ifp->if_ierrors++; if (rxstat & SIS_RXSTAT_COLL) ifp->if_collisions++; - sis_newbuf(sc, cur_rx, m); + sis_discard_rxbuf(rxd); continue; } - /* No errors; receive the packet. */ -#ifdef __NO_STRICT_ALIGNMENT + /* Add a new receive buffer to the ring. */ + m = rxd->rx_m; + if (sis_newbuf(sc, rxd) != 0) { + ifp->if_iqdrops++; + sis_discard_rxbuf(rxd); + continue; + } + + /* No errors; receive the packet. */ + m->m_pkthdr.len = m->m_len = total_len; +#ifndef __NO_STRICT_ALIGNMENT /* * On architectures without alignment problems we try to * allocate a new buffer for the receive ring, and pass up * the one where the packet is already, saving the expensive - * copy done in m_devget(). - * If we are on an architecture with alignment problems, or - * if the allocation fails, then use m_devget and leave the - * existing buffer in the receive ring. + * copy operation. */ - if (sis_newbuf(sc, cur_rx, NULL) == 0) - m->m_pkthdr.len = m->m_len = total_len; - else + sis_fixup_rx(m); #endif - { - m0 = m_devget(mtod(m, char *), total_len, - ETHER_ALIGN, ifp, NULL); - sis_newbuf(sc, cur_rx, m); - if (m0 == NULL) { - ifp->if_ierrors++; - continue; - } - m = m0; - } - ifp->if_ipackets++; m->m_pkthdr.rcvif = ifp; @@ -1479,7 +1634,12 @@ sis_rxeof(struct sis_softc *sc) rx_npkts++; } - sc->sis_rx_pdsc = cur_rx; + if (prog > 0) { + sc->sis_rx_cons = rx_cons; + bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + } + return (rx_npkts); } @@ -1492,54 +1652,54 @@ static void sis_txeof(struct sis_softc *sc) { struct ifnet *ifp; - u_int32_t idx; + struct sis_desc *cur_tx; + struct sis_txdesc *txd; + uint32_t cons, txstat; SIS_LOCK_ASSERT(sc); + + cons = sc->sis_tx_cons; + if (cons == sc->sis_tx_prod) + return; + ifp = sc->sis_ifp; + bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ - for (idx = sc->sis_tx_cons; sc->sis_tx_cnt > 0; - sc->sis_tx_cnt--, SIS_INC(idx, SIS_TX_LIST_CNT) ) { - struct sis_desc *cur_tx = &sc->sis_tx_list[idx]; - - if (SIS_OWNDESC(cur_tx)) + for (; cons != sc->sis_tx_prod; SIS_INC(cons, SIS_TX_LIST_CNT)) { + cur_tx = &sc->sis_tx_list[cons]; + txstat = le32toh(cur_tx->sis_cmdsts); + if ((txstat & SIS_CMDSTS_OWN) != 0) break; - - if (cur_tx->sis_ctl & SIS_CMDSTS_MORE) - continue; - - if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) { - ifp->if_oerrors++; - if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS) - ifp->if_collisions++; - if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL) - ifp->if_collisions++; + txd = &sc->sis_txdesc[cons]; + if (txd->tx_m != NULL) { + bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); + m_freem(txd->tx_m); + txd->tx_m = NULL; + if ((txstat & SIS_CMDSTS_PKT_OK) != 0) { + ifp->if_opackets++; + ifp->if_collisions += + (txstat & SIS_TXSTAT_COLLCNT) >> 16; + } else { + ifp->if_oerrors++; + if (txstat & SIS_TXSTAT_EXCESSCOLLS) + ifp->if_collisions++; + if (txstat & SIS_TXSTAT_OUTOFWINCOLL) + ifp->if_collisions++; + } } - - ifp->if_collisions += - (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16; - - ifp->if_opackets++; - if (cur_tx->sis_mbuf != NULL) { - m_freem(cur_tx->sis_mbuf); - cur_tx->sis_mbuf = NULL; - bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map); - bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map); - } - } - - if (idx != sc->sis_tx_cons) { - /* we freed up some buffers */ - sc->sis_tx_cons = idx; + sc->sis_tx_cnt--; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } - - sc->sis_watchdog_timer = (sc->sis_tx_cnt == 0) ? 0 : 5; - - return; + sc->sis_tx_cons = cons; + if (sc->sis_tx_cnt == 0) + sc->sis_watchdog_timer = 0; } static void @@ -1551,23 +1711,14 @@ sis_tick(void *xsc) sc = xsc; SIS_LOCK_ASSERT(sc); - sc->in_tick = 1; ifp = sc->sis_ifp; mii = device_get_softc(sc->sis_miibus); mii_tick(mii); - sis_watchdog(sc); - - if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->sis_link++; - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - sis_startl(ifp); - } - + if ((sc->sis_flags & SIS_FLAG_LINK) == 0) + sis_miibus_statchg(sc->sis_dev); callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); - sc->in_tick = 0; } #ifdef DEVICE_POLLING @@ -1599,7 +1750,7 @@ sis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) sis_startl(ifp); if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { - u_int32_t status; + uint32_t status; /* Reading the ISR register clears all interrupts. */ status = CSR_READ_4(sc, SIS_ISR); @@ -1611,7 +1762,7 @@ sis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); if (status & SIS_ISR_SYSERR) { - sis_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sis_initl(sc); } } @@ -1626,14 +1777,11 @@ sis_intr(void *arg) { struct sis_softc *sc; struct ifnet *ifp; - u_int32_t status; + uint32_t status; sc = arg; ifp = sc->sis_ifp; - if (sc->sis_stopped) /* Most likely shared interrupt */ - return; - SIS_LOCK(sc); #ifdef DEVICE_POLLING if (ifp->if_capenable & IFCAP_POLLING) { @@ -1642,20 +1790,23 @@ sis_intr(void *arg) } #endif + /* Reading the ISR register clears all interrupts. */ + status = CSR_READ_4(sc, SIS_ISR); + if ((status & SIS_INTRS) == 0) { + /* Not ours. */ + SIS_UNLOCK(sc); + return; + } + /* Disable interrupts. */ CSR_WRITE_4(sc, SIS_IER, 0); - for (;;) { - SIS_LOCK_ASSERT(sc); - /* Reading the ISR register clears all interrupts. */ - status = CSR_READ_4(sc, SIS_ISR); - - if ((status & SIS_INTRS) == 0) + for (;(status & SIS_INTRS) != 0;) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) break; - if (status & (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | - SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) + SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) sis_txeof(sc); if (status & (SIS_ISR_RX_DESC_OK | SIS_ISR_RX_OK | @@ -1669,16 +1820,21 @@ sis_intr(void *arg) SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); if (status & SIS_ISR_SYSERR) { - sis_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sis_initl(sc); + SIS_UNLOCK(sc); + return; } + status = CSR_READ_4(sc, SIS_ISR); } - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, SIS_IER, 1); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* Re-enable interrupts. */ + CSR_WRITE_4(sc, SIS_IER, 1); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - sis_startl(ifp); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + sis_startl(ifp); + } SIS_UNLOCK(sc); } @@ -1688,83 +1844,112 @@ sis_intr(void *arg) * pointers to the fragment pointers. */ static int -sis_encap(struct sis_softc *sc, struct mbuf **m_head, uint32_t *txidx) +sis_encap(struct sis_softc *sc, struct mbuf **m_head) { - struct sis_desc *f = NULL; struct mbuf *m; - int frag, cur, cnt = 0, chainlen = 0; + struct sis_txdesc *txd; + struct sis_desc *f; + bus_dma_segment_t segs[SIS_MAXTXSEGS]; + bus_dmamap_t map; + int error, i, frag, nsegs, prod; + int padlen; - /* - * If there's no way we can send any packets, return now. - */ - if (SIS_TX_LIST_CNT - sc->sis_tx_cnt < 2) - return (ENOBUFS); - - /* - * Count the number of frags in this chain to see if - * we need to m_defrag. Since the descriptor list is shared - * by all packets, we'll m_defrag long chains so that they - * do not use up the entire list, even if they would fit. - */ - - for (m = *m_head; m != NULL; m = m->m_next) - chainlen++; - - if ((chainlen > SIS_TX_LIST_CNT / 4) || - ((SIS_TX_LIST_CNT - (chainlen + sc->sis_tx_cnt)) < 2)) { - m = m_defrag(*m_head, M_DONTWAIT); - if (m == NULL) - return (ENOBUFS); + prod = sc->sis_tx_prod; + txd = &sc->sis_txdesc[prod]; + if ((sc->sis_flags & SIS_FLAG_MANUAL_PAD) != 0 && + (*m_head)->m_pkthdr.len < SIS_MIN_FRAMELEN) { + m = *m_head; + padlen = SIS_MIN_FRAMELEN - m->m_pkthdr.len; + if (M_WRITABLE(m) == 0) { + /* Get a writable copy. */ + m = m_dup(*m_head, M_DONTWAIT); + m_freem(*m_head); + if (m == NULL) { + *m_head = NULL; + return (ENOBUFS); + } + *m_head = m; + } + if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { + m = m_defrag(m, M_DONTWAIT); + if (m == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); + } + } + /* + * Manually pad short frames, and zero the pad space + * to avoid leaking data. + */ + bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); + m->m_pkthdr.len += padlen; + m->m_len = m->m_pkthdr.len; *m_head = m; } - - /* - * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. - */ - cur = frag = *txidx; - - for (m = *m_head; m != NULL; m = m->m_next) { - if (m->m_len != 0) { - if ((SIS_TX_LIST_CNT - - (sc->sis_tx_cnt + cnt)) < 2) - return(ENOBUFS); - f = &sc->sis_tx_list[frag]; - f->sis_ctl = SIS_CMDSTS_MORE | m->m_len; - bus_dmamap_create(sc->sis_tag, 0, &f->sis_map); - bus_dmamap_load(sc->sis_tag, f->sis_map, - mtod(m, void *), m->m_len, - sis_dma_map_desc_ptr, f, 0); - bus_dmamap_sync(sc->sis_tag, - f->sis_map, BUS_DMASYNC_PREREAD); - if (cnt != 0) - f->sis_ctl |= SIS_CMDSTS_OWN; - cur = frag; - SIS_INC(frag, SIS_TX_LIST_CNT); - cnt++; + error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, + *m_head, segs, &nsegs, 0); + if (error == EFBIG) { + m = m_collapse(*m_head, M_DONTWAIT, SIS_MAXTXSEGS); + if (m == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); } + *m_head = m; + error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, + *m_head, segs, &nsegs, 0); + if (error != 0) { + m_freem(*m_head); + *m_head = NULL; + return (error); + } + } else if (error != 0) + return (error); + + /* Check for descriptor overruns. */ + if (sc->sis_tx_cnt + nsegs > SIS_TX_LIST_CNT - 1) { + bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); + return (ENOBUFS); } - if (m != NULL) - return(ENOBUFS); + bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); - sc->sis_tx_list[cur].sis_mbuf = *m_head; - sc->sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE; - sc->sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN; - sc->sis_tx_cnt += cnt; - *txidx = frag; + frag = prod; + for (i = 0; i < nsegs; i++) { + f = &sc->sis_tx_list[prod]; + if (i == 0) + f->sis_cmdsts = htole32(segs[i].ds_len | + SIS_CMDSTS_MORE); + else + f->sis_cmdsts = htole32(segs[i].ds_len | + SIS_CMDSTS_OWN | SIS_CMDSTS_MORE); + f->sis_ptr = htole32(SIS_ADDR_LO(segs[i].ds_addr)); + SIS_INC(prod, SIS_TX_LIST_CNT); + sc->sis_tx_cnt++; + } - return(0); + /* Update producer index. */ + sc->sis_tx_prod = prod; + + /* Remove MORE flag on the last descriptor. */ + prod = (prod - 1) & (SIS_TX_LIST_CNT - 1); + f = &sc->sis_tx_list[prod]; + f->sis_cmdsts &= ~htole32(SIS_CMDSTS_MORE); + + /* Lastly transfer ownership of packet to the controller. */ + f = &sc->sis_tx_list[frag]; + f->sis_cmdsts |= htole32(SIS_CMDSTS_OWN); + + /* Swap the last and the first dmamaps. */ + map = txd->tx_dmamap; + txd->tx_dmamap = sc->sis_txdesc[prod].tx_dmamap; + sc->sis_txdesc[prod].tx_dmamap = map; + sc->sis_txdesc[prod].tx_m = *m_head; + + return (0); } -/* - * Main transmit routine. To avoid having to do mbuf copies, we put pointers - * to the mbuf data regions directly in the transmit lists. We also save a - * copy of the pointers since the transmit list fragment pointers are - * physical addresses. - */ - static void sis_start(struct ifnet *ifp) { @@ -1780,27 +1965,26 @@ static void sis_startl(struct ifnet *ifp) { struct sis_softc *sc; - struct mbuf *m_head = NULL; - u_int32_t idx, queued = 0; + struct mbuf *m_head; + int queued; sc = ifp->if_softc; SIS_LOCK_ASSERT(sc); - if (!sc->sis_link) + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || (sc->sis_flags & SIS_FLAG_LINK) == 0) return; - idx = sc->sis_tx_prod; - - if (ifp->if_drv_flags & IFF_DRV_OACTIVE) - return; - - while(sc->sis_tx_list[idx].sis_mbuf == NULL) { + for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && + sc->sis_tx_cnt < SIS_TX_LIST_CNT - 4;) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; - if (sis_encap(sc, &m_head, &idx)) { + if (sis_encap(sc, &m_head) != 0) { + if (m_head == NULL) + break; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; @@ -1813,12 +1997,12 @@ sis_startl(struct ifnet *ifp) * to him. */ BPF_MTAP(ifp, m_head); - } if (queued) { /* Transmit */ - sc->sis_tx_prod = idx; + bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); /* @@ -1843,15 +2027,21 @@ sis_initl(struct sis_softc *sc) { struct ifnet *ifp = sc->sis_ifp; struct mii_data *mii; + uint8_t *eaddr; SIS_LOCK_ASSERT(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + /* * Cancel pending I/O and free all RX/TX buffers. */ sis_stop(sc); - sc->sis_stopped = 0; - + /* + * Reset the chip to a known state. + */ + sis_reset(sc); #ifdef notyet if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { /* @@ -1865,26 +2055,21 @@ sis_initl(struct sis_softc *sc) mii = device_get_softc(sc->sis_miibus); /* Set MAC address */ + eaddr = IF_LLADDR(sc->sis_ifp); if (sc->sis_type == SIS_TYPE_83815) { CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[0]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[1]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[2]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); } else { CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[0]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[1]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, - ((u_int16_t *)IF_LLADDR(sc->sis_ifp))[2]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); } /* Init circular TX/RX lists. */ @@ -1895,6 +2080,13 @@ sis_initl(struct sis_softc *sc) return; } + if (sc->sis_type == SIS_TYPE_83815 || sc->sis_type == SIS_TYPE_83816) { + if (sc->sis_manual_pad != 0) + sc->sis_flags |= SIS_FLAG_MANUAL_PAD; + else + sc->sis_flags &= ~SIS_FLAG_MANUAL_PAD; + } + /* * Short Cable Receive Errors (MP21.E) * also: Page 78 of the DP83815 data sheet (september 2002 version) @@ -1914,7 +2106,6 @@ sis_initl(struct sis_softc *sc) CSR_WRITE_4(sc, NS_PHY_PAGE, 0); } - /* * For the NatSemi chip, we have to explicitly enable the * reception of ARP frames, as well as turn on the 'perfect @@ -1956,8 +2147,8 @@ sis_initl(struct sis_softc *sc) /* * Load the address of the RX and TX lists. */ - CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_rx_paddr); - CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_tx_paddr); + CSR_WRITE_4(sc, SIS_RX_LISTPTR, SIS_ADDR_LO(sc->sis_rx_paddr)); + CSR_WRITE_4(sc, SIS_TX_LISTPTR, SIS_ADDR_LO(sc->sis_tx_paddr)); /* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of * the PCI bus. When this bit is set, the Max DMA Burst Size @@ -1972,52 +2163,11 @@ sis_initl(struct sis_softc *sc) /* Accept Long Packets for VLAN support */ SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); - /* Set TX configuration */ - if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { - CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); - } else { - CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); - } - - /* Set full/half duplex mode. */ - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { - SIS_SETBIT(sc, SIS_TX_CFG, - (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); - SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); - } else { - SIS_CLRBIT(sc, SIS_TX_CFG, - (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); - SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); - } - - if (sc->sis_type == SIS_TYPE_83816) { - /* - * MPII03.D: Half Duplex Excessive Collisions. - * Also page 49 in 83816 manual - */ - SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D); - } - - if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A && - IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { - uint32_t reg; - - /* - * Short Cable Receive Errors (MP21.E) - */ - CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); - reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff; - CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000); - DELAY(100); - reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff; - if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) { - device_printf(sc->sis_dev, - "Applying short cable fix (reg=%x)\n", reg); - CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8); - SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20); - } - CSR_WRITE_4(sc, NS_PHY_PAGE, 0); - } + /* + * Assume 100Mbps link, actual MAC configuration is done + * after getting a valid link. + */ + CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); /* * Enable interrupts. @@ -2034,19 +2184,16 @@ sis_initl(struct sis_softc *sc) #endif CSR_WRITE_4(sc, SIS_IER, 1); - /* Enable receiver and transmitter. */ - SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); - SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); + /* Clear MAC disable. */ + SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); -#ifdef notdef + sc->sis_flags &= ~SIS_FLAG_LINK; mii_mediachg(mii); -#endif ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - if (!sc->in_tick) - callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); + callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); } /* @@ -2057,21 +2204,21 @@ sis_ifmedia_upd(struct ifnet *ifp) { struct sis_softc *sc; struct mii_data *mii; + int error; sc = ifp->if_softc; SIS_LOCK(sc); mii = device_get_softc(sc->sis_miibus); - sc->sis_link = 0; if (mii->mii_instance) { struct mii_softc *miisc; LIST_FOREACH(miisc, &mii->mii_phys, mii_list) mii_phy_reset(miisc); } - mii_mediachg(mii); + error = mii_mediachg(mii); SIS_UNLOCK(sc); - return(0); + return (error); } /* @@ -2099,16 +2246,25 @@ sis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) struct sis_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct mii_data *mii; - int error = 0; + int error = 0, mask; - switch(command) { + switch (command) { case SIOCSIFFLAGS: SIS_LOCK(sc); if (ifp->if_flags & IFF_UP) { - sis_initl(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && + ((ifp->if_flags ^ sc->sis_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) != 0) { + if (sc->sis_type == SIS_TYPE_83815) + sis_setmulti_ns(sc); + else + sis_setmulti_sis(sc); + } else + sis_initl(sc); } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { sis_stop(sc); } + sc->sis_if_flags = ifp->if_flags; SIS_UNLOCK(sc); error = 0; break; @@ -2120,7 +2276,6 @@ sis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) else sis_setmulti_sis(sc); SIS_UNLOCK(sc); - error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -2128,39 +2283,44 @@ sis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: - /* ok, disable interrupts */ + SIS_LOCK(sc); + mask = ifr->ifr_reqcap ^ ifp->if_capenable; #ifdef DEVICE_POLLING - if (ifr->ifr_reqcap & IFCAP_POLLING && - !(ifp->if_capenable & IFCAP_POLLING)) { - error = ether_poll_register(sis_poll, ifp); - if (error) - return(error); - SIS_LOCK(sc); - /* Disable interrupts */ - CSR_WRITE_4(sc, SIS_IER, 0); - ifp->if_capenable |= IFCAP_POLLING; - SIS_UNLOCK(sc); - return (error); - - } - if (!(ifr->ifr_reqcap & IFCAP_POLLING) && - ifp->if_capenable & IFCAP_POLLING) { - error = ether_poll_deregister(ifp); - /* Enable interrupts. */ - SIS_LOCK(sc); - CSR_WRITE_4(sc, SIS_IER, 1); - ifp->if_capenable &= ~IFCAP_POLLING; - SIS_UNLOCK(sc); - return (error); + if ((mask & IFCAP_POLLING) != 0 && + (IFCAP_POLLING & ifp->if_capabilities) != 0) { + ifp->if_capenable ^= IFCAP_POLLING; + if ((IFCAP_POLLING & ifp->if_capenable) != 0) { + error = ether_poll_register(sis_poll, ifp); + if (error != 0) { + SIS_UNLOCK(sc); + break; + } + /* Disable interrupts. */ + CSR_WRITE_4(sc, SIS_IER, 0); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + CSR_WRITE_4(sc, SIS_IER, 1); + } } #endif /* DEVICE_POLLING */ + if ((mask & IFCAP_WOL) != 0 && + (ifp->if_capabilities & IFCAP_WOL) != 0) { + if ((mask & IFCAP_WOL_UCAST) != 0) + ifp->if_capenable ^= IFCAP_WOL_UCAST; + if ((mask & IFCAP_WOL_MCAST) != 0) + ifp->if_capenable ^= IFCAP_WOL_MCAST; + if ((mask & IFCAP_WOL_MAGIC) != 0) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; + } + SIS_UNLOCK(sc); break; default: error = ether_ioctl(ifp, command, data); break; } - return(error); + return (error); } static void @@ -2168,10 +2328,6 @@ sis_watchdog(struct sis_softc *sc) { SIS_LOCK_ASSERT(sc); - if (sc->sis_stopped) { - SIS_UNLOCK(sc); - return; - } if (sc->sis_watchdog_timer == 0 || --sc->sis_watchdog_timer >0) return; @@ -2179,8 +2335,7 @@ sis_watchdog(struct sis_softc *sc) device_printf(sc->sis_dev, "watchdog timeout\n"); sc->sis_ifp->if_oerrors++; - sis_stop(sc); - sis_reset(sc); + sc->sis_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; sis_initl(sc); if (!IFQ_DRV_IS_EMPTY(&sc->sis_ifp->if_snd)) @@ -2194,13 +2349,13 @@ sis_watchdog(struct sis_softc *sc) static void sis_stop(struct sis_softc *sc) { - int i; struct ifnet *ifp; - struct sis_desc *dp; + struct sis_rxdesc *rxd; + struct sis_txdesc *txd; + int i; - if (sc->sis_stopped) - return; SIS_LOCK_ASSERT(sc); + ifp = sc->sis_ifp; sc->sis_watchdog_timer = 0; @@ -2215,38 +2370,35 @@ sis_stop(struct sis_softc *sc) CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); - sc->sis_link = 0; + sc->sis_flags &= ~SIS_FLAG_LINK; /* * Free data in the RX lists. */ - dp = &sc->sis_rx_list[0]; - for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) { - if (dp->sis_mbuf == NULL) - continue; - bus_dmamap_unload(sc->sis_tag, dp->sis_map); - bus_dmamap_destroy(sc->sis_tag, dp->sis_map); - m_freem(dp->sis_mbuf); - dp->sis_mbuf = NULL; + for (i = 0; i < SIS_RX_LIST_CNT; i++) { + rxd = &sc->sis_rxdesc[i]; + if (rxd->rx_m != NULL) { + bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); + m_freem(rxd->rx_m); + rxd->rx_m = NULL; + } } - bzero(sc->sis_rx_list, SIS_RX_LIST_SZ); /* * Free the TX list buffers. */ - dp = &sc->sis_tx_list[0]; - for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) { - if (dp->sis_mbuf == NULL) - continue; - bus_dmamap_unload(sc->sis_tag, dp->sis_map); - bus_dmamap_destroy(sc->sis_tag, dp->sis_map); - m_freem(dp->sis_mbuf); - dp->sis_mbuf = NULL; + for (i = 0; i < SIS_TX_LIST_CNT; i++) { + txd = &sc->sis_txdesc[i]; + if (txd->tx_m != NULL) { + bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); + m_freem(txd->tx_m); + txd->tx_m = NULL; + } } - - bzero(sc->sis_tx_list, SIS_TX_LIST_SZ); - - sc->sis_stopped = 1; } /* @@ -2255,23 +2407,125 @@ sis_stop(struct sis_softc *sc) */ static int sis_shutdown(device_t dev) +{ + + return (sis_suspend(dev)); +} + +static int +sis_suspend(device_t dev) { struct sis_softc *sc; sc = device_get_softc(dev); SIS_LOCK(sc); - sis_reset(sc); sis_stop(sc); + sis_wol(sc); SIS_UNLOCK(sc); return (0); } +static int +sis_resume(device_t dev) +{ + struct sis_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + SIS_LOCK(sc); + ifp = sc->sis_ifp; + if ((ifp->if_flags & IFF_UP) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + sis_initl(sc); + } + SIS_UNLOCK(sc); + return (0); +} + +static void +sis_wol(struct sis_softc *sc) +{ + struct ifnet *ifp; + uint32_t val; + uint16_t pmstat; + int pmc; + + ifp = sc->sis_ifp; + if ((ifp->if_capenable & IFCAP_WOL) == 0) + return; + + if (sc->sis_type == SIS_TYPE_83815) { + /* Reset RXDP. */ + CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); + + /* Configure WOL events. */ + CSR_READ_4(sc, NS_WCSR); + val = 0; + if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0) + val |= NS_WCSR_WAKE_UCAST; + if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) + val |= NS_WCSR_WAKE_MCAST; + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + val |= NS_WCSR_WAKE_MAGIC; + CSR_WRITE_4(sc, NS_WCSR, val); + /* Enable PME and clear PMESTS. */ + val = CSR_READ_4(sc, NS_CLKRUN); + val |= NS_CLKRUN_PMEENB | NS_CLKRUN_PMESTS; + CSR_WRITE_4(sc, NS_CLKRUN, val); + /* Enable silent RX mode. */ + SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); + } else { + if (pci_find_extcap(sc->sis_dev, PCIY_PMG, &pmc) != 0) + return; + val = 0; + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + val |= SIS_PWRMAN_WOL_MAGIC; + CSR_WRITE_4(sc, SIS_PWRMAN_CTL, val); + /* Request PME. */ + pmstat = pci_read_config(sc->sis_dev, + pmc + PCIR_POWER_STATUS, 2); + pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; + pci_write_config(sc->sis_dev, + pmc + PCIR_POWER_STATUS, pmstat, 2); + } +} + +static void +sis_add_sysctls(struct sis_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + char tn[32]; + int unit; + + ctx = device_get_sysctl_ctx(sc->sis_dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sis_dev)); + + unit = device_get_unit(sc->sis_dev); + /* + * Unlike most other controllers, NS DP83815/DP83816 controllers + * seem to pad with 0xFF when it encounter short frames. According + * to RFC 1042 the pad bytes should be 0x00. Turning this tunable + * on will have driver pad manully but it's disabled by default + * because it will consume extra CPU cycles for short frames. + */ + sc->sis_manual_pad = 0; + snprintf(tn, sizeof(tn), "dev.sis.%d.manual_pad", unit); + TUNABLE_INT_FETCH(tn, &sc->sis_manual_pad); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, "manual_pad", + CTLFLAG_RW, &sc->sis_manual_pad, 0, "Manually pad short frames"); +} + static device_method_t sis_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sis_probe), DEVMETHOD(device_attach, sis_attach), DEVMETHOD(device_detach, sis_detach), DEVMETHOD(device_shutdown, sis_shutdown), + DEVMETHOD(device_suspend, sis_suspend), + DEVMETHOD(device_resume, sis_resume), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), diff --git a/sys/dev/sis/if_sisreg.h b/sys/dev/sis/if_sisreg.h index 927bd58f760..28d43901a23 100644 --- a/sys/dev/sis/if_sisreg.h +++ b/sys/dev/sis/if_sisreg.h @@ -77,6 +77,7 @@ /* NS DP83815/6 registers */ #define NS_IHR 0x1C #define NS_CLKRUN 0x3C +#define NS_WCSR 0x40 #define NS_SRR 0x58 #define NS_BMCR 0x80 #define NS_BMSR 0x84 @@ -99,6 +100,29 @@ #define NS_CLKRUN_PMEENB 0x00000100 #define NS_CLNRUN_CLKRUN_ENB 0x00000001 +#define NS_WCSR_WAKE_PHYINTR 0x00000001 +#define NS_WCSR_WAKE_UCAST 0x00000002 +#define NS_WCSR_WAKE_MCAST 0x00000004 +#define NS_WCSR_WAKE_BCAST 0x00000008 +#define NS_WCSR_WAKE_ARP 0x00000010 +#define NS_WCSR_WAKE_PATTERN0 0x00000020 +#define NS_WCSR_WAKE_PATTERN1 0x00000040 +#define NS_WCSR_WAKE_PATTERN2 0x00000080 +#define NS_WCSR_WAKE_PATTERN3 0x00000100 +#define NS_WCSR_WAKE_MAGIC 0x00000200 +#define NS_WCSR_WAKE_MAGIC_SEC 0x00000400 +#define NS_WCSR_DET_MAGIC_SECH 0x00100000 +#define NS_WCSR_DET_PHYINTR 0x00400000 +#define NS_WCSR_DET_UCAST 0x00800000 +#define NS_WCSR_DET_MCAST 0x01000000 +#define NS_WCSR_DET_BCAST 0x02000000 +#define NS_WCSR_DET_ARP 0x04000000 +#define NS_WCSR_DET_PATTERN0 0x08000000 +#define NS_WCSR_DET_PATTERN1 0x10000000 +#define NS_WCSR_DET_PATTERN2 0x20000000 +#define NS_WCSR_DET_PATTERN3 0x40000000 +#define NS_WCSR_DET_MAGIC 0x80000000 + /* NS silicon revisions */ #define NS_SRR_15C 0x302 #define NS_SRR_15D 0x403 @@ -252,7 +276,7 @@ SIS_TXCFG_FILL(64)|SIS_TXCFG_DRAIN(1536)) #define SIS_RXCFG_DRAIN_THRESH 0x0000003E /* 8-byte units */ -#define SIS_TXCFG_MPII03D 0x00040000 /* "Must be 1" */ +#define SIS_TXCFG_MPII03D 0x00040000 /* "Must be 1" */ #define SIS_RXCFG_DMABURST 0x00700000 #define SIS_RXCFG_RX_JABBER 0x08000000 #define SIS_RXCFG_RX_TXPKTS 0x10000000 @@ -303,26 +327,18 @@ #define NS_FILTADDR_FMEM_LO 0x00000200 #define NS_FILTADDR_FMEM_HI 0x000003FE +#define SIS_PWRMAN_WOL_LINK_OFF 0x00000001 +#define SIS_PWRMAN_WOL_LINK_ON 0x00000002 +#define SIS_PWRMAN_WOL_MAGIC 0x00000400 + /* - * DMA descriptor structures. The first part of the descriptor - * is the hardware descriptor format, which is just three longwords. - * After this, we include some additional structure members for - * use by the driver. Note that for this structure will be a different - * size on the alpha, but that's okay as long as it's a multiple of 4 - * bytes in size. + * TX/RX DMA descriptor structures. */ struct sis_desc { /* SiS hardware descriptor section */ - u_int32_t sis_next; - u_int32_t sis_cmdsts; -#define sis_rxstat sis_cmdsts -#define sis_txstat sis_cmdsts -#define sis_ctl sis_cmdsts - u_int32_t sis_ptr; - /* Driver software section */ - struct mbuf *sis_mbuf; - struct sis_desc *sis_nextdesc; - bus_dmamap_t sis_map; + uint32_t sis_next; + uint32_t sis_cmdsts; + uint32_t sis_ptr; }; #define SIS_CMDSTS_BUFLEN 0x00000FFF @@ -332,11 +348,6 @@ struct sis_desc { #define SIS_CMDSTS_MORE 0x40000000 #define SIS_CMDSTS_OWN 0x80000000 -#define SIS_LASTDESC(x) (!((x)->sis_ctl & SIS_CMDSTS_MORE)) -#define SIS_OWNDESC(x) ((x)->sis_ctl & SIS_CMDSTS_OWN) -#define SIS_INC(x, y) (x) = ((x) == ((y)-1)) ? 0 : (x)+1 -#define SIS_RXBYTES(x) (((x)->sis_ctl & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN) - #define SIS_RXSTAT_COLL 0x00010000 #define SIS_RXSTAT_LOOPBK 0x00020000 #define SIS_RXSTAT_ALIGNERR 0x00040000 @@ -367,12 +378,25 @@ struct sis_desc { #define SIS_TXSTAT_UNDERRUN 0x02000000 #define SIS_TXSTAT_TX_ABORT 0x04000000 +#define SIS_DESC_ALIGN 16 +#define SIS_RX_BUF_ALIGN 4 +#define SIS_MAXTXSEGS 16 #define SIS_RX_LIST_CNT 64 #define SIS_TX_LIST_CNT 128 #define SIS_RX_LIST_SZ SIS_RX_LIST_CNT * sizeof(struct sis_desc) #define SIS_TX_LIST_SZ SIS_TX_LIST_CNT * sizeof(struct sis_desc) +#define SIS_ADDR_LO(x) ((uint64_t) (x) & 0xffffffff) +#define SIS_ADDR_HI(x) ((uint64_t) (x) >> 32) + +#define SIS_RX_RING_ADDR(sc, i) \ + ((sc)->sis_rx_paddr + sizeof(struct sis_desc) * (i)) +#define SIS_TX_RING_ADDR(sc, i) \ + ((sc)->sis_tx_paddr + sizeof(struct sis_desc) * (i)) + +#define SIS_INC(x, y) (x) = (x + 1) % (y) + /* * SiS PCI vendor ID. */ @@ -407,18 +431,18 @@ struct sis_desc { #define NS_DEVICEID_DP83815 0x0020 struct sis_type { - u_int16_t sis_vid; - u_int16_t sis_did; + uint16_t sis_vid; + uint16_t sis_did; char *sis_name; }; struct sis_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; + uint8_t mii_stdelim; + uint8_t mii_opcode; + uint8_t mii_phyaddr; + uint8_t mii_regaddr; + uint8_t mii_turnaround; + uint16_t mii_data; }; /* @@ -434,37 +458,54 @@ struct sis_mii_frame { #define SIS_TYPE_83815 3 #define SIS_TYPE_83816 4 +struct sis_txdesc { + struct mbuf *tx_m; + bus_dmamap_t tx_dmamap; +}; + +struct sis_rxdesc { + struct mbuf *rx_m; + bus_dmamap_t rx_dmamap; + struct sis_desc *rx_desc; +}; + struct sis_softc { struct ifnet *sis_ifp; /* interface info */ struct resource *sis_res[2]; void *sis_intrhand; device_t sis_dev; device_t sis_miibus; - u_int8_t sis_type; - u_int8_t sis_rev; - u_int8_t sis_link; - u_int sis_srr; + uint8_t sis_type; + uint8_t sis_rev; + uint32_t sis_flags; +#define SIS_FLAG_MANUAL_PAD 0x0800 +#define SIS_FLAG_LINK 0x8000 + int sis_manual_pad; + uint32_t sis_srr; struct sis_desc *sis_rx_list; struct sis_desc *sis_tx_list; - bus_dma_tag_t sis_rx_tag; - bus_dmamap_t sis_rx_dmamap; - bus_dma_tag_t sis_tx_tag; - bus_dmamap_t sis_tx_dmamap; + bus_dma_tag_t sis_rx_list_tag; + bus_dmamap_t sis_rx_list_map; + bus_dma_tag_t sis_tx_list_tag; + bus_dmamap_t sis_tx_list_map; bus_dma_tag_t sis_parent_tag; - bus_dma_tag_t sis_tag; - struct sis_desc *sis_rx_pdsc; + bus_dma_tag_t sis_rx_tag; + bus_dmamap_t sis_rx_sparemap; + bus_dma_tag_t sis_tx_tag; + struct sis_rxdesc sis_rxdesc[SIS_RX_LIST_CNT]; + struct sis_txdesc sis_txdesc[SIS_TX_LIST_CNT]; int sis_tx_prod; int sis_tx_cons; int sis_tx_cnt; - u_int32_t sis_rx_paddr; - u_int32_t sis_tx_paddr; + int sis_rx_cons;; + bus_addr_t sis_rx_paddr; + bus_addr_t sis_tx_paddr; struct callout sis_stat_ch; int sis_watchdog_timer; - int sis_stopped; + int sis_if_flags; #ifdef DEVICE_POLLING int rxcycles; #endif - int in_tick; struct mtx sis_mtx; }; diff --git a/sys/dev/sk/if_sk.c b/sys/dev/sk/if_sk.c index c8cd9564dc5..5a8c959e3bd 100644 --- a/sys/dev/sk/if_sk.c +++ b/sys/dev/sk/if_sk.c @@ -545,9 +545,6 @@ sk_xmac_miibus_readreg(sc_if, phy, reg) { int i; - if (sc_if->sk_phytype == SK_PHYTYPE_XMAC && phy != 0) - return(0); - SK_XM_WRITE_2(sc_if, XM_PHY_ADDR, reg|(phy << 8)); SK_XM_READ_2(sc_if, XM_PHY_DATA); if (sc_if->sk_phytype != SK_PHYTYPE_XMAC) { @@ -628,9 +625,8 @@ sk_marv_miibus_readreg(sc_if, phy, reg) u_int16_t val; int i; - if (phy != 0 || - (sc_if->sk_phytype != SK_PHYTYPE_MARV_COPPER && - sc_if->sk_phytype != SK_PHYTYPE_MARV_FIBER)) { + if (sc_if->sk_phytype != SK_PHYTYPE_MARV_COPPER && + sc_if->sk_phytype != SK_PHYTYPE_MARV_FIBER) { return(0); } @@ -1323,7 +1319,7 @@ sk_attach(dev) struct sk_softc *sc; struct sk_if_softc *sc_if; struct ifnet *ifp; - int i, port, error; + int error, i, phy, port; u_char eaddr[6]; if (dev == NULL) @@ -1496,23 +1492,27 @@ sk_attach(dev) /* * Do miibus setup. */ + phy = MII_PHY_ANY; switch (sc->sk_type) { case SK_GENESIS: sk_init_xmac(sc_if); + if (sc_if->sk_phytype == SK_PHYTYPE_XMAC) + phy = 0; break; case SK_YUKON: case SK_YUKON_LITE: case SK_YUKON_LP: sk_init_yukon(sc_if); + phy = 0; break; } SK_IF_UNLOCK(sc_if); - if (mii_phy_probe(dev, &sc_if->sk_miibus, - sk_ifmedia_upd, sk_ifmedia_sts)) { - device_printf(sc_if->sk_if_dev, "no PHY found!\n"); + error = mii_attach(dev, &sc_if->sk_miibus, ifp, sk_ifmedia_upd, + sk_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(sc_if->sk_if_dev, "attaching PHYs failed\n"); ether_ifdetach(ifp); - error = ENXIO; goto fail; } diff --git a/sys/dev/smc/if_smc.c b/sys/dev/smc/if_smc.c index 6d9ba592679..22f8bab9e82 100644 --- a/sys/dev/smc/if_smc.c +++ b/sys/dev/smc/if_smc.c @@ -324,8 +324,9 @@ smc_attach(device_t dev) callout_init_mtx(&sc->smc_mii_tick_ch, &sc->smc_mtx, CALLOUT_RETURNUNLOCKED); if (sc->smc_chip >= REV_CHIP_91110FD) { - mii_phy_probe(dev, &sc->smc_miibus, smc_mii_ifmedia_upd, - smc_mii_ifmedia_sts); + (void)mii_attach(dev, &sc->smc_miibus, ifp, + smc_mii_ifmedia_upd, smc_mii_ifmedia_sts, BMSR_DEFCAPMASK, + MII_PHY_ANY, MII_OFFSET_ANY, 0); if (sc->smc_miibus != NULL) { sc->smc_mii_tick = smc_mii_tick; sc->smc_mii_mediachg = smc_mii_mediachg; diff --git a/sys/dev/sound/pci/envy24ht.c b/sys/dev/sound/pci/envy24ht.c index 7c1874b63d4..0358625115c 100644 --- a/sys/dev/sound/pci/envy24ht.c +++ b/sys/dev/sound/pci/envy24ht.c @@ -2236,7 +2236,8 @@ envy24ht_putcfg(struct sc_info *sc) else printf("not implemented\n"); switch (sc->adcn) { - case 0x01 || 0x02: + case 0x01: + case 0x02: printf(" ADC #: "); printf("%d\n", sc->adcn); break; diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c index a0b1dc7d6c7..2175f371a2a 100644 --- a/sys/dev/sound/pci/hda/hdac.c +++ b/sys/dev/sound/pci/hda/hdac.c @@ -140,6 +140,7 @@ SND_DECLARE_FILE("$FreeBSD$"); /* Intel */ #define INTEL_VENDORID 0x8086 +#define HDA_INTEL_CPT HDA_MODEL_CONSTRUCT(INTEL, 0x1c20) #define HDA_INTEL_82801F HDA_MODEL_CONSTRUCT(INTEL, 0x2668) #define HDA_INTEL_63XXESB HDA_MODEL_CONSTRUCT(INTEL, 0x269a) #define HDA_INTEL_82801G HDA_MODEL_CONSTRUCT(INTEL, 0x27d8) @@ -486,6 +487,7 @@ static const struct { char *desc; char flags; } hdac_devices[] = { + { HDA_INTEL_CPT, "Intel Cougar Point", 0 }, { HDA_INTEL_82801F, "Intel 82801F", 0 }, { HDA_INTEL_63XXESB, "Intel 631x/632xESB", 0 }, { HDA_INTEL_82801G, "Intel 82801G", 0 }, diff --git a/sys/dev/sound/pci/spicds.c b/sys/dev/sound/pci/spicds.c index 78d9374b8fe..3a4002c81b3 100644 --- a/sys/dev/sound/pci/spicds.c +++ b/sys/dev/sound/pci/spicds.c @@ -283,7 +283,8 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r case SPICDS_TYPE_WM8770: left = left + 27; break; - case SPICDS_TYPE_AK4381 || SPICDS_TYPE_AK4396: + case SPICDS_TYPE_AK4381: + case SPICDS_TYPE_AK4396: left = left * 255 / 100; break; default: diff --git a/sys/dev/spibus/spibus.c b/sys/dev/spibus/spibus.c index a0c0380398d..9491734eedd 100644 --- a/sys/dev/spibus/spibus.c +++ b/sys/dev/spibus/spibus.c @@ -127,7 +127,7 @@ spibus_read_ivar(device_t bus, device_t child, int which, u_int *result) } static device_t -spibus_add_child(device_t dev, int order, const char *name, int unit) +spibus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct spibus_ivar *devi; diff --git a/sys/dev/ste/if_ste.c b/sys/dev/ste/if_ste.c index e3297e6d573..f616e50b854 100644 --- a/sys/dev/ste/if_ste.c +++ b/sys/dev/ste/if_ste.c @@ -369,10 +369,6 @@ ste_miibus_readreg(device_t dev, int phy, int reg) struct ste_mii_frame frame; sc = device_get_softc(dev); - - if ((sc->ste_flags & STE_FLAG_ONE_PHY) != 0 && phy != 0) - return (0); - bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; @@ -1059,7 +1055,7 @@ ste_attach(device_t dev) struct ste_softc *sc; struct ifnet *ifp; uint16_t eaddr[ETHER_ADDR_LEN / 2]; - int error = 0, pmc, prefer_iomap, rid; + int error = 0, phy, pmc, prefer_iomap, rid; sc = device_get_softc(dev); sc->ste_dev = dev; @@ -1148,10 +1144,13 @@ ste_attach(device_t dev) } /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->ste_miibus, - ste_ifmedia_upd, ste_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + phy = MII_PHY_ANY; + if ((sc->ste_flags & STE_FLAG_ONE_PHY) != 0) + phy = 0; + error = mii_attach(dev, &sc->ste_miibus, ifp, ste_ifmedia_upd, + ste_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/stge/if_stge.c b/sys/dev/stge/if_stge.c index e28981482b6..9e857719402 100644 --- a/sys/dev/stge/if_stge.c +++ b/sys/dev/stge/if_stge.c @@ -576,7 +576,7 @@ stge_attach(device_t dev) struct stge_softc *sc; struct ifnet *ifp; uint8_t enaddr[ETHER_ADDR_LEN]; - int error, i; + int error, flags, i; uint16_t cmd; uint32_t val; @@ -738,9 +738,14 @@ stge_attach(device_t dev) (PC_PhyDuplexPolarity | PC_PhyLnkPolarity); /* Set up MII bus. */ - if ((error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus, stge_mediachange, - stge_mediastatus)) != 0) { - device_printf(sc->sc_dev, "no PHY found!\n"); + flags = 0; + if (sc->sc_rev >= 0x40 && sc->sc_rev <= 0x4e) + flags |= MIIF_MACPRIV0; + error = mii_attach(sc->sc_dev, &sc->sc_miibus, ifp, stge_mediachange, + stge_mediastatus, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + flags); + if (error != 0) { + device_printf(sc->sc_dev, "attaching PHYs failed\n"); goto fail; } @@ -1377,6 +1382,7 @@ stge_watchdog(struct stge_softc *sc) ifp = sc->sc_ifp; if_printf(sc->sc_ifp, "device timeout\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; stge_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) stge_start_locked(ifp); @@ -1405,7 +1411,10 @@ stge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) else if (ifp->if_mtu != ifr->ifr_mtu) { ifp->if_mtu = ifr->ifr_mtu; STGE_LOCK(sc); - stge_init_locked(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + stge_init_locked(sc); + } STGE_UNLOCK(sc); } break; @@ -1639,8 +1648,10 @@ stge_intr(void *arg) } force_init: - if (reinit != 0) + if (reinit != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; stge_init_locked(sc); + } /* Re-enable interrupts. */ CSR_WRITE_2(sc, STGE_IntEnable, sc->sc_IntEnable); @@ -1936,11 +1947,14 @@ stge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) if ((status & IS_HostError) != 0) { device_printf(sc->sc_dev, "Host interface error, resetting...\n"); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; stge_init_locked(sc); } if ((status & IS_TxComplete) != 0) { - if (stge_tx_error(sc) != 0) + if (stge_tx_error(sc) != 0) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; stge_init_locked(sc); + } } } @@ -2121,6 +2135,8 @@ stge_init_locked(struct stge_softc *sc) STGE_LOCK_ASSERT(sc); ifp = sc->sc_ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; mii = device_get_softc(sc->sc_miibus); /* diff --git a/sys/dev/syscons/scvgarndr.c b/sys/dev/syscons/scvgarndr.c index 355d436c87a..6e6663c27fc 100644 --- a/sys/dev/syscons/scvgarndr.c +++ b/sys/dev/syscons/scvgarndr.c @@ -716,8 +716,7 @@ vga_egadraw(scr_stat *scp, int from, int count, int flip) } ++d; if ((i % scp->xsize) == scp->xsize - 1) - d += scp->xoff*2 - + (scp->font_size - 1)*line_width; + d += scp->font_size * line_width - scp->xsize; } outw(GDCIDX, 0x0000); /* set/reset */ outw(GDCIDX, 0x0001); /* set/reset enable */ @@ -769,9 +768,8 @@ vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) d += 8 * pixel_size; if ((i % scp->xsize) == scp->xsize - 1) - d += scp->xoff * scp->font_size * pixel_size + - scp->font_size * line_width - - scp->xpixel * pixel_size; + d += scp->font_size * line_width - + scp->xsize * 8 * pixel_size; } } @@ -827,8 +825,7 @@ vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) } ++d; if ((i % scp->xsize) == scp->xsize - 1) - d += scp->xoff*2 - + (scp->font_size - 1)*line_width; + d += scp->font_size * line_width - scp->xsize; } outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ outw(GDCIDX, 0x0000); /* set/reset */ diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index 4bf5e158b52..2f41f3a0f58 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -475,7 +475,7 @@ sc_attach_unit(int unit, int flags) scrn_timer(sc); /* set up the keyboard */ - kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); + (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); update_kbd_state(scp, scp->status, LOCK_MASK); printf("%s%d: %s <%d virtual consoles, flags=0x%x>\n", @@ -584,7 +584,7 @@ sctty_open(struct tty *tp) #ifndef __sparc64__ if (sc->kbd != NULL) { key.keynum = KEYCODE_BS; - kbdd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key); + (void)kbdd_ioctl(sc->kbd, GIO_KEYMAPENT, (caddr_t)&key); tp->t_termios.c_cc[VERASE] = key.key.map[0]; } #endif @@ -643,7 +643,7 @@ sctty_close(struct tty *tp) #endif scp->kbd_mode = K_XLATE; if (scp == scp->sc->cur_scp) - kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); + (void)kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); DPRINTF(5, ("done.\n")); } } @@ -1222,7 +1222,7 @@ sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) case K_CODE: /* switch to CODE mode */ scp->kbd_mode = *(int *)data; if (scp == sc->cur_scp) - kbdd_ioctl(sc->kbd, KDSKBMODE, data); + (void)kbdd_ioctl(sc->kbd, KDSKBMODE, data); return 0; default: return EINVAL; @@ -1336,7 +1336,7 @@ sctty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) } sc->kbd = kbd_get_keyboard(i); /* sc->kbd == newkbd */ sc->keyboard = i; - kbdd_ioctl(sc->kbd, KDSKBMODE, + (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode); update_kbd_state(sc->cur_scp, sc->cur_scp->status, LOCK_MASK); @@ -1649,14 +1649,14 @@ sc_cngetc(struct consdev *cd) /* we shall always use the keyboard in the XLATE mode here */ cur_mode = scp->kbd_mode; scp->kbd_mode = K_XLATE; - kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); + (void)kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); kbdd_poll(scp->sc->kbd, TRUE); c = scgetc(scp->sc, SCGETC_CN | SCGETC_NONBLOCK); kbdd_poll(scp->sc->kbd, FALSE); scp->kbd_mode = cur_mode; - kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); + (void)kbdd_ioctl(scp->sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); kbdd_disable(scp->sc->kbd); splx(s); @@ -1756,7 +1756,7 @@ scrn_timer(void *arg) sc->keyboard = sc_allocate_keyboard(sc, -1); if (sc->keyboard >= 0) { sc->kbd = kbd_get_keyboard(sc->keyboard); - kbdd_ioctl(sc->kbd, KDSKBMODE, + (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&sc->cur_scp->kbd_mode); update_kbd_state(sc->cur_scp, sc->cur_scp->status, LOCK_MASK); @@ -2551,7 +2551,7 @@ exchange_scr(sc_softc_t *sc) /* set up the keyboard for the new screen */ if (sc->old_scp->kbd_mode != scp->kbd_mode) - kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); + (void)kbdd_ioctl(sc->kbd, KDSKBMODE, (caddr_t)&scp->kbd_mode); update_kbd_state(scp, scp->status, LOCK_MASK); mark_all(scp); @@ -3334,7 +3334,7 @@ next_code: case NLK: case CLK: case ALK: break; case SLK: - kbdd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f); + (void)kbdd_ioctl(sc->kbd, KDGKBSTATE, (caddr_t)&f); if (f & SLKED) { scp->status |= SLKED; } else { @@ -3764,7 +3764,7 @@ sc_allocate_keyboard(sc_softc_t *sc, int unit) strcpy(ki.kb_name, k->kb_name); ki.kb_unit = k->kb_unit; - kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); + (void)kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki); } } else idx0 = kbd_allocate("*", unit, (void *)&sc->keyboard, sckbdevent, sc); diff --git a/sys/dev/tl/if_tl.c b/sys/dev/tl/if_tl.c index d18d21a63b6..a256552c0ab 100644 --- a/sys/dev/tl/if_tl.c +++ b/sys/dev/tl/if_tl.c @@ -1104,12 +1104,11 @@ static int tl_attach(dev) device_t dev; { - int i; u_int16_t did, vid; struct tl_type *t; struct ifnet *ifp; struct tl_softc *sc; - int unit, error = 0, rid; + int error, flags, i, rid, unit; u_char eaddr[6]; vid = pci_get_vendor(dev); @@ -1207,10 +1206,9 @@ tl_attach(dev) bzero(sc->tl_ldata, sizeof(struct tl_list_data)); - sc->tl_dinfo = t; - if (t->tl_vid == COMPAQ_VENDORID || t->tl_vid == TI_VENDORID) + if (vid == COMPAQ_VENDORID || vid == TI_VENDORID) sc->tl_eeaddr = TL_EEPROM_EADDR; - if (t->tl_vid == OLICOM_VENDORID) + if (vid == OLICOM_VENDORID) sc->tl_eeaddr = TL_EEPROM_EADDR_OC; /* Reset the adapter. */ @@ -1241,7 +1239,7 @@ tl_attach(dev) * word. To make things even more confusing, neither 00:00:28 * nor 00:00:24 appear in the IEEE OUI database. */ - if (sc->tl_dinfo->tl_vid == OLICOM_VENDORID) { + if (vid == OLICOM_VENDORID) { for (i = 0; i < ETHER_ADDR_LEN; i += 2) { u_int16_t *p; p = (u_int16_t *)&eaddr[i]; @@ -1276,9 +1274,25 @@ tl_attach(dev) * Do MII setup. If no PHYs are found, then this is a * bitrate ThunderLAN chip that only supports 10baseT * and AUI/BNC. + * XXX mii_attach() can fail for reason different than + * no PHYs found! */ - if (mii_phy_probe(dev, &sc->tl_miibus, - tl_ifmedia_upd, tl_ifmedia_sts)) { + flags = 0; + if (vid == COMPAQ_VENDORID) { + if (did == COMPAQ_DEVICEID_NETEL_10_100_PROLIANT || + did == COMPAQ_DEVICEID_NETFLEX_3P_INTEGRATED || + did == COMPAQ_DEVICEID_NETFLEX_3P_BNC || + did == COMPAQ_DEVICEID_NETEL_10_T2_UTP_COAX) + flags |= MIIF_MACPRIV0; + if (did == COMPAQ_DEVICEID_NETEL_10 || + did == COMPAQ_DEVICEID_NETEL_10_100_DUAL || + did == COMPAQ_DEVICEID_NETFLEX_3P || + did == COMPAQ_DEVICEID_NETEL_10_100_EMBEDDED) + flags |= MIIF_MACPRIV1; + } else if (vid == OLICOM_VENDORID && did == OLICOM_DEVICEID_OC2183) + flags |= MIIF_MACPRIV0 | MIIF_MACPRIV1; + if (mii_attach(dev, &sc->tl_miibus, ifp, tl_ifmedia_upd, + tl_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0)) { struct ifmedia *ifm; sc->tl_bitrate = 1; ifmedia_init(&sc->ifmedia, 0, tl_ifmedia_upd, tl_ifmedia_sts); diff --git a/sys/dev/tl/if_tlreg.h b/sys/dev/tl/if_tlreg.h index f0347e769ee..4e340b1eee7 100644 --- a/sys/dev/tl/if_tlreg.h +++ b/sys/dev/tl/if_tlreg.h @@ -116,7 +116,6 @@ struct tl_softc { struct resource *tl_irq; struct resource *tl_res; device_t tl_miibus; - struct tl_type *tl_dinfo; /* ThunderLAN adapter info */ u_int8_t tl_eeaddr; struct tl_list_data *tl_ldata; /* TX/RX lists and mbufs */ struct tl_chain_data tl_cdata; diff --git a/sys/dev/tsec/if_tsec.c b/sys/dev/tsec/if_tsec.c index 7ba7dc68528..c924419675a 100644 --- a/sys/dev/tsec/if_tsec.c +++ b/sys/dev/tsec/if_tsec.c @@ -268,11 +268,12 @@ tsec_attach(struct tsec_softc *sc) ifp->if_capabilities |= IFCAP_POLLING; #endif - /* Probe PHY(s) */ - error = mii_phy_probe(sc->dev, &sc->tsec_miibus, tsec_ifmedia_upd, - tsec_ifmedia_sts); + /* Attach PHY(s) */ + error = mii_attach(sc->dev, &sc->tsec_miibus, ifp, tsec_ifmedia_upd, + tsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->phyaddr, MII_OFFSET_ANY, + 0); if (error) { - device_printf(sc->dev, "MII failed to find PHY!\n"); + device_printf(sc->dev, "attaching PHYs failed\n"); if_free(ifp); sc->tsec_ifp = NULL; tsec_detach(sc); @@ -1561,11 +1562,6 @@ tsec_miibus_readreg(device_t dev, int phy, int reg) struct tsec_softc *sc; uint32_t timeout; - sc = device_get_softc(dev); - - if (sc->phyaddr != phy) - return (0); - sc = tsec0_sc; TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); @@ -1589,11 +1585,6 @@ tsec_miibus_writereg(device_t dev, int phy, int reg, int value) struct tsec_softc *sc; uint32_t timeout; - sc = device_get_softc(dev); - - if (sc->phyaddr != phy) - return (0); - sc = tsec0_sc; TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); diff --git a/sys/dev/twa/tw_cl.h b/sys/dev/twa/tw_cl.h index f15260a5ac7..ab1936d7302 100644 --- a/sys/dev/twa/tw_cl.h +++ b/sys/dev/twa/tw_cl.h @@ -88,7 +88,8 @@ struct tw_cli_q_stats { #define TW_CLI_BUSY_Q 1 /* q of reqs submitted to fw */ #define TW_CLI_PENDING_Q 2 /* q of reqs deferred due to 'q full' */ #define TW_CLI_COMPLETE_Q 3 /* q of reqs completed by fw */ -#define TW_CLI_Q_COUNT 4 /* total number of queues */ +#define TW_CLI_RESET_Q 4 /* q of reqs reset by timeout */ +#define TW_CLI_Q_COUNT 5 /* total number of queues */ /* CL's internal request context. */ @@ -133,6 +134,7 @@ struct tw_cli_ctlr_context { TW_UINT8 interrupts_enabled; /* Interrupts on controller enabled. */ TW_UINT8 internal_req_busy; /* Data buffer for internal requests in use. */ TW_UINT8 get_more_aens; /* More AEN's need to be retrieved. */ + TW_UINT8 reset_needed; /* Controller needs a soft reset. */ TW_UINT8 reset_in_progress; /* Controller is being reset. */ TW_UINT8 reset_phase1_in_progress; /* In 'phase 1' of reset. */ TW_UINT32 flags; /* controller settings */ diff --git a/sys/dev/twa/tw_cl_externs.h b/sys/dev/twa/tw_cl_externs.h index 1dd24255e5f..9fd2a3280b9 100644 --- a/sys/dev/twa/tw_cl_externs.h +++ b/sys/dev/twa/tw_cl_externs.h @@ -86,6 +86,8 @@ extern TW_INT32 tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, /* Soft reset the controller. */ extern TW_INT32 tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr); +extern int twa_setup_intr(struct twa_softc *sc); +extern int twa_teardown_intr(struct twa_softc *sc); /* Send down a SCSI command to the firmware (usually, an internal Req Sense. */ extern TW_INT32 tw_cli_send_scsi_cmd(struct tw_cli_req_context *req, diff --git a/sys/dev/twa/tw_cl_fwif.h b/sys/dev/twa/tw_cl_fwif.h index f9c7678380e..52f76bfeab1 100644 --- a/sys/dev/twa/tw_cl_fwif.h +++ b/sys/dev/twa/tw_cl_fwif.h @@ -89,7 +89,7 @@ #define TWA_STATUS_MINOR_VERSION_MASK 0x0F000000 #define TWA_STATUS_MAJOR_VERSION_MASK 0xF0000000 -#define TWA_STATUS_UNEXPECTED_BITS 0x00F00000 +#define TWA_STATUS_UNEXPECTED_BITS 0x00D00000 /* PCI related defines. */ diff --git a/sys/dev/twa/tw_cl_init.c b/sys/dev/twa/tw_cl_init.c index 0b7daa521f8..a39da75b7ff 100644 --- a/sys/dev/twa/tw_cl_init.c +++ b/sys/dev/twa/tw_cl_init.c @@ -315,6 +315,7 @@ tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags, tw_cli_req_q_init(ctlr, TW_CLI_BUSY_Q); tw_cli_req_q_init(ctlr, TW_CLI_PENDING_Q); tw_cli_req_q_init(ctlr, TW_CLI_COMPLETE_Q); + tw_cli_req_q_init(ctlr, TW_CLI_RESET_Q); /* Initialize all locks used by CL. */ ctlr->gen_lock = &(ctlr->gen_lock_handle); @@ -675,15 +676,14 @@ tw_cli_init_connection(struct tw_cli_ctlr_context *ctlr, /* Submit the command, and wait for it to complete. */ error = tw_cli_submit_and_poll_request(req, TW_CLI_REQUEST_TIMEOUT_PERIOD); - if (error == TW_OSL_ETIMEDOUT) - /* Clean-up done by tw_cli_submit_and_poll_request. */ - return(error); if (error) goto out; if ((error = init_connect->status)) { +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, &(req->cmd_pkt->cmd_hdr)); +#endif // 0 goto out; } if (set_features & TWA_EXTENDED_INIT_CONNECT) { diff --git a/sys/dev/twa/tw_cl_intr.c b/sys/dev/twa/tw_cl_intr.c index 08d63f9f0b8..a7c90d39555 100644 --- a/sys/dev/twa/tw_cl_intr.c +++ b/sys/dev/twa/tw_cl_intr.c @@ -248,8 +248,7 @@ tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr) #ifdef TW_OSL_DEBUG tw_cl_print_ctlr_stats(ctlr->ctlr_handle); #endif /* TW_OSL_DEBUG */ - tw_cl_reset_ctlr(ctlr->ctlr_handle); - return(TW_OSL_EIO); + continue; } /* @@ -402,9 +401,7 @@ tw_cli_complete_io(struct tw_cli_req_context *req) #ifdef TW_OSL_DEBUG tw_cl_print_ctlr_stats(ctlr->ctlr_handle); #endif /* TW_OSL_DEBUG */ - tw_cl_reset_ctlr(ctlr->ctlr_handle); - req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; - goto out; + return; } if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { @@ -483,6 +480,7 @@ tw_cli_scsi_complete(struct tw_cli_req_context *req) cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]); +#if 0 /* * Print the error. Firmware doesn't yet support * the 'Mode Sense' cmd. Don't print if the cmd @@ -493,6 +491,7 @@ tw_cli_scsi_complete(struct tw_cli_req_context *req) tw_cli_create_ctlr_event(req->ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, cmd_hdr); +#endif // 0 } if (scsi_req->sense_data) { @@ -530,9 +529,11 @@ tw_cli_param_callback(struct tw_cli_req_context *req) */ if (! req->error_code) if (cmd->param.status) { +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, &(req->cmd_pkt->cmd_hdr)); +#endif // 0 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING, @@ -590,9 +591,11 @@ tw_cli_aen_callback(struct tw_cli_req_context *req) if ((error = cmd->status)) { cmd_hdr = (struct tw_cl_command_header *) (&(req->cmd_pkt->cmd_hdr)); +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, cmd_hdr); +#endif // 0 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING, diff --git a/sys/dev/twa/tw_cl_io.c b/sys/dev/twa/tw_cl_io.c index 51ce08cdf43..1e1ca6cd676 100644 --- a/sys/dev/twa/tw_cl_io.c +++ b/sys/dev/twa/tw_cl_io.c @@ -74,18 +74,12 @@ tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, struct tw_cli_req_context *req; struct tw_cl_command_9k *cmd; struct tw_cl_scsi_req_packet *scsi_req; - TW_INT32 error; + TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); - if (ctlr->reset_in_progress) { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "I/O during reset: returning busy."); - return(TW_OSL_EBUSY); - } - /* * If working with a firmware version that does not support multiple * luns, and this request is directed at a non-zero lun, error it @@ -145,7 +139,12 @@ tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, cmd->sg_list, scsi_req->sgl_entries); } - if ((error = tw_cli_submit_cmd(req))) { + if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || + (ctlr->reset_in_progress)) { + tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); + TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, + TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); + } else if ((error = tw_cli_submit_cmd(req))) { tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "Could not start request. request = %p, error = %d", req, error); @@ -171,7 +170,7 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) struct tw_cli_ctlr_context *ctlr = req->ctlr; struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; TW_UINT32 status_reg; - TW_INT32 error; + TW_INT32 error = 0; tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); @@ -185,11 +184,7 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) TWA_COMMAND_QUEUE_OFFSET_LOW, (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); - /* Check to see if we can post a command. */ status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); - if ((error = tw_cli_check_ctlr_state(ctlr, status_reg))) - goto out; - if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) { struct tw_cl_req_packet *req_pkt = (struct tw_cl_req_packet *)(req->orig_req); @@ -207,14 +202,12 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) "pending internal/ioctl request"); req->state = TW_CLI_REQ_STATE_PENDING; tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); - error = 0; /* Unmask command interrupt. */ TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); } else error = TW_OSL_EBUSY; } else { - tw_osl_ctlr_busy(ctlr_handle, req->req_handle); error = TW_OSL_EBUSY; } } else { @@ -246,7 +239,7 @@ tw_cli_submit_cmd(struct tw_cli_req_context *req) (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); } } -out: + tw_osl_free_lock(ctlr_handle, ctlr->io_lock); return(error); @@ -277,18 +270,12 @@ tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT8 opcode; TW_UINT8 sgl_offset; TW_VOID *sgl = TW_CL_NULL; - TW_INT32 error; + TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); - if (ctlr->reset_in_progress) { - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "Passthru request during reset: returning busy."); - return(TW_OSL_EBUSY); - } - if ((req = tw_cli_get_request(ctlr )) == TW_CL_NULL) { tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), @@ -301,7 +288,7 @@ tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, req->orig_req = req_pkt; req->tw_cli_callback = tw_cli_complete_io; - req->flags |= (TW_CLI_REQ_FLAGS_EXTERNAL | TW_CLI_REQ_FLAGS_PASSTHRU); + req->flags |= TW_CLI_REQ_FLAGS_PASSTHRU; pt_req = &(req_pkt->gen_req_pkt.pt_req); @@ -348,7 +335,12 @@ tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, tw_cli_fill_sg_list(ctlr, pt_req->sg_list, sgl, pt_req->sgl_entries); - if ((error = tw_cli_submit_cmd(req))) { + if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || + (ctlr->reset_in_progress)) { + tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); + TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, + TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); + } else if ((error = tw_cli_submit_cmd(req))) { tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING, @@ -760,8 +752,7 @@ tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, cmd->param.sgl_off__opcode = BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM); - cmd->param.request_id = - (TW_UINT8)(TW_CL_SWAP16(req->request_id)); + cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id)); cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); cmd->param.param_count = TW_CL_SWAP16(1); @@ -789,15 +780,14 @@ tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, /* There's no call back; wait till the command completes. */ error = tw_cli_submit_and_poll_request(req, TW_CLI_REQUEST_TIMEOUT_PERIOD); - if (error == TW_OSL_ETIMEDOUT) - /* Clean-up done by tw_cli_submit_and_poll_request. */ - return(error); if (error) goto out; if ((error = cmd->param.status)) { +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, &(req->cmd_pkt->cmd_hdr)); +#endif // 0 goto out; } tw_osl_memcpy(param_data, param->data, param_size); @@ -905,18 +895,17 @@ tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, /* Submit the command. */ if (callback == TW_CL_NULL) { - /* There's no call back; wait till the command completes. */ + /* There's no call back; wait till the command completes. */ error = tw_cli_submit_and_poll_request(req, - TW_CLI_REQUEST_TIMEOUT_PERIOD); - if (error == TW_OSL_ETIMEDOUT) - /* Clean-up done by tw_cli_submit_and_poll_request. */ - return(error); + TW_CLI_REQUEST_TIMEOUT_PERIOD); if (error) goto out; if ((error = cmd->param.status)) { +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, &(req->cmd_pkt->cmd_hdr)); +#endif // 0 goto out; } ctlr->internal_req_busy = TW_CL_FALSE; @@ -1022,9 +1011,7 @@ tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, * tw_cli_submit_pending_queue. There could be a race in that case. * Need to revisit. */ - if (req->state != TW_CLI_REQ_STATE_PENDING) - tw_cl_reset_ctlr(ctlr->ctlr_handle); - else { + if (req->state == TW_CLI_REQ_STATE_PENDING) { tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "Removing request from pending queue"); /* @@ -1053,6 +1040,7 @@ tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, * drains any incomplete requests. * * Input: ctlr -- ptr to per ctlr structure + * req_handle -- ptr to request handle * Output: None * Return value: 0 -- success * non-zero-- failure @@ -1063,15 +1051,15 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) struct tw_cli_ctlr_context *ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt; + struct tw_cli_req_context *req; TW_INT32 reset_attempt = 1; - TW_INT32 error; + TW_INT32 error = 0; tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered"); ctlr->reset_in_progress = TW_CL_TRUE; - xpt_freeze_simq(sc->sim, 1); + twa_teardown_intr(sc); - tw_cli_disable_interrupts(ctlr); /* * Error back all requests in the complete, busy, and pending queues. @@ -1080,8 +1068,6 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) * will continue its course and get submitted to the controller after * the reset is done (and io_lock is released). */ - tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), - "Draining all queues following reset"); tw_cli_drain_complete_queue(ctlr); tw_cli_drain_busy_queue(ctlr); tw_cli_drain_pending_queue(ctlr); @@ -1089,53 +1075,88 @@ tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) ctlr->get_more_aens = TW_CL_FALSE; /* Soft reset the controller. */ -try_reset: - if ((error = tw_cli_soft_reset(ctlr))) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + while (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) { + if ((error = tw_cli_soft_reset(ctlr))) { + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, + TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, + 0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING, + "Controller reset failed", + "error = %d; attempt %d", error, reset_attempt++); + reset_attempt++; + continue; + } + + /* Re-establish logical connection with the controller. */ + if ((error = tw_cli_init_connection(ctlr, + (TW_UINT16)(ctlr->max_simult_reqs), + 0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL, + TW_CL_NULL, TW_CL_NULL))) { + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, + TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, + 0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING, + "Can't initialize connection after reset", + "error = %d", error); + reset_attempt++; + continue; + } + +#ifdef TW_OSL_DEBUG + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Controller reset failed", - "error = %d; attempt %d", error, reset_attempt++); - if (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) - goto try_reset; - else - goto out; + 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, + "Controller reset done!", " "); +#endif /* TW_OSL_DEBUG */ + break; + } /* End of while */ + + /* Move commands from the reset queue to the pending queue. */ + while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_RESET_Q)) != TW_CL_NULL) { + tw_osl_timeout(req->req_handle); + tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); } - /* Re-establish logical connection with the controller. */ - if ((error = tw_cli_init_connection(ctlr, - (TW_UINT16)(ctlr->max_simult_reqs), - 0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL, - TW_CL_NULL, TW_CL_NULL))) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Can't initialize connection after reset", - "error = %d", error); - goto out; - } - - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, - "Controller reset done!", - " "); - -out: - ctlr->reset_in_progress = TW_CL_FALSE; - xpt_release_simq(sc->sim, 1); - - /* - * Enable interrupts, and also clear attention and response interrupts. - */ + twa_setup_intr(sc); tw_cli_enable_interrupts(ctlr); - + if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) + TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, + TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); + ctlr->reset_in_progress = TW_CL_FALSE; + ctlr->reset_needed = TW_CL_FALSE; + /* Request for a bus re-scan. */ - if (!error) - tw_osl_scan_bus(ctlr_handle); + tw_osl_scan_bus(ctlr_handle); + return(error); } +TW_VOID +tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) +{ + struct tw_cli_ctlr_context *ctlr = + (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); + + ctlr->reset_needed = TW_CL_TRUE; +} + +TW_INT32 +tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) +{ + struct tw_cli_ctlr_context *ctlr = + (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); + + return(ctlr->reset_needed); +} + +TW_INT32 +tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle) +{ + struct tw_cli_ctlr_context *ctlr = + (struct tw_cli_ctlr_context *) + (ctlr_handle->cl_ctlr_ctxt); + + return(ctlr->active); +} + /* @@ -1151,14 +1172,13 @@ TW_INT32 tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) { struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; - TW_UINT32 status_reg; int found; int loop_count; TW_UINT32 error; tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered"); - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING, "Resetting controller...", @@ -1193,7 +1213,7 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */ if (!found) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Missed firmware handshake after soft-reset", @@ -1210,7 +1230,7 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) TWA_STATUS_MICROCONTROLLER_READY | TWA_STATUS_ATTENTION_INTERRUPT, TW_CLI_RESET_TIMEOUT_PERIOD))) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Micro-ctlr not ready/No attn intr after reset", @@ -1244,26 +1264,14 @@ tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) } if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Reset not reported by controller", "error = %d", error); return(error); } - - status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); - - if ((error = TW_CLI_STATUS_ERRORS(status_reg)) || - (error = tw_cli_check_ctlr_state(ctlr, status_reg))) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x110D, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Controller errors detected after reset", - "error = %d", error); - return(error); - } - + return(TW_OSL_ESUCCESS); } diff --git a/sys/dev/twa/tw_cl_misc.c b/sys/dev/twa/tw_cl_misc.c index f6c98455303..b6b53330f21 100644 --- a/sys/dev/twa/tw_cl_misc.c +++ b/sys/dev/twa/tw_cl_misc.c @@ -83,7 +83,8 @@ tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr) tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); /* Walk the busy queue. */ - while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q))) { + while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) != + TW_CL_NULL) { if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { /* * It's an internal request. Set the appropriate @@ -97,20 +98,21 @@ tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr) req->error_code = TW_CL_ERR_REQ_BUS_RESET; if (req->tw_cli_callback) req->tw_cli_callback(req); - } else { - if ((req_pkt = req->orig_req)) { - /* It's a SCSI request. Complete it. */ - tw_cli_dbg_printf(2, ctlr->ctlr_handle, - tw_osl_cur_func(), - "Completing complete request %p " - "on reset", - req); + } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { + /* It's a passthru request. Complete it. */ + if ((req_pkt = req->orig_req) != TW_CL_NULL) { req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; - req_pkt->tw_osl_callback(req->req_handle); + + if (req_pkt->tw_osl_callback) + req_pkt->tw_osl_callback(req->req_handle); } tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); + } else { + /* It's an external (SCSI) request. Add it to the reset queue. */ + tw_osl_untimeout(req->req_handle); + tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); } - } + } /* End of while loop */ } @@ -135,7 +137,8 @@ tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); /* Walk the busy queue. */ - while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q))) { + while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q)) != + TW_CL_NULL) { if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { /* * It's an internal request. Set the appropriate @@ -149,19 +152,21 @@ tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) req->error_code = TW_CL_ERR_REQ_BUS_RESET; if (req->tw_cli_callback) req->tw_cli_callback(req); - } else { - if ((req_pkt = req->orig_req)) { - /* It's a SCSI request. Complete it. */ - tw_cli_dbg_printf(2, ctlr->ctlr_handle, - tw_osl_cur_func(), - "Completing busy request %p on reset", - req); + } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { + /* It's a passthru request. Complete it. */ + if ((req_pkt = req->orig_req) != TW_CL_NULL) { req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; - req_pkt->tw_osl_callback(req->req_handle); + + if (req_pkt->tw_osl_callback) + req_pkt->tw_osl_callback(req->req_handle); } tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); + } else { + /* It's an external (SCSI) request. Add it to the reset queue. */ + tw_osl_untimeout(req->req_handle); + tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); } - } + } /* End of while loop */ } @@ -188,7 +193,8 @@ tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr) /* * Pull requests off the pending queue, and complete them. */ - while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q))) { + while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) != + TW_CL_NULL) { if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { /* * It's an internal request. Set the appropriate @@ -202,19 +208,21 @@ tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr) req->error_code = TW_CL_ERR_REQ_BUS_RESET; if (req->tw_cli_callback) req->tw_cli_callback(req); - } else { - if ((req_pkt = req->orig_req)) { - /* It's an external request. Complete it. */ - tw_cli_dbg_printf(2, ctlr->ctlr_handle, - tw_osl_cur_func(), - "Completing pending request %p " - "on reset", req); + } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { + /* It's a passthru request. Complete it. */ + if ((req_pkt = req->orig_req) != TW_CL_NULL) { req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; - req_pkt->tw_osl_callback(req->req_handle); + + if (req_pkt->tw_osl_callback) + req_pkt->tw_osl_callback(req->req_handle); } tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); + } else { + /* It's an external (SCSI) request. Add it to the reset queue. */ + tw_osl_untimeout(req->req_handle); + tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); } - } + } /* End of while loop */ } @@ -239,9 +247,6 @@ tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr) for (;;) { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); - if (tw_cli_check_ctlr_state(ctlr, status_reg)) - return(TW_OSL_EGENFAILURE); - if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) return(TW_OSL_ESUCCESS); /* no more response queue entries */ @@ -273,9 +278,6 @@ tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id) for (;;) { status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); - if (tw_cli_check_ctlr_state(ctlr, status_reg)) - return(TW_OSL_EGENFAILURE); - if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) return(TW_OSL_ENOTTY); /* no more response queue entries */ @@ -356,9 +358,11 @@ tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr) if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) { cmd_hdr = &req->cmd_pkt->cmd_hdr; +#if 0 tw_cli_create_ctlr_event(ctlr, TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, cmd_hdr); +#endif // 0 break; } @@ -714,7 +718,7 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) tw_osl_memzero(desc, 200); if (!(ctlr->reset_phase1_in_progress)) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Missing expected status bit(s)", @@ -738,7 +742,7 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) || (!(ctlr->reset_in_progress)) || ((status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) == 0)) - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Unexpected status bit(s)", @@ -748,7 +752,7 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) TWA_STATUS_UNEXPECTED_BITS, desc)); if (status_reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1303, 0x1, TW_CL_SEVERITY_ERROR_STRING, "PCI parity error: clearing... " @@ -768,7 +772,7 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) } if (status_reg & TWA_STATUS_PCI_ABORT_INTERRUPT) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1304, 0x1, TW_CL_SEVERITY_ERROR_STRING, "PCI abort: clearing... ", @@ -791,7 +795,7 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) if (((ctlr->device_id != TW_CL_DEVICE_ID_9K_E) && (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) || (!(ctlr->reset_in_progress))) - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, + tw_cl_create_event(ctlr_handle, TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 0x1305, 0x1, TW_CL_SEVERITY_ERROR_STRING, "Controller queue error: clearing... ", @@ -801,17 +805,6 @@ tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, TWA_CONTROL_CLEAR_QUEUE_ERROR); } - - if (status_reg & TWA_STATUS_MICROCONTROLLER_ERROR) { - tw_cl_create_event(ctlr_handle, TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, - 0x1307, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Micro-controller error! ", - "status reg = 0x%x %s", - status_reg, - tw_cli_describe_bits(status_reg, desc)); - error = TW_OSL_EGENFAILURE; - } } return(error); } @@ -850,8 +843,6 @@ tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str) tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,"); if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT) tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,"); - if (reg & TWA_STATUS_MICROCONTROLLER_ERROR) - tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_ERR,"); if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,"); if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) diff --git a/sys/dev/twa/tw_cl_share.h b/sys/dev/twa/tw_cl_share.h index d9eb788b17a..727684984c5 100644 --- a/sys/dev/twa/tw_cl_share.h +++ b/sys/dev/twa/tw_cl_share.h @@ -349,10 +349,14 @@ extern TW_VOID tw_osl_breakpoint(TW_VOID); #endif -#ifndef tw_osl_ctlr_busy -/* Called when CL is too busy to accept new requests. */ -extern TW_VOID tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle, - struct tw_cl_req_handle *req_handle); +#ifndef tw_osl_timeout +/* Start OS timeout() routine after controller reset sequence */ +extern TW_VOID tw_osl_timeout(struct tw_cl_req_handle *req_handle); +#endif + +#ifndef tw_osl_untimeout +/* Stop OS timeout() routine during controller reset sequence */ +extern TW_VOID tw_osl_untimeout(struct tw_cl_req_handle *req_handle); #endif @@ -552,6 +556,10 @@ extern TW_INT32 tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle, ); +extern TW_VOID tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle); +extern TW_INT32 tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle); +extern TW_INT32 tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle); + /* CL's interrupt handler. */ extern TW_INT32 tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle); diff --git a/sys/dev/twa/tw_osl.h b/sys/dev/twa/tw_osl.h index bce9958987b..1cc40fb1f03 100644 --- a/sys/dev/twa/tw_osl.h +++ b/sys/dev/twa/tw_osl.h @@ -77,6 +77,7 @@ EINPROGRESS */ #define TW_OSLI_REQ_FLAGS_PASSTHRU (1<<5) /* pass through request */ #define TW_OSLI_REQ_FLAGS_SLEEPING (1<<6) /* owner sleeping on this cmd */ +#define TW_OSLI_REQ_FLAGS_FAILED (1<<7) /* bus_dmamap_load() failed */ #ifdef TW_OSL_DEBUG @@ -100,6 +101,7 @@ struct tw_osli_req_context { struct twa_softc *ctlr; /* ptr to OSL's controller context */ TW_VOID *data; /* ptr to data being passed to CL */ TW_UINT32 length; /* length of buf being passed to CL */ + TW_UINT64 deadline;/* request timeout (in absolute time) */ /* * ptr to, and length of data passed to us from above, in case a buffer @@ -151,6 +153,9 @@ struct twa_softc { struct mtx sim_lock_handle;/* sim lock shared with cam */ struct mtx *sim_lock;/* ptr to sim lock */ + struct callout watchdog_callout[2]; /* For command timout */ + TW_UINT32 watchdog_index; + #ifdef TW_OSL_DEBUG struct tw_osli_q_stats q_stats[TW_OSLI_Q_COUNT];/* queue statistics */ #endif /* TW_OSL_DEBUG */ diff --git a/sys/dev/twa/tw_osl_cam.c b/sys/dev/twa/tw_osl_cam.c index 5854fd6c727..8b81ccca4f0 100644 --- a/sys/dev/twa/tw_osl_cam.c +++ b/sys/dev/twa/tw_osl_cam.c @@ -55,7 +55,6 @@ static TW_VOID twa_action(struct cam_sim *sim, union ccb *ccb); static TW_VOID twa_poll(struct cam_sim *sim); -static TW_VOID twa_timeout(TW_VOID *arg); static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb); @@ -81,7 +80,7 @@ tw_osli_cam_attach(struct twa_softc *sc) /* * Create the device queue for our SIM. */ - if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_REQUESTS)) == NULL) { + if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) { tw_osli_printf(sc, "error = %d", TW_CL_SEVERITY_ERROR_STRING, TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, @@ -275,6 +274,7 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) "I/O size too big", csio->dxfer_len); ccb_h->status = CAM_REQ_TOO_BIG; + ccb_h->status &= ~CAM_SIM_QUEUED; xpt_done(ccb); return(1); } @@ -290,6 +290,7 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) 0x2107, "XPT_SCSI_IO: Got SGList"); ccb_h->status = CAM_REQ_INVALID; + ccb_h->status &= ~CAM_SIM_QUEUED; xpt_done(ccb); return(1); } @@ -306,13 +307,20 @@ tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb) return(1); } - ccb_h->timeout_ch = timeout(twa_timeout, req, - (ccb_h->timeout * hz) / 1000); + req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000); + + /* * twa_map_load_data_callback will fill in the SGL, * and submit the I/O. */ error = tw_osli_map_request(req); + if ((error) && (req->flags & TW_OSLI_REQ_FLAGS_FAILED)) { + req->deadline = 0; + ccb_h->status = CAM_REQ_CMP_ERR; + ccb_h->status &= ~CAM_SIM_QUEUED; + xpt_done(ccb); + } return(error); } @@ -345,10 +353,20 @@ twa_action(struct cam_sim *sim, union ccb *ccb) * Freeze the simq to maintain ccb ordering. The next * ccb that gets completed will unfreeze the simq. */ + ccb_h->status &= ~CAM_SIM_QUEUED; ccb_h->status |= CAM_REQUEUE_REQ; xpt_done(ccb); break; } + + if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) { + ccb_h->status &= ~CAM_SIM_QUEUED; + ccb_h->status |= CAM_REQUEUE_REQ; + xpt_done(ccb); + tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q); + break; + } + req->req_handle.osl_req_ctxt = req; req->req_handle.is_io = TW_CL_TRUE; req->orig_req = ccb; @@ -364,25 +382,14 @@ twa_action(struct cam_sim *sim, union ccb *ccb) break; case XPT_RESET_BUS: - tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE, + tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE, TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, 0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING, "Received Reset Bus request from CAM", " "); - mtx_unlock(sc->sim_lock); - if (tw_cl_reset_ctlr(&sc->ctlr_handle)) { - tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, - 0x2109, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Failed to reset bus", - " "); - ccb_h->status = CAM_REQ_CMP_ERR; - } - else - ccb_h->status = CAM_REQ_CMP; - - mtx_lock(sc->sim_lock); + tw_cl_set_reset_needed(&(sc->ctlr_handle)); + ccb_h->status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -450,6 +457,7 @@ twa_action(struct cam_sim *sim, union ccb *ccb) path_inq->transport_version = 2; path_inq->protocol = PROTO_SCSI; path_inq->protocol_version = SCSI_REV_2; + path_inq->maxio = TW_CL_MAX_IO_SIZE; ccb_h->status = CAM_REQ_CMP; xpt_done(ccb); break; @@ -486,31 +494,6 @@ twa_poll(struct cam_sim *sim) -/* - * Function name: twa_timeout - * Description: Driver entry point for being alerted on a request - * timing out. - * - * Input: arg -- ptr to timed out request - * Output: None - * Return value: None - */ -static TW_VOID -twa_timeout(TW_VOID *arg) -{ - struct tw_osli_req_context *req = - (struct tw_osli_req_context *)arg; - - tw_cl_create_event(&(req->ctlr->ctlr_handle), TW_CL_TRUE, - TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, - 0x210B, 0x1, TW_CL_SEVERITY_ERROR_STRING, - "Request timed out!", - "request = %p", req); - tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle)); -} - - - /* * Function name: tw_osli_request_bus_scan * Description: Requests CAM for a scan of the bus. @@ -574,20 +557,39 @@ tw_osli_disallow_new_requests(struct twa_softc *sc, /* - * Function name: tw_osl_ctlr_busy - * Description: CL calls this function on cmd queue full or otherwise, - * when it is too busy to accept new requests. + * Function name: tw_osl_timeout + * Description: Call to timeout(). * - * Input: ctlr_handle -- ptr to controller handle - * req_handle -- ptr to request handle sent by OSL. + * Input: req_handle -- ptr to request handle sent by OSL. * Output: None * Return value: None */ TW_VOID -tw_osl_ctlr_busy(struct tw_cl_ctlr_handle *ctlr_handle, - struct tw_cl_req_handle *req_handle) +tw_osl_timeout(struct tw_cl_req_handle *req_handle) { - tw_osli_disallow_new_requests(ctlr_handle->osl_ctlr_ctxt, req_handle); + struct tw_osli_req_context *req = req_handle->osl_req_ctxt; + union ccb *ccb = (union ccb *)(req->orig_req); + struct ccb_hdr *ccb_h = &(ccb->ccb_h); + + req->deadline = tw_osl_get_local_time() + (ccb_h->timeout / 1000); +} + + + +/* + * Function name: tw_osl_untimeout + * Description: Inverse of call to timeout(). + * + * Input: req_handle -- ptr to request handle sent by OSL. + * Output: None + * Return value: None + */ +TW_VOID +tw_osl_untimeout(struct tw_cl_req_handle *req_handle) +{ + struct tw_osli_req_context *req = req_handle->osl_req_ctxt; + + req->deadline = 0; } @@ -655,7 +657,7 @@ tw_osl_complete_io(struct tw_cl_req_handle *req_handle) tw_osli_unmap_request(req); - untimeout(twa_timeout, req, ccb->ccb_h.timeout_ch); + req->deadline = 0; if (req->error_code) { /* This request never got submitted to the firmware. */ if (req->error_code == EBUSY) { @@ -682,7 +684,7 @@ tw_osl_complete_io(struct tw_cl_req_handle *req_handle) else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR) ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET) - ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; + ccb->ccb_h.status |= (CAM_REQUEUE_REQ | CAM_SCSI_BUS_RESET); /* * If none of the above errors occurred, simply * mark completion error. diff --git a/sys/dev/twa/tw_osl_freebsd.c b/sys/dev/twa/tw_osl_freebsd.c index 09bb55ee2db..caf18f1f77b 100644 --- a/sys/dev/twa/tw_osl_freebsd.c +++ b/sys/dev/twa/tw_osl_freebsd.c @@ -175,6 +175,9 @@ static TW_INT32 twa_detach(device_t dev); static TW_INT32 twa_shutdown(device_t dev); static TW_VOID twa_busdma_lock(TW_VOID *lock_arg, bus_dma_lock_op_t op); static TW_VOID twa_pci_intr(TW_VOID *arg); +static TW_VOID twa_watchdog(TW_VOID *arg); +int twa_setup_intr(struct twa_softc *sc); +int twa_teardown_intr(struct twa_softc *sc); static TW_INT32 tw_osli_alloc_mem(struct twa_softc *sc); static TW_VOID tw_osli_free_resources(struct twa_softc *sc); @@ -238,6 +241,32 @@ twa_probe(device_t dev) return(ENXIO); } +int twa_setup_intr(struct twa_softc *sc) +{ + int error = 0; + + if (!(sc->intr_handle) && (sc->irq_res)) { + error = bus_setup_intr(sc->bus_dev, sc->irq_res, + INTR_TYPE_CAM | INTR_MPSAFE, + NULL, twa_pci_intr, + sc, &sc->intr_handle); + } + return( error ); +} + + +int twa_teardown_intr(struct twa_softc *sc) +{ + int error = 0; + + if ((sc->intr_handle) && (sc->irq_res)) { + error = bus_teardown_intr(sc->bus_dev, + sc->irq_res, sc->intr_handle); + sc->intr_handle = NULL; + } + return( error ); +} + /* @@ -354,10 +383,7 @@ twa_attach(device_t dev) tw_osli_free_resources(sc); return(ENXIO); } - if ((error = bus_setup_intr(sc->bus_dev, sc->irq_res, - INTR_TYPE_CAM | INTR_MPSAFE, - NULL, twa_pci_intr, - sc, &sc->intr_handle))) { + if ((error = twa_setup_intr(sc))) { tw_osli_printf(sc, "error = %d", TW_CL_SEVERITY_ERROR_STRING, TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, @@ -412,10 +438,77 @@ twa_attach(device_t dev) return(error); } + sc->watchdog_index = 0; + callout_init(&(sc->watchdog_callout[0]), CALLOUT_MPSAFE); + callout_init(&(sc->watchdog_callout[1]), CALLOUT_MPSAFE); + callout_reset(&(sc->watchdog_callout[0]), 5*hz, twa_watchdog, &sc->ctlr_handle); + return(0); } +static TW_VOID +twa_watchdog(TW_VOID *arg) +{ + struct tw_cl_ctlr_handle *ctlr_handle = + (struct tw_cl_ctlr_handle *)arg; + struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt; + int i; + int i_need_a_reset = 0; + int driver_is_active = 0; + int my_watchdog_was_pending = 1234; + TW_UINT64 current_time; + struct tw_osli_req_context *my_req; + + +//============================================================================== + current_time = (TW_UINT64) (tw_osl_get_local_time()); + + for (i = 0; i < TW_OSLI_MAX_NUM_REQUESTS; i++) { + my_req = &(sc->req_ctx_buf[i]); + + if ((my_req->state == TW_OSLI_REQ_STATE_BUSY) && + (my_req->deadline) && + (my_req->deadline < current_time)) { + tw_cl_set_reset_needed(ctlr_handle); +#ifdef TW_OSL_DEBUG + device_printf((sc)->bus_dev, "Request %d timed out! d = %llu, c = %llu\n", i, my_req->deadline, current_time); +#else /* TW_OSL_DEBUG */ + device_printf((sc)->bus_dev, "Request %d timed out!\n", i); +#endif /* TW_OSL_DEBUG */ + break; + } + } +//============================================================================== + + i_need_a_reset = tw_cl_is_reset_needed(ctlr_handle); + + i = (int) ((sc->watchdog_index++) & 1); + + driver_is_active = tw_cl_is_active(ctlr_handle); + + if (i_need_a_reset) { +#ifdef TW_OSL_DEBUG + device_printf((sc)->bus_dev, "Watchdog rescheduled in 70 seconds\n"); +#endif /* TW_OSL_DEBUG */ + my_watchdog_was_pending = + callout_reset(&(sc->watchdog_callout[i]), 70*hz, twa_watchdog, &sc->ctlr_handle); + tw_cl_reset_ctlr(ctlr_handle); +#ifdef TW_OSL_DEBUG + device_printf((sc)->bus_dev, "Watchdog reset completed!\n"); +#endif /* TW_OSL_DEBUG */ + } else if (driver_is_active) { + my_watchdog_was_pending = + callout_reset(&(sc->watchdog_callout[i]), 5*hz, twa_watchdog, &sc->ctlr_handle); + } +#ifdef TW_OSL_DEBUG + if (i_need_a_reset || my_watchdog_was_pending) + device_printf((sc)->bus_dev, "i_need_a_reset = %d, " + "driver_is_active = %d, my_watchdog_was_pending = %d\n", + i_need_a_reset, driver_is_active, my_watchdog_was_pending); +#endif /* TW_OSL_DEBUG */ +} + /* * Function name: tw_osli_alloc_mem @@ -715,9 +808,7 @@ tw_osli_free_resources(struct twa_softc *sc) /* Disconnect the interrupt handler. */ - if (sc->intr_handle) - if ((error = bus_teardown_intr(sc->bus_dev, - sc->irq_res, sc->intr_handle))) + if ((error = twa_teardown_intr(sc))) tw_osli_dbg_dprintf(1, sc, "teardown_intr returned %d", error); @@ -809,6 +900,13 @@ twa_shutdown(device_t dev) tw_osli_dbg_dprintf(3, sc, "entered"); + /* Disconnect interrupts. */ + error = twa_teardown_intr(sc); + + /* Stop watchdog task. */ + callout_drain(&(sc->watchdog_callout[0])); + callout_drain(&(sc->watchdog_callout[1])); + /* Disconnect from the controller. */ if ((error = tw_cl_shutdown_ctlr(&(sc->ctlr_handle), 0))) { tw_osli_printf(sc, "error = %d", @@ -997,33 +1095,35 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf) error = 0; /* False error */ break; } - tw_osli_printf(sc, "request = %p", - TW_CL_SEVERITY_ERROR_STRING, - TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, - 0x2018, - "Passthru request timed out!", - req); - /* - * Should I check here if the timeout happened - * because of yet another reset, and not do a - * second reset? - */ - tw_cl_reset_ctlr(&sc->ctlr_handle); + if (!(tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) { +#ifdef TW_OSL_DEBUG + tw_osli_printf(sc, "request = %p", + TW_CL_SEVERITY_ERROR_STRING, + TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, + 0x2018, + "Passthru request timed out!", + req); +#else /* TW_OSL_DEBUG */ + device_printf((sc)->bus_dev, "Passthru request timed out!\n"); +#endif /* TW_OSL_DEBUG */ + tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle)); + } + + error = 0; + end_time = tw_osl_get_local_time() + timeout; + continue; /* * Don't touch req after a reset. It (and any - * associated data) will already have been + * associated data) will be * unmapped by the callback. */ - user_buf->driver_pkt.os_status = error; - error = ETIMEDOUT; - goto fw_passthru_err; } /* * Either the request got completed, or we were woken up by a * signal. Calculate the new timeout, in case it was the latter. */ timeout = (end_time - tw_osl_get_local_time()); - } + } /* End of while loop */ /* If there was a payload, copy it back. */ if ((!error) && (req->length)) @@ -1037,19 +1137,9 @@ tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf) error); fw_passthru_err: - /* - * Print the failure message. For some reason, on certain OS versions, - * printing this error message during reset hangs the display (although - * the rest of the system is running fine. So, don't print it if the - * failure was due to a reset. - */ - if ((error) && (error != TW_CL_ERR_REQ_BUS_RESET)) - tw_osli_printf(sc, "error = %d", - TW_CL_SEVERITY_ERROR_STRING, - TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, - 0x201A, - "Firmware passthru failed!", - error); + + if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET) + error = EBUSY; user_buf->driver_pkt.os_status = error; /* Free resources. */ @@ -1073,6 +1163,8 @@ TW_VOID tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle) { struct tw_osli_req_context *req = req_handle->osl_req_ctxt; + struct tw_cl_req_packet *req_pkt = + (struct tw_cl_req_packet *)(&req->req_pkt); struct twa_softc *sc = req->ctlr; tw_osli_dbg_dprintf(5, sc, "entered"); @@ -1120,6 +1212,9 @@ tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle) if (req->flags & TW_OSLI_REQ_FLAGS_MAPPED) return; + if (req_pkt->status == TW_CL_ERR_REQ_BUS_RESET) + return; + tw_osli_printf(sc, "request = %p", TW_CL_SEVERITY_ERROR_STRING, TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, @@ -1166,6 +1261,7 @@ tw_osli_get_request(struct twa_softc *sc) req->req_handle.is_io = 0; req->data = NULL; req->length = 0; + req->deadline = 0; req->real_data = NULL; req->real_length = 0; req->state = TW_OSLI_REQ_STATE_INIT;/* req being initialized */ @@ -1207,6 +1303,11 @@ twa_map_load_data_callback(TW_VOID *arg, bus_dma_segment_t *segs, tw_osli_dbg_dprintf(10, sc, "entered"); + if (error == EINVAL) { + req->error_code = error; + return; + } + /* Mark the request as currently being processed. */ req->state = TW_OSLI_REQ_STATE_BUSY; /* Move the request into the busy queue. */ @@ -1400,6 +1501,14 @@ tw_osli_map_request(struct tw_osli_req_context *req) mtx_unlock_spin(sc->io_lock); error = 0; } else { + tw_osli_printf(sc, "error = %d", + TW_CL_SEVERITY_ERROR_STRING, + TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER, + 0x9999, + "Failed to map DMA memory " + "for I/O request", + error); + req->flags |= TW_OSLI_REQ_FLAGS_FAILED; /* Free alignment buffer if it was used. */ if (req->flags & TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED) { diff --git a/sys/dev/twa/tw_osl_share.h b/sys/dev/twa/tw_osl_share.h index 4d10ed46c1b..c17d8cc28b5 100644 --- a/sys/dev/twa/tw_osl_share.h +++ b/sys/dev/twa/tw_osl_share.h @@ -75,7 +75,7 @@ #define TW_OSL_ENCLOSURE_SUPPORT #endif -#define TW_OSL_DRIVER_VERSION_STRING "3.80.06.002" +#define TW_OSL_DRIVER_VERSION_STRING "3.80.06.003" #define TW_OSL_CAN_SLEEP diff --git a/sys/dev/tx/if_tx.c b/sys/dev/tx/if_tx.c index 3750e7b6a59..12843ac9037 100644 --- a/sys/dev/tx/if_tx.c +++ b/sys/dev/tx/if_tx.c @@ -379,10 +379,10 @@ epic_attach(device_t dev) device_printf(dev, "unknown card vendor %04xh\n", sc->cardvend); /* Do ifmedia setup. */ - if (mii_phy_probe(dev, &sc->miibus, - epic_ifmedia_upd, epic_ifmedia_sts)) { - device_printf(dev, "ERROR! MII without any PHY!?\n"); - error = ENXIO; + error = mii_attach(dev, &sc->miibus, ifp, epic_ifmedia_upd, + epic_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c index fc0db86a3b8..aaced9fcbd4 100644 --- a/sys/dev/usb/controller/at91dci.c +++ b/sys/dev/usb/controller/at91dci.c @@ -1689,7 +1689,7 @@ static const struct usb_device_descriptor at91dci_devd = { .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_HUB, .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, + .bDeviceProtocol = UDPROTO_FSHUB, .bMaxPacketSize = 64, .bcdDevice = {0x00, 0x01}, .iManufacturer = 1, @@ -1697,17 +1697,6 @@ static const struct usb_device_descriptor at91dci_devd = { .bNumConfigurations = 1, }; -static const struct usb_device_qualifier at91dci_odevd = { - .bLength = sizeof(struct usb_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - static const struct at91dci_config_desc at91dci_confd = { .confd = { .bLength = sizeof(struct usb_config_descriptor), @@ -1725,7 +1714,7 @@ static const struct at91dci_config_desc at91dci_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c index adbd972db6d..45d18682332 100644 --- a/sys/dev/usb/controller/atmegadci.c +++ b/sys/dev/usb/controller/atmegadci.c @@ -1511,7 +1511,7 @@ static const struct usb_device_descriptor atmegadci_devd = { .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_HUB, .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, + .bDeviceProtocol = UDPROTO_FSHUB, .bMaxPacketSize = 64, .bcdDevice = {0x00, 0x01}, .iManufacturer = 1, @@ -1519,17 +1519,6 @@ static const struct usb_device_descriptor atmegadci_devd = { .bNumConfigurations = 1, }; -static const struct usb_device_qualifier atmegadci_odevd = { - .bLength = sizeof(struct usb_device_qualifier), - .bDescriptorType = UDESC_DEVICE_QUALIFIER, - .bcdUSB = {0x00, 0x02}, - .bDeviceClass = UDCLASS_HUB, - .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_FSHUB, - .bMaxPacketSize0 = 0, - .bNumConfigurations = 0, -}; - static const struct atmegadci_config_desc atmegadci_confd = { .confd = { .bLength = sizeof(struct usb_config_descriptor), @@ -1547,7 +1536,7 @@ static const struct atmegadci_config_desc atmegadci_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), diff --git a/sys/dev/usb/controller/avr32dci.c b/sys/dev/usb/controller/avr32dci.c index 8abe46c4a6c..6c171baebad 100644 --- a/sys/dev/usb/controller/avr32dci.c +++ b/sys/dev/usb/controller/avr32dci.c @@ -1480,7 +1480,7 @@ static const struct avr32dci_config_desc avr32dci_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), diff --git a/sys/dev/usb/controller/ehci.c b/sys/dev/usb/controller/ehci.c index 40c95241672..91119823c81 100644 --- a/sys/dev/usb/controller/ehci.c +++ b/sys/dev/usb/controller/ehci.c @@ -145,7 +145,6 @@ struct ehci_std_temp { uint8_t auto_data_toggle; uint8_t setup_alt_next; uint8_t last_frame; - uint8_t can_use_next; }; void @@ -157,6 +156,9 @@ ehci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) cb(bus, &sc->sc_hw.pframes_pc, &sc->sc_hw.pframes_pg, sizeof(uint32_t) * EHCI_FRAMELIST_COUNT, EHCI_FRAMELIST_ALIGN); + cb(bus, &sc->sc_hw.terminate_pc, &sc->sc_hw.terminate_pg, + sizeof(struct ehci_qh_sub), EHCI_QH_ALIGN); + cb(bus, &sc->sc_hw.async_start_pc, &sc->sc_hw.async_start_pg, sizeof(ehci_qh_t), EHCI_QH_ALIGN); @@ -310,6 +312,24 @@ ehci_init(ehci_softc_t *sc) sc->sc_eintrs = EHCI_NORMAL_INTRS; + if (1) { + struct ehci_qh_sub *qh; + + usbd_get_page(&sc->sc_hw.terminate_pc, 0, &buf_res); + + qh = buf_res.buffer; + + sc->sc_terminate_self = htohc32(sc, buf_res.physaddr); + + /* init terminate TD */ + qh->qtd_next = + htohc32(sc, EHCI_LINK_TERMINATE); + qh->qtd_altnext = + htohc32(sc, EHCI_LINK_TERMINATE); + qh->qtd_status = + htohc32(sc, EHCI_QTD_HALTED); + } + for (i = 0; i < EHCI_VIRTUAL_FRAMELIST_COUNT; i++) { ehci_qh_t *qh; @@ -1416,15 +1436,7 @@ ehci_check_transfer(struct usb_xfer *xfer) */ if (status & EHCI_QTD_ACTIVE) { /* update cache */ - if (xfer->td_transfer_cache != td) { - xfer->td_transfer_cache = td; - if (qh->qh_qtd.qtd_next & - htohc32(sc, EHCI_LINK_TERMINATE)) { - /* XXX - manually advance to next frame */ - qh->qh_qtd.qtd_next = td->qtd_self; - usb_pc_cpu_flush(td->page_cache); - } - } + xfer->td_transfer_cache = td; goto done; } /* @@ -1634,10 +1646,12 @@ ehci_setup_standard_chain_sub(struct ehci_std_temp *temp) uint32_t average; uint32_t len_old; uint32_t terminate; + uint32_t qtd_altnext; uint8_t shortpkt_old; uint8_t precompute; - terminate = htohc32(temp->sc, EHCI_LINK_TERMINATE); + terminate = temp->sc->sc_terminate_self; + qtd_altnext = temp->sc->sc_terminate_self; td_alt_next = NULL; buf_offset = 0; shortpkt_old = temp->shortpkt; @@ -1771,23 +1785,11 @@ restart: td->qtd_buffer_hi[x] = 0; } - if (temp->can_use_next) { - if (td_next) { - /* link the current TD with the next one */ - td->qtd_next = td_next->qtd_self; - } - } else { - /* - * BUG WARNING: The EHCI HW can use the - * qtd_next field instead of qtd_altnext when - * a short packet is received! We work this - * around in software by not queueing more - * than one job/TD at a time! - */ - td->qtd_next = terminate; + if (td_next) { + /* link the current TD with the next one */ + td->qtd_next = td_next->qtd_self; } - - td->qtd_altnext = terminate; + td->qtd_altnext = qtd_altnext; td->alt_next = td_alt_next; usb_pc_cpu_flush(td->page_cache); @@ -1799,9 +1801,15 @@ restart: /* setup alt next pointer, if any */ if (temp->last_frame) { td_alt_next = NULL; + qtd_altnext = terminate; } else { /* we use this field internally */ td_alt_next = td_next; + if (temp->setup_alt_next) { + qtd_altnext = td_next->qtd_self; + } else { + qtd_altnext = terminate; + } } /* restore */ @@ -1846,8 +1854,6 @@ ehci_setup_standard_chain(struct usb_xfer *xfer, ehci_qh_t **qh_last) temp.qtd_status = 0; temp.last_frame = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.can_use_next = (xfer->flags_int.control_xfr || - (UE_GET_DIR(xfer->endpointno) == UE_DIR_OUT)); if (xfer->flags_int.control_xfr) { if (xfer->endpoint->toggle_next) { @@ -1860,7 +1866,8 @@ ehci_setup_standard_chain(struct usb_xfer *xfer, ehci_qh_t **qh_last) temp.auto_data_toggle = 1; } - if (usbd_get_speed(xfer->xroot->udev) != USB_SPEED_HIGH) { + if ((xfer->xroot->udev->parent_hs_hub != NULL) || + (xfer->xroot->udev->address != 0)) { /* max 3 retries */ temp.qtd_status |= htohc32(temp.sc, EHCI_QTD_SET_CERR(3)); @@ -3063,8 +3070,7 @@ static const struct ehci_config_desc ehci_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, - 0 + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), @@ -3114,7 +3120,6 @@ ehci_roothub_exec(struct usb_device *udev, uint16_t i; uint16_t value; uint16_t index; - uint8_t l; usb_error_t err; USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); @@ -3318,20 +3323,23 @@ ehci_roothub_exec(struct usb_device *udev, err = USB_ERR_IOERROR; goto done; } - v = EOREAD4(sc, EHCI_HCSPARAMS); + v = EREAD4(sc, EHCI_HCSPARAMS); sc->sc_hub_desc.hubd = ehci_hubd; sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; - USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, - (EHCI_HCS_PPC(v) ? UHD_PWR_INDIVIDUAL : UHD_PWR_NO_SWITCH) | - (EHCI_HCS_P_INDICATOR(EREAD4(sc, EHCI_HCSPARAMS)) ? - UHD_PORT_IND : 0)); + + if (EHCI_HCS_PPC(v)) + i = UHD_PWR_INDIVIDUAL; + else + i = UHD_PWR_NO_SWITCH; + + if (EHCI_HCS_P_INDICATOR(v)) + i |= UHD_PORT_IND; + + USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, i); /* XXX can't find out? */ sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 200; - for (l = 0; l < sc->sc_noport; l++) { - /* XXX can't find out? */ - sc->sc_hub_desc.hubd.DeviceRemovable[l / 8] &= ~(1 << (l % 8)); - } + /* XXX don't know if ports are removable or not */ sc->sc_hub_desc.hubd.bDescLength = 8 + ((sc->sc_noport + 7) / 8); len = sc->sc_hub_desc.hubd.bDescLength; @@ -3804,7 +3812,7 @@ done: } static void -ehci_get_dma_delay(struct usb_bus *bus, uint32_t *pus) +ehci_get_dma_delay(struct usb_device *udev, uint32_t *pus) { /* * Wait until the hardware has finished any possible use of diff --git a/sys/dev/usb/controller/ehci.h b/sys/dev/usb/controller/ehci.h index 397e61d9c03..a8aa514a006 100644 --- a/sys/dev/usb/controller/ehci.h +++ b/sys/dev/usb/controller/ehci.h @@ -285,12 +285,14 @@ typedef struct ehci_fstn ehci_fstn_t; struct ehci_hw_softc { struct usb_page_cache pframes_pc; + struct usb_page_cache terminate_pc; struct usb_page_cache async_start_pc; struct usb_page_cache intr_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct usb_page_cache isoc_hs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct usb_page_cache isoc_fs_start_pc[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct usb_page pframes_pg; + struct usb_page terminate_pg; struct usb_page async_start_pg; struct usb_page intr_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT]; struct usb_page isoc_hs_start_pg[EHCI_VIRTUAL_FRAMELIST_COUNT]; @@ -329,6 +331,7 @@ typedef struct ehci_softc { bus_space_tag_t sc_io_tag; bus_space_handle_t sc_io_hdl; + uint32_t sc_terminate_self; /* TD short packet termination pointer */ uint32_t sc_eintrs; uint32_t sc_cmd; /* shadow of cmd register during * suspend */ diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c index c8d2d61a670..7e87762c32a 100644 --- a/sys/dev/usb/controller/ehci_pci.c +++ b/sys/dev/usb/controller/ehci_pci.c @@ -93,8 +93,6 @@ __FBSDID("$FreeBSD$"); #define PCI_EHCI_VENDORID_NVIDIA2 0x10DE #define PCI_EHCI_VENDORID_VIA 0x1106 -#define PCI_EHCI_BASE_REG 0x10 - static void ehci_pci_takecontroller(device_t self); static device_probe_t ehci_pci_probe; diff --git a/sys/dev/usb/controller/ehcireg.h b/sys/dev/usb/controller/ehcireg.h index 4da80c0488e..ab81f08cf30 100644 --- a/sys/dev/usb/controller/ehcireg.h +++ b/sys/dev/usb/controller/ehcireg.h @@ -55,7 +55,7 @@ /* EHCI capability registers */ #define EHCI_CAPLENGTH 0x00 /* RO Capability register length field */ -/* reserved 0x01 */ +#define EHCI_RESERVED 0x01 /* Reserved register */ #define EHCI_HCIVERSION 0x02 /* RO Interface version number */ #define EHCI_HCSPARAMS 0x04 /* RO Structural parameters */ #define EHCI_HCS_DEBUGPORT(x) (((x) >> 20) & 0xf) diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c index e4db7bf6857..8a3d36eebbb 100644 --- a/sys/dev/usb/controller/musb_otg.c +++ b/sys/dev/usb/controller/musb_otg.c @@ -2181,7 +2181,7 @@ static const struct musbotg_config_desc musbotg_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), diff --git a/sys/dev/usb/controller/ohci.c b/sys/dev/usb/controller/ohci.c index 0d630d76325..8c94b4152fd 100644 --- a/sys/dev/usb/controller/ohci.c +++ b/sys/dev/usb/controller/ohci.c @@ -2105,7 +2105,7 @@ struct ohci_config_desc ohci_confd = .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_FSHUB, + .bInterfaceProtocol = 0, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), @@ -2630,7 +2630,7 @@ ohci_xfer_unsetup(struct usb_xfer *xfer) } static void -ohci_get_dma_delay(struct usb_bus *bus, uint32_t *pus) +ohci_get_dma_delay(struct usb_device *udev, uint32_t *pus) { /* * Wait until hardware has finished any possible use of the diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c index 50fdb0d1e86..7fb72f3256b 100644 --- a/sys/dev/usb/controller/uhci.c +++ b/sys/dev/usb/controller/uhci.c @@ -3084,7 +3084,7 @@ uhci_xfer_unsetup(struct usb_xfer *xfer) } static void -uhci_get_dma_delay(struct usb_bus *bus, uint32_t *pus) +uhci_get_dma_delay(struct usb_device *udev, uint32_t *pus) { /* * Wait until hardware has finished any possible use of the diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index 1a9b4742ec2..71e7ef1da69 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -103,10 +103,15 @@ static driver_t usb_driver = { .size = 0, }; +/* Host Only Drivers */ DRIVER_MODULE(usbus, ohci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, uhci, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, ehci, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usbus, xhci, usb_driver, usb_devclass, 0, 0); + +/* Device Only Drivers */ DRIVER_MODULE(usbus, at91_udp, usb_driver, usb_devclass, 0, 0); +DRIVER_MODULE(usbus, musbotg, usb_driver, usb_devclass, 0, 0); DRIVER_MODULE(usbus, uss820, usb_driver, usb_devclass, 0, 0); /*------------------------------------------------------------------------* @@ -121,6 +126,16 @@ usb_probe(device_t dev) return (0); } +static void +usb_root_mount_rel(struct usb_bus *bus) +{ + if (bus->bus_roothold != NULL) { + DPRINTF("Releasing root mount hold %p\n", bus->bus_roothold); + root_mount_rel(bus->bus_roothold); + bus->bus_roothold = NULL; + } +} + /*------------------------------------------------------------------------* * usb_attach *------------------------------------------------------------------------*/ @@ -164,10 +179,7 @@ usb_detach(device_t dev) usb_callout_drain(&bus->power_wdog); /* Let the USB explore process detach all devices. */ - if (bus->bus_roothold != NULL) { - root_mount_rel(bus->bus_roothold); - bus->bus_roothold = NULL; - } + usb_root_mount_rel(bus); USB_BUS_LOCK(bus); if (usb_proc_msignal(&bus->explore_proc, @@ -244,10 +256,7 @@ usb_bus_explore(struct usb_proc_msg *pm) (udev->hub->explore) (udev); USB_BUS_LOCK(bus); } - if (bus->bus_roothold != NULL) { - root_mount_rel(bus->bus_roothold); - bus->bus_roothold = NULL; - } + usb_root_mount_rel(bus); } /*------------------------------------------------------------------------* @@ -351,8 +360,14 @@ usb_bus_attach(struct usb_proc_msg *pm) device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); break; + case USB_REV_3_0: + speed = USB_SPEED_SUPER; + device_printf(bus->bdev, "4.8Gbps Super Speed USB v3.0\n"); + break; + default: device_printf(bus->bdev, "Unsupported USB revision\n"); + usb_root_mount_rel(bus); return; } @@ -394,6 +409,7 @@ usb_bus_attach(struct usb_proc_msg *pm) if (err) { device_printf(bus->bdev, "Root HUB problem, error=%s\n", usbd_errstr(err)); + usb_root_mount_rel(bus); } /* set softc - we are ready */ diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c index 74221695f84..7d007604175 100644 --- a/sys/dev/usb/controller/uss820dci.c +++ b/sys/dev/usb/controller/uss820dci.c @@ -1740,7 +1740,7 @@ static const struct usb_device_descriptor uss820dci_devd = { .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_HUB, .bDeviceSubClass = UDSUBCLASS_HUB, - .bDeviceProtocol = UDPROTO_HSHUBSTT, + .bDeviceProtocol = UDPROTO_FSHUB, .bMaxPacketSize = 64, .bcdDevice = {0x00, 0x01}, .iManufacturer = 1, @@ -1776,7 +1776,7 @@ static const struct uss820dci_config_desc uss820dci_confd = { .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, - .bInterfaceProtocol = UIPROTO_HSHUBSTT, + .bInterfaceProtocol = 0, }, .endpd = { diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c new file mode 100644 index 00000000000..81c9704c96d --- /dev/null +++ b/sys/dev/usb/controller/xhci.c @@ -0,0 +1,3862 @@ +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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. + */ + +/* + * USB eXtensible Host Controller Interface, a.k.a. USB 3.0 controller. + * + * The XHCI 1.0 spec can be found at + * http://www.intel.com/technology/usb/download/xHCI_Specification_for_USB.pdf + * and the USB 3.0 spec at + * http://www.usb.org/developers/docs/usb_30_spec_060910.zip + */ + +/* + * A few words about the design implementation: This driver emulates + * the concept about TDs which is found in EHCI specification. This + * way we avoid too much diveration among USB drivers. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define USB_DEBUG_VAR xhcidebug + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define XHCI_BUS2SC(bus) \ + ((struct xhci_softc *)(((uint8_t *)(bus)) - \ + ((uint8_t *)&(((struct xhci_softc *)0)->sc_bus)))) + +#ifdef USB_DEBUG +static int xhcidebug = 0; + +SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI"); +SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW, + &xhcidebug, 0, "Debug level"); + +TUNABLE_INT("hw.usb.xhci.debug", &xhcidebug); + +#endif + +#define XHCI_INTR_ENDPT 1 + +struct xhci_std_temp { + struct xhci_softc *sc; + struct usb_page_cache *pc; + struct xhci_td *td; + struct xhci_td *td_next; + uint32_t len; + uint32_t offset; + uint32_t max_packet_size; + uint32_t average; + uint16_t isoc_delta; + uint16_t isoc_frame; + uint8_t shortpkt; + uint8_t multishort; + uint8_t last_frame; + uint8_t trb_type; + uint8_t direction; + uint8_t tbc; + uint8_t tlbpc; + uint8_t step_td; +}; + +static void xhci_do_poll(struct usb_bus *); +static void xhci_device_done(struct usb_xfer *, usb_error_t); +static void xhci_root_intr(struct xhci_softc *); +static void xhci_free_device_ext(struct usb_device *); +static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *, + struct usb_endpoint_descriptor *); +static usb_proc_callback_t xhci_configure_msg; +static usb_error_t xhci_configure_device(struct usb_device *); +static usb_error_t xhci_configure_endpoint(struct usb_device *, + struct usb_endpoint_descriptor *, uint64_t, uint16_t, + uint8_t, uint8_t, uint8_t, uint16_t, uint16_t); +static usb_error_t xhci_configure_mask(struct usb_device *, + uint32_t, uint8_t); +static usb_error_t xhci_cmd_evaluate_ctx(struct xhci_softc *, + uint64_t, uint8_t); +static void xhci_endpoint_doorbell(struct usb_xfer *); + +extern struct usb_bus_methods xhci_bus_methods; + +#ifdef USB_DEBUG +static void +xhci_dump_trb(struct xhci_trb *trb) +{ + DPRINTFN(5, "trb = %p\n", trb); + DPRINTFN(5, "qwTrb0 = 0x%016llx\n", (long long)le64toh(trb->qwTrb0)); + DPRINTFN(5, "dwTrb2 = 0x%08x\n", le32toh(trb->dwTrb2)); + DPRINTFN(5, "dwTrb3 = 0x%08x\n", le32toh(trb->dwTrb3)); +} + +static void +xhci_dump_endpoint(struct xhci_endp_ctx *pep) +{ + DPRINTFN(5, "pep = %p\n", pep); + DPRINTFN(5, "dwEpCtx0=0x%08x\n", pep->dwEpCtx0); + DPRINTFN(5, "dwEpCtx1=0x%08x\n", pep->dwEpCtx1); + DPRINTFN(5, "qwEpCtx2=0x%016llx\n", (long long)pep->qwEpCtx2); + DPRINTFN(5, "dwEpCtx4=0x%08x\n", pep->dwEpCtx4); + DPRINTFN(5, "dwEpCtx5=0x%08x\n", pep->dwEpCtx5); + DPRINTFN(5, "dwEpCtx6=0x%08x\n", pep->dwEpCtx6); + DPRINTFN(5, "dwEpCtx7=0x%08x\n", pep->dwEpCtx7); +} + +static void +xhci_dump_device(struct xhci_slot_ctx *psl) +{ + DPRINTFN(5, "psl = %p\n", psl); + DPRINTFN(5, "dwSctx0=0x%08x\n", psl->dwSctx0); + DPRINTFN(5, "dwSctx1=0x%08x\n", psl->dwSctx1); + DPRINTFN(5, "dwSctx2=0x%08x\n", psl->dwSctx2); + DPRINTFN(5, "dwSctx3=0x%08x\n", psl->dwSctx3); +} +#endif + +static void +xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) +{ + struct xhci_softc *sc = XHCI_BUS2SC(bus); + uint8_t i; + + cb(bus, &sc->sc_hw.root_pc, &sc->sc_hw.root_pg, + sizeof(struct xhci_hw_root), XHCI_PAGE_SIZE); + + cb(bus, &sc->sc_hw.ctx_pc, &sc->sc_hw.ctx_pg, + sizeof(struct xhci_dev_ctx_addr), XHCI_PAGE_SIZE); + + for (i = 0; i != XHCI_MAX_SCRATCHPADS; i++) { + cb(bus, &sc->sc_hw.scratch_pc[i], &sc->sc_hw.scratch_pg[i], + XHCI_PAGE_SIZE, XHCI_PAGE_SIZE); + } +} + +usb_error_t +xhci_start_controller(struct xhci_softc *sc) +{ + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + struct xhci_dev_ctx_addr *pdctxa; + uint64_t addr; + uint32_t temp; + uint16_t i; + + DPRINTF("\n"); + + sc->sc_capa_off = 0; + sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); + sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0x1F; + sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; + + DPRINTF("CAPLENGTH=0x%x\n", sc->sc_oper_off); + DPRINTF("RUNTIMEOFFSET=0x%x\n", sc->sc_runt_off); + DPRINTF("DOOROFFSET=0x%x\n", sc->sc_door_off); + + sc->sc_event_ccs = 1; + sc->sc_event_idx = 0; + sc->sc_command_ccs = 1; + sc->sc_command_idx = 0; + + DPRINTF("xHCI version = 0x%04x\n", XREAD2(sc, capa, XHCI_HCIVERSION)); + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + DPRINTF("HCS0 = 0x%08x\n", temp); + + if (XHCI_HCS0_CSZ(temp)) { + device_printf(sc->sc_bus.parent, "Driver does not " + "support 64-byte contexts."); + return (USB_ERR_IOERROR); + } + + /* Reset controller */ + XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, oper, XHCI_USBCMD) & + (XHCI_CMD_HCRST | XHCI_STS_CNR); + if (!temp) + break; + } + + if (temp) { + device_printf(sc->sc_bus.parent, "Controller " + "reset timeout.\n"); + return (USB_ERR_IOERROR); + } + + if (!(XREAD4(sc, oper, XHCI_PAGESIZE) & XHCI_PAGESIZE_4K)) { + device_printf(sc->sc_bus.parent, "Controller does " + "not support 4K page size.\n"); + return (USB_ERR_IOERROR); + } + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS1); + + i = XHCI_HCS1_N_PORTS(temp); + + if (i == 0) { + device_printf(sc->sc_bus.parent, "Invalid number " + "of ports: %u\n", i); + return (USB_ERR_IOERROR); + } + + sc->sc_noport = i; + sc->sc_noslot = XHCI_HCS1_DEVSLOT_MAX(temp); + + if (sc->sc_noslot > XHCI_MAX_DEVICES) + sc->sc_noslot = XHCI_MAX_DEVICES; + + /* setup number of device slots */ + + DPRINTF("CONFIG=0x%08x -> 0x%08x\n", + XREAD4(sc, oper, XHCI_CONFIG), sc->sc_noslot); + + XWRITE4(sc, oper, XHCI_CONFIG, sc->sc_noslot); + + DPRINTF("Max slots: %u\n", sc->sc_noslot); + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); + + sc->sc_noscratch = XHCI_HCS2_SPB_MAX(temp); + + if (sc->sc_noscratch > XHCI_MAX_SCRATCHPADS) { + device_printf(sc->sc_bus.parent, "XHCI request " + "too many scratchpads\n"); + return (USB_ERR_NOMEM); + } + + DPRINTF("Max scratch: %u\n", sc->sc_noscratch); + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS3); + + sc->sc_exit_lat_max = XHCI_HCS3_U1_DEL(temp) + + XHCI_HCS3_U2_DEL(temp) + 250 /* us */; + + temp = XREAD4(sc, oper, XHCI_USBSTS); + + /* clear interrupts */ + XWRITE4(sc, oper, XHCI_USBSTS, temp); + /* disable all device notifications */ + XWRITE4(sc, oper, XHCI_DNCTRL, 0); + + /* setup device context base address */ + usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); + pdctxa = buf_res.buffer; + memset(pdctxa, 0, sizeof(*pdctxa)); + + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_dev_ctx_addr *)0)->qwSpBufPtr[0]; + + /* slot 0 points to the table of scratchpad pointers */ + pdctxa->qwBaaDevCtxAddr[0] = htole64(addr); + + for (i = 0; i != sc->sc_noscratch; i++) { + struct usb_page_search buf_scp; + usbd_get_page(&sc->sc_hw.scratch_pc[i], 0, &buf_scp); + pdctxa->qwSpBufPtr[i] = htole64((uint64_t)buf_scp.physaddr); + } + + addr = buf_res.physaddr; + + XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); + XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); + XWRITE4(sc, oper, XHCI_DCBAAP_LO, (uint32_t)addr); + XWRITE4(sc, oper, XHCI_DCBAAP_HI, (uint32_t)(addr >> 32)); + + /* Setup event table size */ + + temp = XREAD4(sc, capa, XHCI_HCSPARAMS2); + + DPRINTF("HCS2=0x%08x\n", temp); + + temp = XHCI_HCS2_ERST_MAX(temp); + temp = 1U << temp; + if (temp > XHCI_MAX_RSEG) + temp = XHCI_MAX_RSEG; + + sc->sc_erst_max = temp; + + DPRINTF("ERSTSZ=0x%08x -> 0x%08x\n", + XREAD4(sc, runt, XHCI_ERSTSZ(0)), temp); + + XWRITE4(sc, runt, XHCI_ERSTSZ(0), XHCI_ERSTS_SET(temp)); + + /* Setup interrupt rate */ + XWRITE4(sc, runt, XHCI_IMOD(0), XHCI_IMOD_DEFAULT); + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.buffer; + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[0]; + + /* reset hardware root structure */ + memset(phwr, 0, sizeof(*phwr)); + + phwr->hwr_ring_seg[0].qwEvrsTablePtr = htole64(addr); + phwr->hwr_ring_seg[0].dwEvrsTableSize = htole32(XHCI_MAX_EVENTS); + + DPRINTF("ERDP(0)=0x%016llx\n", (unsigned long long)addr); + + XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); + XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); + + addr = (uint64_t)buf_res.physaddr; + + DPRINTF("ERSTBA(0)=0x%016llx\n", (unsigned long long)addr); + + XWRITE4(sc, runt, XHCI_ERSTBA_LO(0), (uint32_t)addr); + XWRITE4(sc, runt, XHCI_ERSTBA_HI(0), (uint32_t)(addr >> 32)); + + /* Setup interrupter registers */ + + temp = XREAD4(sc, runt, XHCI_IMAN(0)); + temp |= XHCI_IMAN_INTR_ENA; + XWRITE4(sc, runt, XHCI_IMAN(0), temp); + + /* setup command ring control base address */ + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[0]; + + DPRINTF("CRCR=0x%016llx\n", (unsigned long long)addr); + + XWRITE4(sc, oper, XHCI_CRCR_LO, ((uint32_t)addr) | XHCI_CRCR_LO_RCS); + XWRITE4(sc, oper, XHCI_CRCR_HI, (uint32_t)(addr >> 32)); + + phwr->hwr_commands[XHCI_MAX_COMMANDS - 1].qwTrb0 = htole64(addr); + + usb_bus_mem_flush_all(&sc->sc_bus, &xhci_iterate_hw_softc); + + /* Go! */ + XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_RS | + XHCI_CMD_INTE | XHCI_CMD_HSEE); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; + if (!temp) + break; + } + if (temp) { + XWRITE4(sc, oper, XHCI_USBCMD, 0); + device_printf(sc->sc_bus.parent, "Run timeout.\n"); + return (USB_ERR_IOERROR); + } + + /* catch any lost interrupts */ + xhci_do_poll(&sc->sc_bus); + + return (0); +} + +usb_error_t +xhci_halt_controller(struct xhci_softc *sc) +{ + uint32_t temp; + uint16_t i; + + DPRINTF("\n"); + + sc->sc_capa_off = 0; + sc->sc_oper_off = XREAD1(sc, capa, XHCI_CAPLENGTH); + sc->sc_runt_off = XREAD4(sc, capa, XHCI_RTSOFF) & ~0xF; + sc->sc_door_off = XREAD4(sc, capa, XHCI_DBOFF) & ~0x3; + + /* Halt controller */ + XWRITE4(sc, oper, XHCI_USBCMD, 0); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 1000); + temp = XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_HCH; + if (temp) + break; + } + + if (!temp) { + device_printf(sc->sc_bus.parent, "Controller halt timeout.\n"); + return (USB_ERR_IOERROR); + } + return (0); +} + +usb_error_t +xhci_init(struct xhci_softc *sc, device_t self) +{ + /* initialise some bus fields */ + sc->sc_bus.parent = self; + + /* set the bus revision */ + sc->sc_bus.usbrev = USB_REV_3_0; + + /* set up the bus struct */ + sc->sc_bus.methods = &xhci_bus_methods; + + /* setup devices array */ + sc->sc_bus.devices = sc->sc_devices; + sc->sc_bus.devices_max = XHCI_MAX_DEVICES; + + /* setup command queue mutex and condition varible */ + cv_init(&sc->sc_cmd_cv, "CMDQ"); + sx_init(&sc->sc_cmd_sx, "CMDQ lock"); + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_bus, + USB_GET_DMA_TAG(self), &xhci_iterate_hw_softc)) { + return (ENOMEM); + } + + sc->sc_config_msg[0].hdr.pm_callback = &xhci_configure_msg; + sc->sc_config_msg[0].bus = &sc->sc_bus; + sc->sc_config_msg[1].hdr.pm_callback = &xhci_configure_msg; + sc->sc_config_msg[1].bus = &sc->sc_bus; + + if (usb_proc_create(&sc->sc_config_proc, + &sc->sc_bus.bus_mtx, device_get_nameunit(self), USB_PRI_MED)) { + printf("WARNING: Creation of XHCI configure " + "callback process failed.\n"); + } + return (0); +} + +void +xhci_uninit(struct xhci_softc *sc) +{ + usb_proc_free(&sc->sc_config_proc); + + usb_bus_mem_free_all(&sc->sc_bus, &xhci_iterate_hw_softc); + + cv_destroy(&sc->sc_cmd_cv); + sx_destroy(&sc->sc_cmd_sx); +} + +void +xhci_suspend(struct xhci_softc *sc) +{ + /* XXX TODO */ +} + +void +xhci_resume(struct xhci_softc *sc) +{ + /* XXX TODO */ +} + +void +xhci_shutdown(struct xhci_softc *sc) +{ + DPRINTF("Stopping the XHCI\n"); + + xhci_halt_controller(sc); +} + +static usb_error_t +xhci_generic_done_sub(struct usb_xfer *xfer) +{ + struct xhci_td *td; + struct xhci_td *td_alt_next; + uint32_t len; + uint8_t status; + + td = xfer->td_transfer_cache; + td_alt_next = td->alt_next; + + if (xfer->aframes != xfer->nframes) + usbd_xfer_set_frame_len(xfer, xfer->aframes, 0); + + while (1) { + + usb_pc_cpu_invalidate(td->page_cache); + + status = td->status; + len = td->remainder; + + DPRINTFN(4, "xfer=%p[%u/%u] rem=%u/%u status=%u\n", + xfer, (unsigned int)xfer->aframes, + (unsigned int)xfer->nframes, + (unsigned int)len, (unsigned int)td->len, + (unsigned int)status); + + /* + * Verify the status length and + * add the length to "frlengths[]": + */ + if (len > td->len) { + /* should not happen */ + DPRINTF("Invalid status length, " + "0x%04x/0x%04x bytes\n", len, td->len); + status = XHCI_TRB_ERROR_LENGTH; + } else if (xfer->aframes != xfer->nframes) { + xfer->frlengths[xfer->aframes] += td->len - len; + } + /* Check for last transfer */ + if (((void *)td) == xfer->td_transfer_last) { + td = NULL; + break; + } + /* Check for transfer error */ + if (status != XHCI_TRB_ERROR_SHORT_PKT && + status != XHCI_TRB_ERROR_SUCCESS) { + /* the transfer is finished */ + td = NULL; + break; + } + /* Check for short transfer */ + if (len > 0) { + if (xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr) { + /* follow alt next */ + td = td->alt_next; + } else { + /* the transfer is finished */ + td = NULL; + } + break; + } + td = td->obj_next; + + if (td->alt_next != td_alt_next) { + /* this USB frame is complete */ + break; + } + } + + /* update transfer cache */ + + xfer->td_transfer_cache = td; + + return ((status == XHCI_TRB_ERROR_STALL) ? USB_ERR_STALLED : + (status != XHCI_TRB_ERROR_SHORT_PKT && + status != XHCI_TRB_ERROR_SUCCESS) ? USB_ERR_IOERROR : + USB_ERR_NORMAL_COMPLETION); +} + +static void +xhci_generic_done(struct usb_xfer *xfer) +{ + usb_error_t err = 0; + + DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", + xfer, xfer->endpoint); + + /* reset scanner */ + + xfer->td_transfer_cache = xfer->td_transfer_first; + + if (xfer->flags_int.control_xfr) { + + if (xfer->flags_int.control_hdr) + err = xhci_generic_done_sub(xfer); + + xfer->aframes = 1; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + + while (xfer->aframes != xfer->nframes) { + + err = xhci_generic_done_sub(xfer); + xfer->aframes++; + + if (xfer->td_transfer_cache == NULL) + goto done; + } + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) + err = xhci_generic_done_sub(xfer); +done: + /* transfer is complete */ + xhci_device_done(xfer, err); +} + +static void +xhci_activate_transfer(struct usb_xfer *xfer) +{ + struct xhci_td *td; + + td = xfer->td_transfer_cache; + + usb_pc_cpu_invalidate(td->page_cache); + + if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { + + /* activate the transfer */ + + td->td_trb[0].dwTrb3 |= htole32(XHCI_TRB_3_CYCLE_BIT); + usb_pc_cpu_flush(td->page_cache); + + xhci_endpoint_doorbell(xfer); + } +} + +static void +xhci_skip_transfer(struct usb_xfer *xfer) +{ + struct xhci_td *td; + struct xhci_td *td_last; + + td = xfer->td_transfer_cache; + td_last = xfer->td_transfer_last; + + td = td->alt_next; + + usb_pc_cpu_invalidate(td->page_cache); + + if (!(td->td_trb[0].dwTrb3 & htole32(XHCI_TRB_3_CYCLE_BIT))) { + + usb_pc_cpu_invalidate(td_last->page_cache); + + /* copy LINK TRB to current waiting location */ + + td->td_trb[0].qwTrb0 = td_last->td_trb[td_last->ntrb].qwTrb0; + td->td_trb[0].dwTrb2 = td_last->td_trb[td_last->ntrb].dwTrb2; + usb_pc_cpu_flush(td->page_cache); + + td->td_trb[0].dwTrb3 = td_last->td_trb[td_last->ntrb].dwTrb3; + usb_pc_cpu_flush(td->page_cache); + + xhci_endpoint_doorbell(xfer); + } +} + +/*------------------------------------------------------------------------* + * xhci_check_transfer + *------------------------------------------------------------------------*/ +static void +xhci_check_transfer(struct xhci_softc *sc, struct xhci_trb *trb) +{ + int64_t offset; + uint64_t td_event; + uint32_t temp; + uint32_t remainder; + uint8_t status; + uint8_t halted; + uint8_t epno; + uint8_t index; + uint8_t i; + + /* decode TRB */ + td_event = le64toh(trb->qwTrb0); + temp = le32toh(trb->dwTrb2); + + remainder = XHCI_TRB_2_REM_GET(temp); + status = XHCI_TRB_2_ERROR_GET(temp); + + temp = le32toh(trb->dwTrb3); + epno = XHCI_TRB_3_EP_GET(temp); + index = XHCI_TRB_3_SLOT_GET(temp); + + /* check if error means halted */ + halted = (status != XHCI_TRB_ERROR_SHORT_PKT && + status != XHCI_TRB_ERROR_SUCCESS); + + DPRINTF("slot=%u epno=%u remainder=%u status=%u\n", + index, epno, remainder, status); + + if (index > sc->sc_noslot) { + DPRINTF("Invalid slot.\n"); + return; + } + + if ((epno == 0) || (epno >= XHCI_MAX_ENDPOINTS)) { + DPRINTF("Invalid endpoint.\n"); + return; + } + + /* try to find the USB transfer that generated the event */ + for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) { + struct usb_xfer *xfer; + struct xhci_td *td; + struct xhci_endpoint_ext *pepext; + + pepext = &sc->sc_hw.devs[index].endp[epno]; + + xfer = pepext->xfer[i]; + if (xfer == NULL) + continue; + + td = xfer->td_transfer_cache; + + DPRINTFN(5, "Checking if 0x%016llx == (0x%016llx .. 0x%016llx)\n", + (long long)td_event, + (long long)td->td_self, + (long long)td->td_self + sizeof(td->td_trb)); + + /* + * NOTE: Some XHCI implementations might not trigger + * an event on the last LINK TRB so we need to + * consider both the last and second last event + * address as conditions for a successful transfer. + * + * NOTE: We assume that the XHCI will only trigger one + * event per chain of TRBs. + */ + + offset = td_event - td->td_self; + + if (offset >= 0 && + offset < sizeof(td->td_trb)) { + + usb_pc_cpu_invalidate(td->page_cache); + + /* compute rest of remainder, if any */ + for (i = (offset / 16) + 1; i < td->ntrb; i++) { + temp = le32toh(td->td_trb[i].dwTrb2); + remainder += XHCI_TRB_2_BYTES_GET(temp); + } + + DPRINTFN(5, "New remainder: %u\n", remainder); + + /* clear isochronous transfer errors */ + if (xfer->flags_int.isochronous_xfr) { + if (halted) { + halted = 0; + status = XHCI_TRB_ERROR_SUCCESS; + remainder = td->len; + } + } + + /* "td->remainder" is verified later */ + td->remainder = remainder; + td->status = status; + + usb_pc_cpu_flush(td->page_cache); + + /* + * 1) Last transfer descriptor makes the + * transfer done + */ + if (((void *)td) == xfer->td_transfer_last) { + DPRINTF("TD is last\n"); + xhci_generic_done(xfer); + break; + } + + /* + * 2) Any kind of error makes the transfer + * done + */ + if (halted) { + DPRINTF("TD has I/O error\n"); + xhci_generic_done(xfer); + break; + } + + /* + * 3) If there is no alternate next transfer, + * a short packet also makes the transfer done + */ + if (td->remainder > 0) { + DPRINTF("TD has short pkt\n"); + if (xfer->flags_int.short_frames_ok || + xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr) { + /* follow the alt next */ + xfer->td_transfer_cache = td->alt_next; + xhci_activate_transfer(xfer); + break; + } + xhci_skip_transfer(xfer); + xhci_generic_done(xfer); + break; + } + + /* + * 4) Transfer complete - go to next TD + */ + DPRINTF("Following next TD\n"); + xfer->td_transfer_cache = td->obj_next; + xhci_activate_transfer(xfer); + break; /* there should only be one match */ + } + } +} + +static void +xhci_check_command(struct xhci_softc *sc, struct xhci_trb *trb) +{ + if (sc->sc_cmd_addr == trb->qwTrb0) { + DPRINTF("Received command event\n"); + sc->sc_cmd_result[0] = trb->dwTrb2; + sc->sc_cmd_result[1] = trb->dwTrb3; + cv_signal(&sc->sc_cmd_cv); + } +} + +static void +xhci_interrupt_poll(struct xhci_softc *sc) +{ + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + uint64_t addr; + uint32_t temp; + uint16_t i; + uint8_t event; + uint8_t j; + uint8_t k; + uint8_t t; + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.buffer; + + /* Receive any events */ + + usb_pc_cpu_invalidate(&sc->sc_hw.root_pc); + + i = sc->sc_event_idx; + j = sc->sc_event_ccs; + t = 2; + + while (1) { + + temp = le32toh(phwr->hwr_events[i].dwTrb3); + + k = (temp & XHCI_TRB_3_CYCLE_BIT) ? 1 : 0; + + if (j != k) + break; + + event = XHCI_TRB_3_TYPE_GET(temp); + + DPRINTFN(10, "event[%u] = %u (0x%016llx 0x%08lx 0x%08lx)\n", + i, event, (long long)le64toh(phwr->hwr_events[i].qwTrb0), + (long)le32toh(phwr->hwr_events[i].dwTrb2), + (long)le32toh(phwr->hwr_events[i].dwTrb3)); + + switch (event) { + case XHCI_TRB_EVENT_TRANSFER: + xhci_check_transfer(sc, &phwr->hwr_events[i]); + break; + case XHCI_TRB_EVENT_CMD_COMPLETE: + xhci_check_command(sc, &phwr->hwr_events[i]); + break; + default: + DPRINTF("Unhandled event = %u\n", event); + break; + } + + i++; + + if (i == XHCI_MAX_EVENTS) { + i = 0; + j ^= 1; + + /* check for timeout */ + if (!--t) + break; + } + } + + sc->sc_event_idx = i; + sc->sc_event_ccs = j; + + /* + * NOTE: The Event Ring Dequeue Pointer Register is 64-bit + * latched. That means to activate the register we need to + * write both the low and high double word of the 64-bit + * register. + */ + + addr = (uint32_t)buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_events[i]; + + /* try to clear busy bit */ + addr |= XHCI_ERDP_LO_BUSY; + + XWRITE4(sc, runt, XHCI_ERDP_LO(0), (uint32_t)addr); + XWRITE4(sc, runt, XHCI_ERDP_HI(0), (uint32_t)(addr >> 32)); +} + +static usb_error_t +xhci_do_command(struct xhci_softc *sc, struct xhci_trb *trb, + uint16_t timeout_ms) +{ + struct usb_page_search buf_res; + struct xhci_hw_root *phwr; + uint64_t addr; + uint32_t temp; + uint8_t i; + uint8_t j; + int err; + + XHCI_CMD_ASSERT_LOCKED(sc); + + /* get hardware root structure */ + + usbd_get_page(&sc->sc_hw.root_pc, 0, &buf_res); + + phwr = buf_res.buffer; + + /* Queue command */ + + USB_BUS_LOCK(&sc->sc_bus); + + i = sc->sc_command_idx; + j = sc->sc_command_ccs; + + DPRINTFN(10, "command[%u] = %u (0x%016llx, 0x%08lx, 0x%08lx)\n", + i, XHCI_TRB_3_TYPE_GET(le32toh(trb->dwTrb3)), + (long long)le64toh(trb->qwTrb0), + (long)le32toh(trb->dwTrb2), + (long)le32toh(trb->dwTrb3)); + + phwr->hwr_commands[i].qwTrb0 = trb->qwTrb0; + phwr->hwr_commands[i].dwTrb2 = trb->dwTrb2; + + usb_pc_cpu_flush(&sc->sc_hw.root_pc); + + temp = trb->dwTrb3; + + if (j) + temp |= htole32(XHCI_TRB_3_CYCLE_BIT); + else + temp &= ~htole32(XHCI_TRB_3_CYCLE_BIT); + + temp &= ~htole32(XHCI_TRB_3_TC_BIT); + + phwr->hwr_commands[i].dwTrb3 = temp; + + usb_pc_cpu_flush(&sc->sc_hw.root_pc); + + addr = buf_res.physaddr; + addr += (uintptr_t)&((struct xhci_hw_root *)0)->hwr_commands[i]; + + sc->sc_cmd_addr = htole64(addr); + + i++; + + if (i == (XHCI_MAX_COMMANDS - 1)) { + + if (j) { + temp = htole32(XHCI_TRB_3_TC_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | + XHCI_TRB_3_CYCLE_BIT); + } else { + temp = htole32(XHCI_TRB_3_TC_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); + } + + phwr->hwr_commands[i].dwTrb3 = temp; + + usb_pc_cpu_flush(&sc->sc_hw.root_pc); + + i = 0; + j ^= 1; + } + + sc->sc_command_idx = i; + sc->sc_command_ccs = j; + + XWRITE4(sc, door, XHCI_DOORBELL(0), 0); + + err = cv_timedwait(&sc->sc_cmd_cv, &sc->sc_bus.bus_mtx, + USB_MS_TO_TICKS(timeout_ms)); + + if (err) { + DPRINTFN(0, "Command timeout!\n"); + err = USB_ERR_TIMEOUT; + trb->dwTrb2 = 0; + trb->dwTrb3 = 0; + } else { + temp = le32toh(sc->sc_cmd_result[0]); + if (XHCI_TRB_2_ERROR_GET(temp) != XHCI_TRB_ERROR_SUCCESS) + err = USB_ERR_IOERROR; + + trb->dwTrb2 = sc->sc_cmd_result[0]; + trb->dwTrb3 = sc->sc_cmd_result[1]; + } + + USB_BUS_UNLOCK(&sc->sc_bus); + + return (err); +} + +#if 0 +static usb_error_t +xhci_cmd_nop(struct xhci_softc *sc) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NOOP); + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} +#endif + +static usb_error_t +xhci_cmd_enable_slot(struct xhci_softc *sc, uint8_t *pslot) +{ + struct xhci_trb trb; + uint32_t temp; + usb_error_t err; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + trb.dwTrb3 = htole32(XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ENABLE_SLOT)); + + err = xhci_do_command(sc, &trb, 50 /* ms */); + if (err) + goto done; + + temp = le32toh(trb.dwTrb3); + + *pslot = XHCI_TRB_3_SLOT_GET(temp); + +done: + return (err); +} + +static usb_error_t +xhci_cmd_disable_slot(struct xhci_softc *sc, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT) | + XHCI_TRB_3_SLOT_SET(slot_id); + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_set_address(struct xhci_softc *sc, uint64_t input_ctx, + uint8_t bsr, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = htole64(input_ctx); + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_ADDRESS_DEVICE) | + XHCI_TRB_3_SLOT_SET(slot_id); + + if (bsr) + temp |= XHCI_TRB_3_BSR_BIT; + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 500 /* ms */)); +} + +static usb_error_t +xhci_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t address) +{ + struct usb_page_search buf_inp; + struct usb_page_search buf_dev; + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct xhci_hw_dev *hdev; + struct xhci_dev_ctx *pdev; + struct xhci_endpoint_ext *pepext; + uint16_t mps; + usb_error_t err; + uint8_t index; + + /* the root HUB case is not handled here */ + if (udev->parent_hub == NULL) + return (USB_ERR_INVAL); + + index = udev->controller_slot_id; + + hdev = &sc->sc_hw.devs[index]; + + if (mtx != NULL) + mtx_unlock(mtx); + + XHCI_CMD_LOCK(sc); + + switch (hdev->state) { + case XHCI_ST_DEFAULT: + case XHCI_ST_ENABLED: + + hdev->state = XHCI_ST_ENABLED; + + /* set configure mask to slot and EP0 */ + xhci_configure_mask(udev, 3, 0); + + /* configure input slot context structure */ + err = xhci_configure_device(udev); + + if (err != 0) { + DPRINTF("Could not configure device\n"); + break; + } + + /* configure input endpoint context structure */ + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + mps = 8; + break; + case USB_SPEED_HIGH: + mps = 64; + break; + default: + mps = 512; + break; + } + + pepext = xhci_get_endpoint_ext(udev, + &udev->ctrl_ep_desc); + err = xhci_configure_endpoint(udev, + &udev->ctrl_ep_desc, pepext->physaddr, + 0, 1, 1, 0, mps, mps); + + if (err != 0) { + DPRINTF("Could not configure default endpoint\n"); + break; + } + + /* execute set address command */ + usbd_get_page(&hdev->input_pc, 0, &buf_inp); + + err = xhci_cmd_set_address(sc, buf_inp.physaddr, + (address == 0), index); + + if (err != 0) { + DPRINTF("Could not set address " + "for slot %u.\n", index); + if (address != 0) + break; + } + + /* update device address to new value */ + + usbd_get_page(&hdev->device_pc, 0, &buf_dev); + pdev = buf_dev.buffer; + usb_pc_cpu_invalidate(&hdev->device_pc); + udev->address = XHCI_SCTX_3_DEV_ADDR_GET(pdev->ctx_slot.dwSctx3); + + /* update device state to new value */ + + if (address != 0) + hdev->state = XHCI_ST_ADDRESSED; + else + hdev->state = XHCI_ST_DEFAULT; + break; + + default: + DPRINTF("Wrong state for set address.\n"); + err = USB_ERR_IOERROR; + break; + } + XHCI_CMD_UNLOCK(sc); + + if (mtx != NULL) + mtx_lock(mtx); + + return (err); +} + +static usb_error_t +xhci_cmd_configure_ep(struct xhci_softc *sc, uint64_t input_ctx, + uint8_t deconfigure, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = htole64(input_ctx); + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP) | + XHCI_TRB_3_SLOT_SET(slot_id); + + if (deconfigure) + temp |= XHCI_TRB_3_DCEP_BIT; + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_evaluate_ctx(struct xhci_softc *sc, uint64_t input_ctx, + uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = htole64(input_ctx); + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_EVALUATE_CTX) | + XHCI_TRB_3_SLOT_SET(slot_id); + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_reset_ep(struct xhci_softc *sc, uint8_t preserve, + uint8_t ep_id, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_EP) | + XHCI_TRB_3_SLOT_SET(slot_id) | + XHCI_TRB_3_EP_SET(ep_id); + + if (preserve) + temp |= XHCI_TRB_3_PRSV_BIT; + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_set_tr_dequeue_ptr(struct xhci_softc *sc, uint64_t dequeue_ptr, + uint16_t stream_id, uint8_t ep_id, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = htole64(dequeue_ptr); + + temp = XHCI_TRB_2_STREAM_SET(stream_id); + trb.dwTrb2 = htole32(temp); + + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SET_TR_DEQUEUE) | + XHCI_TRB_3_SLOT_SET(slot_id) | + XHCI_TRB_3_EP_SET(ep_id); + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_stop_ep(struct xhci_softc *sc, uint8_t suspend, + uint8_t ep_id, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP) | + XHCI_TRB_3_SLOT_SET(slot_id) | + XHCI_TRB_3_EP_SET(ep_id); + + if (suspend) + temp |= XHCI_TRB_3_SUSP_EP_BIT; + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +static usb_error_t +xhci_cmd_reset_dev(struct xhci_softc *sc, uint8_t slot_id) +{ + struct xhci_trb trb; + uint32_t temp; + + DPRINTF("\n"); + + trb.qwTrb0 = 0; + trb.dwTrb2 = 0; + temp = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_RESET_DEVICE) | + XHCI_TRB_3_SLOT_SET(slot_id); + + trb.dwTrb3 = htole32(temp); + + return (xhci_do_command(sc, &trb, 50 /* ms */)); +} + +/*------------------------------------------------------------------------* + * xhci_interrupt - XHCI interrupt handler + *------------------------------------------------------------------------*/ +void +xhci_interrupt(struct xhci_softc *sc) +{ + uint32_t status; + uint32_t temp; + + USB_BUS_LOCK(&sc->sc_bus); + + status = XREAD4(sc, oper, XHCI_USBSTS); + + /* acknowledge interrupts */ + + XWRITE4(sc, oper, XHCI_USBSTS, status); + + temp = XREAD4(sc, runt, XHCI_IMAN(0)); + + /* acknowledge pending event */ + + XWRITE4(sc, runt, XHCI_IMAN(0), temp); + + DPRINTFN(16, "real interrupt (sts=0x%08x, " + "iman=0x%08x)\n", status, temp); + + if (status != 0) { + if (status & XHCI_STS_PCD) { + xhci_root_intr(sc); + } + + if (status & XHCI_STS_HCH) { + printf("%s: host controller halted\n", + __FUNCTION__); + } + + if (status & XHCI_STS_HSE) { + printf("%s: host system error\n", + __FUNCTION__); + } + + if (status & XHCI_STS_HCE) { + printf("%s: host controller error\n", + __FUNCTION__); + } + } + + xhci_interrupt_poll(sc); + + USB_BUS_UNLOCK(&sc->sc_bus); +} + +/*------------------------------------------------------------------------* + * xhci_timeout - XHCI timeout handler + *------------------------------------------------------------------------*/ +static void +xhci_timeout(void *arg) +{ + struct usb_xfer *xfer = arg; + + DPRINTF("xfer=%p\n", xfer); + + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); + + /* transfer is transferred */ + xhci_device_done(xfer, USB_ERR_TIMEOUT); +} + +static void +xhci_do_poll(struct usb_bus *bus) +{ + struct xhci_softc *sc = XHCI_BUS2SC(bus); + + USB_BUS_LOCK(&sc->sc_bus); + xhci_interrupt_poll(sc); + USB_BUS_UNLOCK(&sc->sc_bus); +} + +static void +xhci_setup_generic_chain_sub(struct xhci_std_temp *temp) +{ + struct usb_page_search buf_res; + struct xhci_td *td; + struct xhci_td *td_next; + struct xhci_td *td_alt_next; + uint32_t buf_offset; + uint32_t average; + uint32_t len_old; + uint32_t dword; + uint8_t shortpkt_old; + uint8_t precompute; + uint8_t x; + + td_alt_next = NULL; + buf_offset = 0; + shortpkt_old = temp->shortpkt; + len_old = temp->len; + precompute = 1; + +restart: + + td = temp->td; + td_next = temp->td_next; + + while (1) { + + if (temp->len == 0) { + + if (temp->shortpkt) + break; + + /* send a Zero Length Packet, ZLP, last */ + + temp->shortpkt = 1; + average = 0; + + } else { + + average = temp->average; + + if (temp->len < average) { + if (temp->len % temp->max_packet_size) { + temp->shortpkt = 1; + } + average = temp->len; + } + } + + if (td_next == NULL) + panic("%s: out of XHCI transfer descriptors!", __FUNCTION__); + + /* get next TD */ + + td = td_next; + td_next = td->obj_next; + + /* check if we are pre-computing */ + + if (precompute) { + + /* update remaining length */ + + temp->len -= average; + + continue; + } + /* fill out current TD */ + + td->len = average; + td->remainder = 0; + td->status = 0; + + /* update remaining length */ + + temp->len -= average; + + /* reset TRB index */ + + x = 0; + + if (temp->trb_type == XHCI_TRB_TYPE_SETUP_STAGE) { + /* immediate data */ + + if (average > 8) + average = 8; + + td->td_trb[0].qwTrb0 = 0; + + usbd_copy_out(temp->pc, temp->offset + buf_offset, + (uint8_t *)(uintptr_t)&td->td_trb[0].qwTrb0, + average); + + dword = XHCI_TRB_2_BYTES_SET(8) | + XHCI_TRB_2_TDSZ_SET(0) | + XHCI_TRB_2_IRQ_SET(0); + + td->td_trb[0].dwTrb2 = htole32(dword); + + dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_SETUP_STAGE) | + XHCI_TRB_3_IDT_BIT | XHCI_TRB_3_CYCLE_BIT; + + /* check wLength */ + if (td->td_trb[0].qwTrb0 & + htole64(XHCI_TRB_0_WLENGTH_MASK)) { + if (td->td_trb[0].qwTrb0 & htole64(1)) + dword |= XHCI_TRB_3_TRT_IN; + else + dword |= XHCI_TRB_3_TRT_OUT; + } + + td->td_trb[0].dwTrb3 = htole32(dword); +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif + x++; + + } else do { + + uint32_t npkt; + + /* fill out buffer pointers */ + + if (average == 0) { + npkt = 1; + memset(&buf_res, 0, sizeof(buf_res)); + } else { + usbd_get_page(temp->pc, temp->offset + + buf_offset, &buf_res); + + /* get length to end of page */ + if (buf_res.length > average) + buf_res.length = average; + + /* check for maximum length */ + if (buf_res.length > XHCI_TD_PAGE_SIZE) + buf_res.length = XHCI_TD_PAGE_SIZE; + + /* setup npkt */ + npkt = (average + temp->max_packet_size - 1) / + temp->max_packet_size; + + if (npkt > 31) + npkt = 31; + } + + /* fill out TRB's */ + td->td_trb[x].qwTrb0 = + htole64((uint64_t)buf_res.physaddr); + + dword = + XHCI_TRB_2_BYTES_SET(buf_res.length) | + XHCI_TRB_2_TDSZ_SET(npkt) | + XHCI_TRB_2_IRQ_SET(0); + + td->td_trb[x].dwTrb2 = htole32(dword); + + dword = XHCI_TRB_3_CHAIN_BIT | XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_TYPE_SET(temp->trb_type) | + XHCI_TRB_3_FRID_SET(temp->isoc_frame / 8) | + XHCI_TRB_3_TBC_SET(temp->tbc) | + XHCI_TRB_3_TLBPC_SET(temp->tlbpc); + + if (temp->direction == UE_DIR_IN) { + dword |= XHCI_TRB_3_DIR_IN; + + /* + * NOTE: Only the SETUP stage should + * use the IDT bit. Else transactions + * can be sent using the wrong data + * toggle value. + */ + if (temp->trb_type != + XHCI_TRB_TYPE_SETUP_STAGE && + temp->trb_type != + XHCI_TRB_TYPE_STATUS_STAGE) + dword |= XHCI_TRB_3_ISP_BIT; + } + + td->td_trb[x].dwTrb3 = htole32(dword); + + average -= buf_res.length; + buf_offset += buf_res.length; +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif + x++; + + } while (average != 0); + + td->td_trb[x-1].dwTrb3 |= htole32(XHCI_TRB_3_IOC_BIT); + + /* store number of data TRB's */ + + td->ntrb = x; + + DPRINTF("NTRB=%u\n", x); + + /* fill out link TRB */ + + if (td_next != NULL) { + /* link the current TD with the next one */ + td->td_trb[x].qwTrb0 = htole64((uint64_t)td_next->td_self); + DPRINTF("LINK=0x%08llx\n", (long long)td_next->td_self); + } else { + /* this field will get updated later */ + DPRINTF("NOLINK\n"); + } + + dword = XHCI_TRB_2_IRQ_SET(0); + + td->td_trb[x].dwTrb2 = htole32(dword); + + dword = XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) | + XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_IOC_BIT; + + td->td_trb[x].dwTrb3 = htole32(dword); + + td->alt_next = td_alt_next; +#ifdef USB_DEBUG + xhci_dump_trb(&td->td_trb[x]); +#endif + usb_pc_cpu_flush(td->page_cache); + } + + if (precompute) { + precompute = 0; + + /* setup alt next pointer, if any */ + if (temp->last_frame) { + td_alt_next = NULL; + } else { + /* we use this field internally */ + td_alt_next = td_next; + } + + /* restore */ + temp->shortpkt = shortpkt_old; + temp->len = len_old; + goto restart; + } + + /* remove cycle bit from first if we are stepping the TRBs */ + if (temp->step_td) + td->td_trb[0].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT); + + /* remove chain bit because this is the last TRB in the chain */ + td->td_trb[td->ntrb - 1].dwTrb2 &= ~htole32(XHCI_TRB_2_TDSZ_SET(15)); + td->td_trb[td->ntrb - 1].dwTrb3 &= ~htole32(XHCI_TRB_3_CHAIN_BIT); + + usb_pc_cpu_flush(td->page_cache); + + temp->td = td; + temp->td_next = td_next; +} + +static void +xhci_setup_generic_chain(struct usb_xfer *xfer) +{ + struct xhci_std_temp temp; + struct xhci_td *td; + uint32_t x; + uint32_t y; + uint8_t mult; + + temp.step_td = 0; + temp.tbc = 0; + temp.tlbpc = 0; + temp.average = xfer->max_hc_frame_size; + temp.max_packet_size = xfer->max_packet_size; + temp.sc = XHCI_BUS2SC(xfer->xroot->bus); + temp.pc = NULL; + temp.last_frame = 0; + temp.offset = 0; + temp.multishort = xfer->flags_int.isochronous_xfr || + xfer->flags_int.control_xfr || + xfer->flags_int.short_frames_ok; + + /* toggle the DMA set we are using */ + xfer->flags_int.curr_dma_set ^= 1; + + /* get next DMA set */ + td = xfer->td_start[xfer->flags_int.curr_dma_set]; + + temp.td = NULL; + temp.td_next = td; + + xfer->td_transfer_first = td; + xfer->td_transfer_cache = td; + + if (xfer->flags_int.isochronous_xfr) { + uint8_t shift; + + /* compute multiplier for ISOCHRONOUS transfers */ + mult = xfer->endpoint->ecomp ? + (xfer->endpoint->ecomp->bmAttributes & 3) : 0; + /* check for USB 2.0 multiplier */ + if (mult == 0) { + mult = (xfer->endpoint->edesc-> + wMaxPacketSize[1] >> 3) & 3; + } + /* range check */ + if (mult > 2) + mult = 3; + else + mult++; + + x = XREAD4(temp.sc, runt, XHCI_MFINDEX); + + DPRINTF("MFINDEX=0x%08x\n", x); + + switch (usbd_get_speed(xfer->xroot->udev)) { + case USB_SPEED_FULL: + shift = 3; + temp.isoc_delta = 8; /* 1ms */ + x += temp.isoc_delta - 1; + x &= ~(temp.isoc_delta - 1); + break; + default: + shift = usbd_xfer_get_fps_shift(xfer); + temp.isoc_delta = 1U << shift; + x += temp.isoc_delta - 1; + x &= ~(temp.isoc_delta - 1); + /* simple frame load balancing */ + x += xfer->endpoint->usb_uframe; + break; + } + + y = XHCI_MFINDEX_GET(x - xfer->endpoint->isoc_next); + + if ((xfer->endpoint->is_synced == 0) || + (y < (xfer->nframes << shift)) || + (XHCI_MFINDEX_GET(-y) >= (128 * 8))) { + /* + * If there is data underflow or the pipe + * queue is empty we schedule the transfer a + * few frames ahead of the current frame + * position. Else two isochronous transfers + * might overlap. + */ + xfer->endpoint->isoc_next = XHCI_MFINDEX_GET(x + (3 * 8)); + xfer->endpoint->is_synced = 1; + DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); + } + + /* compute isochronous completion time */ + + y = XHCI_MFINDEX_GET(xfer->endpoint->isoc_next - (x & ~7)); + + xfer->isoc_time_complete = + usb_isoc_time_expand(&temp.sc->sc_bus, x / 8) + + (y / 8) + (((xfer->nframes << shift) + 7) / 8); + + x = 0; + temp.isoc_frame = xfer->endpoint->isoc_next; + temp.trb_type = XHCI_TRB_TYPE_ISOCH; + + xfer->endpoint->isoc_next += xfer->nframes << shift; + + } else if (xfer->flags_int.control_xfr) { + + /* check if we should prepend a setup message */ + + if (xfer->flags_int.control_hdr) { + + temp.len = xfer->frlengths[0]; + temp.pc = xfer->frbuffers + 0; + temp.shortpkt = temp.len ? 1 : 0; + temp.trb_type = XHCI_TRB_TYPE_SETUP_STAGE; + temp.direction = 0; + + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) + temp.last_frame = 1; + } + + xhci_setup_generic_chain_sub(&temp); + } + x = 1; + mult = 1; + temp.isoc_delta = 0; + temp.isoc_frame = 0; + temp.trb_type = XHCI_TRB_TYPE_DATA_STAGE; + } else { + x = 0; + mult = 1; + temp.isoc_delta = 0; + temp.isoc_frame = 0; + temp.trb_type = XHCI_TRB_TYPE_NORMAL; + } + + if (x != xfer->nframes) { + /* setup page_cache pointer */ + temp.pc = xfer->frbuffers + x; + /* set endpoint direction */ + temp.direction = UE_GET_DIR(xfer->endpointno); + } + + while (x != xfer->nframes) { + + /* DATA0 / DATA1 message */ + + temp.len = xfer->frlengths[x]; + temp.step_td = ((xfer->endpointno & UE_DIR_IN) && + x != 0 && temp.multishort == 0); + + x++; + + if (x == xfer->nframes) { + if (xfer->flags_int.control_xfr) { + /* no STATUS stage yet, DATA is last */ + if (xfer->flags_int.control_act) + temp.last_frame = 1; + } else { + temp.last_frame = 1; + } + } + if (temp.len == 0) { + + /* make sure that we send an USB packet */ + + temp.shortpkt = 0; + + temp.tbc = 0; + temp.tlbpc = mult - 1; + + } else if (xfer->flags_int.isochronous_xfr) { + + uint8_t tdpc; + + /* isochronous transfers don't have short packet termination */ + + temp.shortpkt = 1; + + /* isochronous transfers have a transfer limit */ + + if (temp.len > xfer->max_frame_size) + temp.len = xfer->max_frame_size; + + /* compute TD packet count */ + tdpc = (temp.len + xfer->max_packet_size - 1) / + xfer->max_packet_size; + + temp.tbc = ((tdpc + mult - 1) / mult) - 1; + temp.tlbpc = (tdpc % mult); + + if (temp.tlbpc == 0) + temp.tlbpc = mult - 1; + else + temp.tlbpc--; + } else { + + /* regular data transfer */ + + temp.shortpkt = xfer->flags.force_short_xfer ? 0 : 1; + } + + xhci_setup_generic_chain_sub(&temp); + + if (xfer->flags_int.isochronous_xfr) { + temp.offset += xfer->frlengths[x - 1]; + temp.isoc_frame += temp.isoc_delta; + } else { + /* get next Page Cache pointer */ + temp.pc = xfer->frbuffers + x; + } + } + + /* check if we should append a status stage */ + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) { + + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + temp.step_td = (xfer->nframes != 0); + temp.direction = UE_GET_DIR(xfer->endpointno) ^ UE_DIR_IN; + temp.len = 0; + temp.pc = NULL; + temp.shortpkt = 0; + temp.last_frame = 1; + temp.trb_type = XHCI_TRB_TYPE_STATUS_STAGE; + + xhci_setup_generic_chain_sub(&temp); + } + + td = temp.td; + + /* must have at least one frame! */ + + xfer->td_transfer_last = td; + + DPRINTF("first=%p last=%p\n", xfer->td_transfer_first, td); +} + +static void +xhci_set_slot_pointer(struct xhci_softc *sc, uint8_t index, uint64_t dev_addr) +{ + struct usb_page_search buf_res; + struct xhci_dev_ctx_addr *pdctxa; + + usbd_get_page(&sc->sc_hw.ctx_pc, 0, &buf_res); + + pdctxa = buf_res.buffer; + + DPRINTF("addr[%u]=0x%016llx\n", index, (long long)dev_addr); + + pdctxa->qwBaaDevCtxAddr[index] = htole64(dev_addr); + + usb_pc_cpu_flush(&sc->sc_hw.ctx_pc); +} + +static usb_error_t +xhci_configure_mask(struct usb_device *udev, uint32_t mask, uint8_t drop) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct usb_page_search buf_inp; + struct xhci_input_dev_ctx *pinp; + uint8_t index; + + index = udev->controller_slot_id; + + usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); + + pinp = buf_inp.buffer; + + if (drop) { + mask &= XHCI_INCTX_NON_CTRL_MASK; + pinp->ctx_input.dwInCtx0 = htole32(mask); + pinp->ctx_input.dwInCtx1 = 0; + } else { + pinp->ctx_input.dwInCtx0 = 0; + pinp->ctx_input.dwInCtx1 = htole32(mask); + } + return (0); +} + +static usb_error_t +xhci_configure_endpoint(struct usb_device *udev, + struct usb_endpoint_descriptor *edesc, uint64_t ring_addr, + uint16_t interval, uint8_t max_packet_count, uint8_t mult, + uint8_t fps_shift, uint16_t max_packet_size, uint16_t max_frame_size) +{ + struct usb_page_search buf_inp; + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct xhci_input_dev_ctx *pinp; + uint32_t temp; + uint8_t index; + uint8_t epno; + uint8_t type; + + index = udev->controller_slot_id; + + usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); + + pinp = buf_inp.buffer; + + epno = edesc->bEndpointAddress; + type = edesc->bmAttributes & UE_XFERTYPE; + + if (type == UE_CONTROL) + epno |= UE_DIR_IN; + + epno = XHCI_EPNO2EPID(epno); + + if (epno == 0) + return (USB_ERR_NO_PIPE); /* invalid */ + + if (max_packet_count == 0) + return (USB_ERR_BAD_BUFSIZE); + + max_packet_count--; + + if (mult == 0) + return (USB_ERR_BAD_BUFSIZE); + + temp = XHCI_EPCTX_0_EPSTATE_SET(0) | + XHCI_EPCTX_0_MAXP_STREAMS_SET(0) | + XHCI_EPCTX_0_LSA_SET(0); + + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + /* 1ms -> 125us */ + fps_shift += 3; + break; + default: + break; + } + + switch (type) { + case UE_INTERRUPT: + if (fps_shift > 3) + fps_shift--; + temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); + break; + case UE_ISOCHRONOUS: + temp |= XHCI_EPCTX_0_IVAL_SET(fps_shift); + + switch (udev->speed) { + case USB_SPEED_SUPER: + if (mult > 3) + mult = 3; + temp |= XHCI_EPCTX_0_MULT_SET(mult - 1); + max_packet_count /= mult; + break; + default: + break; + } + break; + default: + break; + } + + pinp->ctx_ep[epno - 1].dwEpCtx0 = htole32(temp); + + temp = + XHCI_EPCTX_1_HID_SET(0) | + XHCI_EPCTX_1_MAXB_SET(max_packet_count) | + XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size); + + if ((udev->parent_hs_hub != NULL) || (udev->address != 0)) { + if (type != UE_ISOCHRONOUS) + temp |= XHCI_EPCTX_1_CERR_SET(3); + } + + switch (type) { + case UE_CONTROL: + temp |= XHCI_EPCTX_1_EPTYPE_SET(4); + break; + case UE_ISOCHRONOUS: + temp |= XHCI_EPCTX_1_EPTYPE_SET(1); + break; + case UE_BULK: + temp |= XHCI_EPCTX_1_EPTYPE_SET(2); + break; + default: + temp |= XHCI_EPCTX_1_EPTYPE_SET(3); + break; + } + + /* check for IN direction */ + if (epno & 1) + temp |= XHCI_EPCTX_1_EPTYPE_SET(4); + + pinp->ctx_ep[epno - 1].dwEpCtx1 = htole32(temp); + + ring_addr |= XHCI_EPCTX_2_DCS_SET(1); + + pinp->ctx_ep[epno - 1].qwEpCtx2 = htole64(ring_addr); + + switch (edesc->bmAttributes & UE_XFERTYPE) { + case UE_INTERRUPT: + case UE_ISOCHRONOUS: + temp = XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(max_frame_size) | + XHCI_EPCTX_4_AVG_TRB_LEN_SET(MIN(XHCI_PAGE_SIZE, + max_frame_size)); + break; + case UE_CONTROL: + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(8); + break; + default: + temp = XHCI_EPCTX_4_AVG_TRB_LEN_SET(XHCI_PAGE_SIZE); + break; + } + + pinp->ctx_ep[epno - 1].dwEpCtx4 = htole32(temp); + +#ifdef USB_DEBUG + xhci_dump_endpoint(&pinp->ctx_ep[epno - 1]); +#endif + usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc); + + return (0); /* success */ +} + +static usb_error_t +xhci_configure_endpoint_by_xfer(struct usb_xfer *xfer) +{ + struct xhci_endpoint_ext *pepext; + struct usb_endpoint_ss_comp_descriptor *ecomp; + + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); + + ecomp = xfer->endpoint->ecomp; + + pepext->trb[0].dwTrb3 = 0; /* halt any transfers */ + usb_pc_cpu_flush(pepext->page_cache); + + return (xhci_configure_endpoint(xfer->xroot->udev, + xfer->endpoint->edesc, pepext->physaddr, + xfer->interval, xfer->max_packet_count, + (ecomp != NULL) ? (ecomp->bmAttributes & 3) + 1 : 1, + usbd_xfer_get_fps_shift(xfer), xfer->max_packet_size, + xfer->max_frame_size)); +} + +static usb_error_t +xhci_configure_device(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct usb_page_search buf_dev; + struct usb_page_search buf_inp; + struct usb_page_cache *pcdev; + struct usb_page_cache *pcinp; + struct xhci_input_dev_ctx *pinp; + struct xhci_dev_ctx *pdev; + struct usb_device *hubdev; + uint32_t temp; + uint32_t route; + uint8_t is_hub; + uint8_t index; + uint8_t rh_port; + + index = udev->controller_slot_id; + + DPRINTF("index=%u\n", index); + + pcdev = &sc->sc_hw.devs[index].device_pc; + pcinp = &sc->sc_hw.devs[index].input_pc; + + usbd_get_page(pcdev, 0, &buf_dev); + usbd_get_page(pcinp, 0, &buf_inp); + + pdev = buf_dev.buffer; + pinp = buf_inp.buffer; + + rh_port = 0; + route = 0; + + /* figure out route string and root HUB port number */ + + for (hubdev = udev; hubdev != NULL; hubdev = hubdev->parent_hub) { + + if (hubdev->parent_hub == NULL) + break; + + /* + * NOTE: HS/FS/LS devices and the SS root HUB can have + * more than 15 ports + */ + + rh_port = hubdev->port_no; + + if (hubdev->parent_hub->parent_hub == NULL) + break; + + route *= 16; + + if (rh_port > 15) + route |= 15; + else + route |= rh_port; + } + + temp = XHCI_SCTX_0_ROUTE_SET(route); + + switch (sc->sc_hw.devs[index].state) { + case XHCI_ST_CONFIGURED: + temp |= XHCI_SCTX_0_CTX_NUM_SET(XHCI_MAX_ENDPOINTS - 1); + break; + default: + temp = XHCI_SCTX_0_CTX_NUM_SET(1); + break; + } + + switch (udev->speed) { + case USB_SPEED_LOW: + temp |= XHCI_SCTX_0_SPEED_SET(2); + break; + case USB_SPEED_HIGH: + temp |= XHCI_SCTX_0_SPEED_SET(3); + break; + case USB_SPEED_FULL: + temp |= XHCI_SCTX_0_SPEED_SET(1); + break; + default: + temp |= XHCI_SCTX_0_SPEED_SET(4); + break; + } + + is_hub = sc->sc_hw.devs[index].nports != 0 && + (udev->speed == USB_SPEED_SUPER || + udev->speed == USB_SPEED_HIGH); + + if (is_hub) { + temp |= XHCI_SCTX_0_HUB_SET(1); +#if 0 + if (udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) { + DPRINTF("HUB supports MTT\n"); + temp |= XHCI_SCTX_0_MTT_SET(1); + } +#endif + } + + pinp->ctx_slot.dwSctx0 = htole32(temp); + + temp = XHCI_SCTX_1_RH_PORT_SET(rh_port); + + if (is_hub) { + temp |= XHCI_SCTX_1_NUM_PORTS_SET( + sc->sc_hw.devs[index].nports); + } + + switch (udev->speed) { + case USB_SPEED_SUPER: + switch (sc->sc_hw.devs[index].state) { + case XHCI_ST_ADDRESSED: + case XHCI_ST_CONFIGURED: + /* enable power save */ + temp |= XHCI_SCTX_1_MAX_EL_SET(sc->sc_exit_lat_max); + break; + default: + /* disable power save */ + break; + } + break; + default: + break; + } + + pinp->ctx_slot.dwSctx1 = htole32(temp); + + temp = XHCI_SCTX_2_IRQ_TARGET_SET(0); + + if (is_hub) + temp |= XHCI_SCTX_2_TT_THINK_TIME_SET(sc->sc_hw.devs[index].tt); + + hubdev = udev->parent_hs_hub; + + /* check if we should activate the transaction translator */ + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + if (hubdev != NULL) { + temp |= XHCI_SCTX_2_TT_HUB_SID_SET( + hubdev->controller_slot_id); + temp |= XHCI_SCTX_2_TT_PORT_NUM_SET( + udev->hs_port_no); + } + break; + default: + break; + } + + pinp->ctx_slot.dwSctx2 = htole32(temp); + + temp = XHCI_SCTX_3_DEV_ADDR_SET(udev->address) | + XHCI_SCTX_3_SLOT_STATE_SET(0); + + pinp->ctx_slot.dwSctx3 = htole32(temp); + +#ifdef USB_DEBUG + xhci_dump_device(&pinp->ctx_slot); +#endif + usb_pc_cpu_flush(pcinp); + + return (0); /* success */ +} + +static usb_error_t +xhci_alloc_device_ext(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct usb_page_search buf_dev; + struct usb_page_search buf_ep; + struct xhci_trb *trb; + struct usb_page_cache *pc; + struct usb_page *pg; + uint64_t addr; + uint8_t index; + uint8_t i; + + index = udev->controller_slot_id; + + pc = &sc->sc_hw.devs[index].device_pc; + pg = &sc->sc_hw.devs[index].device_pg; + + /* need to initialize the page cache */ + pc->tag_parent = sc->sc_bus.dma_parent_tag; + + if (usb_pc_alloc_mem(pc, pg, sizeof(struct xhci_dev_ctx), XHCI_PAGE_SIZE)) + goto error; + + usbd_get_page(pc, 0, &buf_dev); + + pc = &sc->sc_hw.devs[index].input_pc; + pg = &sc->sc_hw.devs[index].input_pg; + + /* need to initialize the page cache */ + pc->tag_parent = sc->sc_bus.dma_parent_tag; + + if (usb_pc_alloc_mem(pc, pg, sizeof(struct xhci_input_dev_ctx), XHCI_PAGE_SIZE)) + goto error; + + pc = &sc->sc_hw.devs[index].endpoint_pc; + pg = &sc->sc_hw.devs[index].endpoint_pg; + + /* need to initialize the page cache */ + pc->tag_parent = sc->sc_bus.dma_parent_tag; + + if (usb_pc_alloc_mem(pc, pg, sizeof(struct xhci_dev_endpoint_trbs), XHCI_PAGE_SIZE)) + goto error; + + /* initialise all endpoint LINK TRBs */ + + for (i = 0; i != XHCI_MAX_ENDPOINTS; i++) { + + /* lookup endpoint TRB ring */ + usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[i][0], &buf_ep); + + /* get TRB pointer */ + trb = buf_ep.buffer; + trb += XHCI_MAX_TRANSFERS - 1; + + /* get TRB start address */ + addr = buf_ep.physaddr; + + /* create LINK TRB */ + trb->qwTrb0 = htole64(addr); + trb->dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); + trb->dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); + } + + usb_pc_cpu_flush(pc); + + xhci_set_slot_pointer(sc, index, buf_dev.physaddr); + + return (0); + +error: + xhci_free_device_ext(udev); + + return (USB_ERR_NOMEM); +} + +static void +xhci_free_device_ext(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + + index = udev->controller_slot_id; + xhci_set_slot_pointer(sc, index, 0); + + usb_pc_free_mem(&sc->sc_hw.devs[index].device_pc); + usb_pc_free_mem(&sc->sc_hw.devs[index].input_pc); + usb_pc_free_mem(&sc->sc_hw.devs[index].endpoint_pc); +} + +static struct xhci_endpoint_ext * +xhci_get_endpoint_ext(struct usb_device *udev, struct usb_endpoint_descriptor *edesc) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct xhci_endpoint_ext *pepext; + struct usb_page_cache *pc; + struct usb_page_search buf_ep; + uint8_t epno; + uint8_t index; + + epno = edesc->bEndpointAddress; + if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) + epno |= UE_DIR_IN; + + epno = XHCI_EPNO2EPID(epno); + + index = udev->controller_slot_id; + + pc = &sc->sc_hw.devs[index].endpoint_pc; + + usbd_get_page(pc, (uintptr_t)&((struct xhci_dev_endpoint_trbs *)0)->trb[epno][0], &buf_ep); + + pepext = &sc->sc_hw.devs[index].endp[epno]; + pepext->page_cache = pc; + pepext->trb = buf_ep.buffer; + pepext->physaddr = buf_ep.physaddr; + + return (pepext); +} + +static void +xhci_endpoint_doorbell(struct usb_xfer *xfer) +{ + struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + uint8_t epno; + uint8_t index; + + epno = xfer->endpointno; + if (xfer->flags_int.control_xfr) + epno |= UE_DIR_IN; + + epno = XHCI_EPNO2EPID(epno); + index = xfer->xroot->udev->controller_slot_id; + + if (xfer->xroot->udev->flags.self_suspended == 0) + XWRITE4(sc, door, XHCI_DOORBELL(index), epno | XHCI_DB_SID_SET(0)); +} + +static void +xhci_transfer_remove(struct usb_xfer *xfer, usb_error_t error) +{ + struct xhci_endpoint_ext *pepext; + + if (xfer->flags_int.bandwidth_reclaimed) { + xfer->flags_int.bandwidth_reclaimed = 0; + + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); + + pepext->trb_used--; + + pepext->xfer[xfer->qh_pos] = NULL; + + if (error && pepext->trb_running != 0) { + pepext->trb_halted = 1; + pepext->trb_running = 0; + } + } +} + +static usb_error_t +xhci_transfer_insert(struct usb_xfer *xfer) +{ + struct xhci_td *td_first; + struct xhci_td *td_last; + struct xhci_endpoint_ext *pepext; + uint64_t addr; + uint8_t i; + uint8_t inext; + uint8_t trb_limit; + + DPRINTFN(8, "\n"); + + /* check if already inserted */ + if (xfer->flags_int.bandwidth_reclaimed) { + DPRINTFN(8, "Already in schedule\n"); + return (0); + } + + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); + + td_first = xfer->td_transfer_first; + td_last = xfer->td_transfer_last; + addr = pepext->physaddr; + + switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { + case UE_CONTROL: + case UE_INTERRUPT: + /* single buffered */ + trb_limit = 1; + break; + default: + /* multi buffered */ + trb_limit = (XHCI_MAX_TRANSFERS - 2); + break; + } + + if (pepext->trb_used >= trb_limit) { + DPRINTFN(8, "Too many TDs queued.\n"); + return (USB_ERR_NOMEM); + } + + /* check for stopped condition, after putting transfer on interrupt queue */ + if (pepext->trb_running == 0) { + struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + + DPRINTFN(8, "Not running\n"); + + /* start configuration */ + (void)usb_proc_msignal(&sc->sc_config_proc, + &sc->sc_config_msg[0], &sc->sc_config_msg[1]); + return (0); + } + + pepext->trb_used++; + + /* get current TRB index */ + i = pepext->trb_index; + + /* get next TRB index */ + inext = (i + 1); + + /* the last entry of the ring is a hardcoded link TRB */ + if (inext >= (XHCI_MAX_TRANSFERS - 1)) + inext = 0; + + /* compute terminating return address */ + addr += inext * sizeof(struct xhci_trb); + + /* update next pointer of last link TRB */ + td_last->td_trb[td_last->ntrb].qwTrb0 = htole64(addr); + td_last->td_trb[td_last->ntrb].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); + td_last->td_trb[td_last->ntrb].dwTrb3 = htole32(XHCI_TRB_3_IOC_BIT | + XHCI_TRB_3_CYCLE_BIT | XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); + +#ifdef USB_DEBUG + xhci_dump_trb(&td_last->td_trb[td_last->ntrb]); +#endif + usb_pc_cpu_flush(td_last->page_cache); + + /* write ahead chain end marker */ + + pepext->trb[inext].qwTrb0 = 0; + pepext->trb[inext].dwTrb2 = 0; + pepext->trb[inext].dwTrb3 = 0; + + /* update next pointer of link TRB */ + + pepext->trb[i].qwTrb0 = htole64((uint64_t)td_first->td_self); + pepext->trb[i].dwTrb2 = htole32(XHCI_TRB_2_IRQ_SET(0)); + +#ifdef USB_DEBUG + xhci_dump_trb(&pepext->trb[i]); +#endif + usb_pc_cpu_flush(pepext->page_cache); + + /* toggle cycle bit which activates the transfer chain */ + + pepext->trb[i].dwTrb3 = htole32(XHCI_TRB_3_CYCLE_BIT | + XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK)); + + usb_pc_cpu_flush(pepext->page_cache); + + DPRINTF("qh_pos = %u\n", i); + + pepext->xfer[i] = xfer; + + xfer->qh_pos = i; + + xfer->flags_int.bandwidth_reclaimed = 1; + + pepext->trb_index = inext; + + xhci_endpoint_doorbell(xfer); + + return (0); +} + +static void +xhci_root_intr(struct xhci_softc *sc) +{ + uint16_t i; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + /* clear any old interrupt data */ + memset(sc->sc_hub_idata, 0, sizeof(sc->sc_hub_idata)); + + for (i = 1; i <= sc->sc_noport; i++) { + /* pick out CHANGE bits from the status register */ + if (XREAD4(sc, oper, XHCI_PORTSC(i)) & ( + XHCI_PS_CSC | XHCI_PS_PEC | + XHCI_PS_OCC | XHCI_PS_WRC | + XHCI_PS_PRC | XHCI_PS_PLC | + XHCI_PS_CEC)) { + sc->sc_hub_idata[i / 8] |= 1 << (i % 8); + DPRINTF("port %d changed\n", i); + } + } + uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, + sizeof(sc->sc_hub_idata)); +} + +/*------------------------------------------------------------------------* + * xhci_device_done - XHCI done handler + * + * NOTE: This function can be called two times in a row on + * the same USB transfer. From close and from interrupt. + *------------------------------------------------------------------------*/ +static void +xhci_device_done(struct usb_xfer *xfer, usb_error_t error) +{ + DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", + xfer, xfer->endpoint, error); + + /* remove transfer from HW queue */ + xhci_transfer_remove(xfer, error); + + /* dequeue transfer and start next transfer */ + usbd_transfer_done(xfer, error); +} + +/*------------------------------------------------------------------------* + * XHCI data transfer support (generic type) + *------------------------------------------------------------------------*/ +static void +xhci_device_generic_open(struct usb_xfer *xfer) +{ + if (xfer->flags_int.isochronous_xfr) { + switch (xfer->xroot->udev->speed) { + case USB_SPEED_FULL: + break; + default: + usb_hs_bandwidth_alloc(xfer); + break; + } + } +} + +static void +xhci_device_generic_close(struct usb_xfer *xfer) +{ + DPRINTF("\n"); + + xhci_device_done(xfer, USB_ERR_CANCELLED); + + if (xfer->flags_int.isochronous_xfr) { + switch (xfer->xroot->udev->speed) { + case USB_SPEED_FULL: + break; + default: + usb_hs_bandwidth_free(xfer); + break; + } + } +} + +static void +xhci_device_generic_multi_enter(struct usb_endpoint *ep, + struct usb_xfer *enter_xfer) +{ + struct usb_xfer *xfer; + + /* check if there is a current transfer */ + xfer = ep->endpoint_q.curr; + if (xfer == NULL) + return; + + /* + * Check if the current transfer is started and then pickup + * the next one, if any. Else wait for next start event due to + * block on failure feature. + */ + if (!xfer->flags_int.bandwidth_reclaimed) + return; + + xfer = TAILQ_FIRST(&ep->endpoint_q.head); + if (xfer == NULL) { + /* + * In case of enter we have to consider that the + * transfer is queued by the USB core after the enter + * method is called. + */ + xfer = enter_xfer; + + if (xfer == NULL) + return; + } + + /* try to multi buffer */ + xhci_transfer_insert(xfer); +} + +static void +xhci_device_generic_enter(struct usb_xfer *xfer) +{ + DPRINTF("\n"); + + /* setup TD's and QH */ + xhci_setup_generic_chain(xfer); + + xhci_device_generic_multi_enter(xfer->endpoint, xfer); +} + +static void +xhci_device_generic_start(struct usb_xfer *xfer) +{ + DPRINTF("\n"); + + /* try to insert xfer on HW queue */ + xhci_transfer_insert(xfer); + + /* try to multi buffer */ + xhci_device_generic_multi_enter(xfer->endpoint, NULL); + + /* add transfer last on interrupt queue */ + usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); + + /* start timeout, if any */ + if (xfer->timeout != 0) + usbd_transfer_timeout_ms(xfer, &xhci_timeout, xfer->timeout); +} + +struct usb_pipe_methods xhci_device_generic_methods = +{ + .open = xhci_device_generic_open, + .close = xhci_device_generic_close, + .enter = xhci_device_generic_enter, + .start = xhci_device_generic_start, +}; + +/*------------------------------------------------------------------------* + * xhci root HUB support + *------------------------------------------------------------------------* + * Simulate a hardware HUB by handling all the necessary requests. + *------------------------------------------------------------------------*/ + +#define HSETW(ptr, val) ptr[0] = (uint8_t)(val), ptr[1] = (uint8_t)((val) >> 8) + +static const +struct usb_device_descriptor xhci_devd = +{ + .bLength = sizeof(xhci_devd), + .bDescriptorType = UDESC_DEVICE, /* type */ + HSETW(.bcdUSB, 0x0300), /* USB version */ + .bDeviceClass = UDCLASS_HUB, /* class */ + .bDeviceSubClass = UDSUBCLASS_HUB, /* subclass */ + .bDeviceProtocol = UDPROTO_SSHUB, /* protocol */ + .bMaxPacketSize = 9, /* max packet size */ + HSETW(.idVendor, 0x0000), /* vendor */ + HSETW(.idProduct, 0x0000), /* product */ + HSETW(.bcdDevice, 0x0100), /* device version */ + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 0, + .bNumConfigurations = 1, /* # of configurations */ +}; + +static const +struct xhci_bos_desc xhci_bosd = { + .bosd = { + .bLength = sizeof(xhci_bosd.bosd), + .bDescriptorType = UDESC_BOS, + HSETW(.wTotalLength, sizeof(xhci_bosd)), + .bNumDeviceCaps = 3, + }, + .usb2extd = { + .bLength = sizeof(xhci_bosd.usb2extd), + .bDescriptorType = 1, + .bDevCapabilityType = 2, + .bmAttributes = 2, + }, + .usbdcd = { + .bLength = sizeof(xhci_bosd.usbdcd), + .bDescriptorType = UDESC_DEVICE_CAPABILITY, + .bDevCapabilityType = 3, + .bmAttributes = 0, /* XXX */ + HSETW(.wSpeedsSupported, 0x000C), + .bFunctionalitySupport = 8, + .bU1DevExitLat = 255, /* dummy - not used */ + .bU2DevExitLat = 255, /* dummy - not used */ + }, + .cidd = { + .bLength = sizeof(xhci_bosd.cidd), + .bDescriptorType = 1, + .bDevCapabilityType = 4, + .bReserved = 0, + .bContainerID = 0, /* XXX */ + }, +}; + +static const +struct xhci_config_desc xhci_confd = { + .confd = { + .bLength = sizeof(xhci_confd.confd), + .bDescriptorType = UDESC_CONFIG, + .wTotalLength[0] = sizeof(xhci_confd), + .bNumInterface = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = UC_SELF_POWERED, + .bMaxPower = 0 /* max power */ + }, + .ifcd = { + .bLength = sizeof(xhci_confd.ifcd), + .bDescriptorType = UDESC_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = UICLASS_HUB, + .bInterfaceSubClass = UISUBCLASS_HUB, + .bInterfaceProtocol = 0, + }, + .endpd = { + .bLength = sizeof(xhci_confd.endpd), + .bDescriptorType = UDESC_ENDPOINT, + .bEndpointAddress = UE_DIR_IN | XHCI_INTR_ENDPT, + .bmAttributes = UE_INTERRUPT, + .wMaxPacketSize[0] = 2, /* max 15 ports */ + .bInterval = 255, + }, + .endpcd = { + .bLength = sizeof(xhci_confd.endpcd), + .bDescriptorType = UDESC_ENDPOINT_SS_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + }, +}; + +static const +struct usb_hub_ss_descriptor xhci_hubd = { + .bLength = sizeof(xhci_hubd), + .bDescriptorType = UDESC_SS_HUB, +}; + +static usb_error_t +xhci_roothub_exec(struct usb_device *udev, + struct usb_device_request *req, const void **pptr, uint16_t *plength) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + const char *str_ptr; + const void *ptr; + uint32_t port; + uint32_t v; + uint16_t len; + uint16_t i; + uint16_t value; + uint16_t index; + uint8_t j; + usb_error_t err; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + /* buffer reset */ + ptr = (const void *)&sc->sc_hub_desc; + len = 0; + err = 0; + + value = UGETW(req->wValue); + index = UGETW(req->wIndex); + + DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " + "wValue=0x%04x wIndex=0x%04x\n", + req->bmRequestType, req->bRequest, + UGETW(req->wLength), value, index); + +#define C(x,y) ((x) | ((y) << 8)) + switch (C(req->bRequest, req->bmRequestType)) { + case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): + case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): + case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): + /* + * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops + * for the integrated root hub. + */ + break; + case C(UR_GET_CONFIG, UT_READ_DEVICE): + len = 1; + sc->sc_hub_desc.temp[0] = sc->sc_conf; + break; + case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): + switch (value >> 8) { + case UDESC_DEVICE: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(xhci_devd); + ptr = (const void *)&xhci_devd; + break; + + case UDESC_BOS: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(xhci_bosd); + ptr = (const void *)&xhci_bosd; + break; + + case UDESC_CONFIG: + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + len = sizeof(xhci_confd); + ptr = (const void *)&xhci_confd; + break; + + case UDESC_STRING: + switch (value & 0xff) { + case 0: /* Language table */ + str_ptr = "\001"; + break; + + case 1: /* Vendor */ + str_ptr = sc->sc_vendor; + break; + + case 2: /* Product */ + str_ptr = "XHCI root HUB"; + break; + + default: + str_ptr = ""; + break; + } + + len = usb_make_str_desc( + sc->sc_hub_desc.temp, + sizeof(sc->sc_hub_desc.temp), + str_ptr); + break; + + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + case C(UR_GET_INTERFACE, UT_READ_INTERFACE): + len = 1; + sc->sc_hub_desc.temp[0] = 0; + break; + case C(UR_GET_STATUS, UT_READ_DEVICE): + len = 2; + USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); + break; + case C(UR_GET_STATUS, UT_READ_INTERFACE): + case C(UR_GET_STATUS, UT_READ_ENDPOINT): + len = 2; + USETW(sc->sc_hub_desc.stat.wStatus, 0); + break; + case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): + if (value >= XHCI_MAX_DEVICES) { + err = USB_ERR_IOERROR; + goto done; + } + break; + case C(UR_SET_CONFIG, UT_WRITE_DEVICE): + if (value != 0 && value != 1) { + err = USB_ERR_IOERROR; + goto done; + } + sc->sc_conf = value; + break; + case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): + break; + case C(UR_SET_FEATURE, UT_WRITE_DEVICE): + case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): + case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): + err = USB_ERR_IOERROR; + goto done; + case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): + break; + case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): + break; + /* Hub requests */ + case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): + break; + case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): + DPRINTFN(9, "UR_CLEAR_PORT_FEATURE\n"); + + if ((index < 1) || + (index > sc->sc_noport)) { + err = USB_ERR_IOERROR; + goto done; + } + port = XHCI_PORTSC(index); + + v = XREAD4(sc, oper, port) & ~XHCI_PS_CLEAR; + + switch (value) { + case UHF_C_BH_PORT_RESET: + XWRITE4(sc, oper, port, v | XHCI_PS_WRC); + break; + case UHF_C_PORT_CONFIG_ERROR: + XWRITE4(sc, oper, port, v | XHCI_PS_CEC); + break; + case UHF_C_PORT_LINK_STATE: + XWRITE4(sc, oper, port, v | XHCI_PS_PLC); + break; + case UHF_C_PORT_CONNECTION: + XWRITE4(sc, oper, port, v | XHCI_PS_CSC); + break; + case UHF_C_PORT_ENABLE: + XWRITE4(sc, oper, port, v | XHCI_PS_PEC); + break; + case UHF_C_PORT_OVER_CURRENT: + XWRITE4(sc, oper, port, v | XHCI_PS_OCC); + break; + case UHF_C_PORT_RESET: + XWRITE4(sc, oper, port, v | XHCI_PS_PRC); + break; + case UHF_PORT_ENABLE: + XWRITE4(sc, oper, port, v | XHCI_PS_PED); + break; + case UHF_PORT_POWER: + XWRITE4(sc, oper, port, v & ~XHCI_PS_PP); + break; + case UHF_PORT_INDICATOR: + XWRITE4(sc, oper, port, v & ~XHCI_PS_PIC_SET(3)); + break; + case UHF_PORT_SUSPEND: + XWRITE4(sc, oper, port, v | + XHCI_PS_PLS_SET(0) | XHCI_PS_LWS); + break; + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + + case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): + if ((value & 0xff) != 0) { + err = USB_ERR_IOERROR; + goto done; + } + + v = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + sc->sc_hub_desc.hubd = xhci_hubd; + + sc->sc_hub_desc.hubd.bNbrPorts = sc->sc_noport; + + if (XHCI_HCS0_PPC(v)) + i = UHD_PWR_INDIVIDUAL; + else + i = UHD_PWR_GANGED; + + if (XHCI_HCS0_PIND(v)) + i |= UHD_PORT_IND; + + i |= UHD_OC_INDIVIDUAL; + + USETW(sc->sc_hub_desc.hubd.wHubCharacteristics, i); + + /* see XHCI section 5.4.9: */ + sc->sc_hub_desc.hubd.bPwrOn2PwrGood = 10; + + for (j = 1; j <= sc->sc_noport; j++) { + + v = XREAD4(sc, oper, XHCI_PORTSC(j)); + if (v & XHCI_PS_DR) { + sc->sc_hub_desc.hubd. + DeviceRemovable[j / 8] |= 1U << (j % 8); + } + } + len = sc->sc_hub_desc.hubd.bLength; + break; + + case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): + len = 16; + memset(sc->sc_hub_desc.temp, 0, 16); + break; + + case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): + DPRINTFN(9, "UR_GET_STATUS i=%d\n", index); + + if ((index < 1) || + (index > sc->sc_noport)) { + err = USB_ERR_IOERROR; + goto done; + } + + v = XREAD4(sc, oper, XHCI_PORTSC(index)); + + DPRINTFN(9, "port status=0x%08x\n", v); + + i = UPS_PORT_LINK_STATE_SET(XHCI_PS_PLS_GET(v)); + + switch (XHCI_PS_SPEED_GET(v)) { + case 3: + i |= UPS_HIGH_SPEED; + break; + case 2: + i |= UPS_LOW_SPEED; + break; + case 1: + /* FULL speed */ + break; + default: + i |= UPS_OTHER_SPEED; + break; + } + + if (v & XHCI_PS_CCS) + i |= UPS_CURRENT_CONNECT_STATUS; + if (v & XHCI_PS_PED) + i |= UPS_PORT_ENABLED; + if (v & XHCI_PS_OCA) + i |= UPS_OVERCURRENT_INDICATOR; + if (v & XHCI_PS_PR) + i |= UPS_RESET; + if (v & XHCI_PS_PP) + i |= UPS_PORT_POWER; + USETW(sc->sc_hub_desc.ps.wPortStatus, i); + + i = 0; + if (v & XHCI_PS_CSC) + i |= UPS_C_CONNECT_STATUS; + if (v & XHCI_PS_PEC) + i |= UPS_C_PORT_ENABLED; + if (v & XHCI_PS_OCC) + i |= UPS_C_OVERCURRENT_INDICATOR; + if (v & XHCI_PS_WRC) + i |= UPS_C_BH_PORT_RESET; + if (v & XHCI_PS_PRC) + i |= UPS_C_PORT_RESET; + if (v & XHCI_PS_PLC) + i |= UPS_C_PORT_LINK_STATE; + if (v & XHCI_PS_CEC) + i |= UPS_C_PORT_CONFIG_ERROR; + + USETW(sc->sc_hub_desc.ps.wPortChange, i); + len = sizeof(sc->sc_hub_desc.ps); + break; + + case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): + err = USB_ERR_IOERROR; + goto done; + + case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): + break; + + case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): + + i = index >> 8; + index &= 0x00FF; + + if ((index < 1) || + (index > sc->sc_noport)) { + err = USB_ERR_IOERROR; + goto done; + } + + port = XHCI_PORTSC(index); + v = XREAD4(sc, oper, port) & ~XHCI_PS_CLEAR; + + switch (value) { + case UHF_PORT_U1_TIMEOUT: + if (XHCI_PS_SPEED_GET(v) != 4) { + err = USB_ERR_IOERROR; + goto done; + } + port = XHCI_PORTPMSC(index); + v = XREAD4(sc, oper, port); + v &= ~XHCI_PM3_U1TO_SET(0xFF); + v |= XHCI_PM3_U1TO_SET(i); + XWRITE4(sc, oper, port, v); + break; + case UHF_PORT_U2_TIMEOUT: + if (XHCI_PS_SPEED_GET(v) != 4) { + err = USB_ERR_IOERROR; + goto done; + } + port = XHCI_PORTPMSC(index); + v = XREAD4(sc, oper, port); + v &= ~XHCI_PM3_U2TO_SET(0xFF); + v |= XHCI_PM3_U2TO_SET(i); + XWRITE4(sc, oper, port, v); + break; + case UHF_BH_PORT_RESET: + XWRITE4(sc, oper, port, v | XHCI_PS_WPR); + break; + case UHF_PORT_LINK_STATE: + XWRITE4(sc, oper, port, v | + XHCI_PS_PLS_SET(i) | XHCI_PS_LWS); + /* 4ms settle time */ + usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 250); + break; + case UHF_PORT_ENABLE: + DPRINTFN(3, "set port enable %d\n", index); + break; + case UHF_PORT_SUSPEND: + DPRINTFN(6, "suspend port %u (LPM=%u)\n", index, i); + j = XHCI_PS_SPEED_GET(v); + if ((j < 1) || (j > 3)) { + /* non-supported speed */ + err = USB_ERR_IOERROR; + goto done; + } + XWRITE4(sc, oper, port, v | + XHCI_PS_PLS_SET(i ? 2 /* LPM */ : 3) | XHCI_PS_LWS); + break; + case UHF_PORT_RESET: + DPRINTFN(6, "reset port %d\n", index); + XWRITE4(sc, oper, port, v | XHCI_PS_PR); + break; + case UHF_PORT_POWER: + DPRINTFN(3, "set port power %d\n", index); + XWRITE4(sc, oper, port, v | XHCI_PS_PP); + break; + case UHF_PORT_TEST: + DPRINTFN(3, "set port test %d\n", index); + break; + case UHF_PORT_INDICATOR: + DPRINTFN(3, "set port indicator %d\n", index); + + v &= ~XHCI_PS_PIC_SET(3); + v |= XHCI_PS_PIC_SET(1); + + XWRITE4(sc, oper, port, v); + break; + default: + err = USB_ERR_IOERROR; + goto done; + } + break; + + case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER): + case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER): + case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER): + case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER): + break; + default: + err = USB_ERR_IOERROR; + goto done; + } +done: + *plength = len; + *pptr = ptr; + return (err); +} + +static void +xhci_xfer_setup(struct usb_setup_params *parm) +{ + struct usb_page_search page_info; + struct usb_page_cache *pc; + struct xhci_softc *sc; + struct usb_xfer *xfer; + void *last_obj; + uint32_t ntd; + uint32_t n; + + sc = XHCI_BUS2SC(parm->udev->bus); + xfer = parm->curr_xfer; + + /* + * The proof for the "ntd" formula is illustrated like this: + * + * +------------------------------------+ + * | | + * | |remainder -> | + * | +-----+---+ | + * | | xxx | x | frm 0 | + * | +-----+---++ | + * | | xxx | xx | frm 1 | + * | +-----+----+ | + * | ... | + * +------------------------------------+ + * + * "xxx" means a completely full USB transfer descriptor + * + * "x" and "xx" means a short USB packet + * + * For the remainder of an USB transfer modulo + * "max_data_length" we need two USB transfer descriptors. + * One to transfer the remaining data and one to finalise with + * a zero length packet in case the "force_short_xfer" flag is + * set. We only need two USB transfer descriptors in the case + * where the transfer length of the first one is a factor of + * "max_frame_size". The rest of the needed USB transfer + * descriptors is given by the buffer size divided by the + * maximum data payload. + */ + parm->hc_max_packet_size = 0x400; + parm->hc_max_packet_count = 16 * 3; + parm->hc_max_frame_size = XHCI_TD_PAYLOAD_MAX; + + xfer->flags_int.bdma_enable = 1; + + usbd_transfer_setup_sub(parm); + + if (xfer->flags_int.isochronous_xfr) { + ntd = ((1 * xfer->nframes) + + (xfer->max_data_length / xfer->max_hc_frame_size)); + } else if (xfer->flags_int.control_xfr) { + ntd = ((2 * xfer->nframes) + 1 /* STATUS */ + + (xfer->max_data_length / xfer->max_hc_frame_size)); + } else { + ntd = ((2 * xfer->nframes) + + (xfer->max_data_length / xfer->max_hc_frame_size)); + } + +alloc_dma_set: + + if (parm->err) + return; + + /* + * Allocate queue heads and transfer descriptors + */ + last_obj = NULL; + + if (usbd_transfer_setup_sub_malloc( + parm, &pc, sizeof(struct xhci_td), + XHCI_TD_ALIGN, ntd)) { + parm->err = USB_ERR_NOMEM; + return; + } + if (parm->buf) { + for (n = 0; n != ntd; n++) { + struct xhci_td *td; + + usbd_get_page(pc + n, 0, &page_info); + + td = page_info.buffer; + + /* init TD */ + td->td_self = page_info.physaddr; + td->obj_next = last_obj; + td->page_cache = pc + n; + + last_obj = td; + + usb_pc_cpu_flush(pc + n); + } + } + xfer->td_start[xfer->flags_int.curr_dma_set] = last_obj; + + if (!xfer->flags_int.curr_dma_set) { + xfer->flags_int.curr_dma_set = 1; + goto alloc_dma_set; + } +} + +static usb_error_t +xhci_configure_reset_endpoint(struct usb_xfer *xfer) +{ + struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + struct usb_page_search buf_dev; + struct usb_page_search buf_inp; + struct usb_device *udev; + struct xhci_endpoint_ext *pepext; + struct usb_endpoint_descriptor *edesc; + struct xhci_dev_ctx *pdctx; + struct usb_page_cache *pcdev; + struct usb_page_cache *pcinp; + usb_error_t err; + uint8_t index; + uint8_t epno; + + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); + + udev = xfer->xroot->udev; + index = udev->controller_slot_id; + + pcdev = &sc->sc_hw.devs[index].device_pc; + pcinp = &sc->sc_hw.devs[index].input_pc; + + usbd_get_page(pcdev, 0, &buf_dev); + usbd_get_page(pcinp, 0, &buf_inp); + + pdctx = buf_dev.buffer; + + edesc = xfer->endpoint->edesc; + + epno = edesc->bEndpointAddress; + + if ((edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) + epno |= UE_DIR_IN; + + epno = XHCI_EPNO2EPID(epno); + + if (epno == 0) + return (USB_ERR_NO_PIPE); /* invalid */ + + XHCI_CMD_LOCK(sc); + + /* configure endpoint */ + + err = xhci_configure_endpoint_by_xfer(xfer); + + if (err != 0) { + XHCI_CMD_UNLOCK(sc); + return (err); + } + + /* + * Get the endpoint into the stopped state according to the + * endpoint context state diagram in the XHCI specification: + */ + + err = xhci_cmd_stop_ep(sc, 0, epno, index); + + if (err != 0) + DPRINTF("Could not stop endpoint %u\n", epno); + + err = xhci_cmd_reset_ep(sc, 0, epno, index); + + if (err != 0) + DPRINTF("Could not reset endpoint %u\n", epno); + + err = xhci_cmd_set_tr_dequeue_ptr(sc, pepext->physaddr | + XHCI_EPCTX_2_DCS_SET(1), 0, epno, index); + + if (err != 0) + DPRINTF("Could not set dequeue ptr for endpoint %u\n", epno); + + /* + * Get the endpoint into the running state according to the + * endpoint context state diagram in the XHCI specification: + */ + + xhci_configure_mask(udev, 1U << epno, 0); + + err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); + + if (err != 0) + DPRINTF("Could not configure endpoint %u\n", epno); + + err = xhci_cmd_configure_ep(sc, buf_inp.physaddr, 0, index); + + if (err != 0) + DPRINTF("Could not configure endpoint %u\n", epno); + + XHCI_CMD_UNLOCK(sc); + + return (0); +} + +static void +xhci_xfer_unsetup(struct usb_xfer *xfer) +{ + return; +} + +static void +xhci_start_dma_delay(struct usb_xfer *xfer) +{ + struct xhci_softc *sc = XHCI_BUS2SC(xfer->xroot->bus); + + /* put transfer on interrupt queue (again) */ + usbd_transfer_enqueue(&sc->sc_bus.intr_q, xfer); + + (void)usb_proc_msignal(&sc->sc_config_proc, + &sc->sc_config_msg[0], &sc->sc_config_msg[1]); +} + +static void +xhci_configure_msg(struct usb_proc_msg *pm) +{ + struct xhci_softc *sc; + struct xhci_endpoint_ext *pepext; + struct usb_xfer *xfer; + + sc = XHCI_BUS2SC(((struct usb_bus_msg *)pm)->bus); + +restart: + TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + + pepext = xhci_get_endpoint_ext(xfer->xroot->udev, + xfer->endpoint->edesc); + + if ((pepext->trb_halted != 0) || + (pepext->trb_running == 0)) { + + uint8_t i; + + /* clear halted and running */ + pepext->trb_halted = 0; + pepext->trb_running = 0; + + /* nuke remaining buffered transfers */ + + for (i = 0; i != (XHCI_MAX_TRANSFERS - 1); i++) { + /* + * NOTE: We need to use the timeout + * error code here else existing + * isochronous clients can get + * confused: + */ + if (pepext->xfer[i] != NULL) { + xhci_device_done(pepext->xfer[i], + USB_ERR_TIMEOUT); + } + } + + /* + * NOTE: The USB transfer cannot vanish in + * this state! + */ + + USB_BUS_UNLOCK(&sc->sc_bus); + + xhci_configure_reset_endpoint(xfer); + + USB_BUS_LOCK(&sc->sc_bus); + + /* check if halted is still cleared */ + if (pepext->trb_halted == 0) { + pepext->trb_running = 1; + pepext->trb_index = 0; + } + goto restart; + } + + if (xfer->flags_int.did_dma_delay) { + + /* remove transfer from interrupt queue (again) */ + usbd_transfer_dequeue(xfer); + + /* we are finally done */ + usb_dma_delay_done_cb(xfer); + + /* queue changed - restart */ + goto restart; + } + } + + TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + + /* try to insert xfer on HW queue */ + xhci_transfer_insert(xfer); + + /* try to multi buffer */ + xhci_device_generic_multi_enter(xfer->endpoint, NULL); + } +} + +static void +xhci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, + struct usb_endpoint *ep) +{ + struct xhci_endpoint_ext *pepext; + + DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d\n", + ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode); + + if (udev->flags.usb_mode != USB_MODE_HOST) { + /* not supported */ + return; + } + if (udev->parent_hub == NULL) { + /* root HUB has special endpoint handling */ + return; + } + + ep->methods = &xhci_device_generic_methods; + + pepext = xhci_get_endpoint_ext(udev, edesc); + + USB_BUS_LOCK(udev->bus); + pepext->trb_halted = 1; + pepext->trb_running = 0; + USB_BUS_UNLOCK(udev->bus); +} + +static void +xhci_ep_uninit(struct usb_device *udev, struct usb_endpoint *ep) +{ + +} + +static void +xhci_ep_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) +{ + struct xhci_endpoint_ext *pepext; + + DPRINTF("\n"); + + if (udev->flags.usb_mode != USB_MODE_HOST) { + /* not supported */ + return; + } + if (udev->parent_hub == NULL) { + /* root HUB has special endpoint handling */ + return; + } + + pepext = xhci_get_endpoint_ext(udev, ep->edesc); + + USB_BUS_LOCK(udev->bus); + pepext->trb_halted = 1; + pepext->trb_running = 0; + USB_BUS_UNLOCK(udev->bus); +} + +static usb_error_t +xhci_device_init(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + usb_error_t err; + uint8_t temp; + + /* no init for root HUB */ + if (udev->parent_hub == NULL) + return (0); + + XHCI_CMD_LOCK(sc); + + /* set invalid default */ + + udev->controller_slot_id = sc->sc_noslot + 1; + + /* try to get a new slot ID from the XHCI */ + + err = xhci_cmd_enable_slot(sc, &temp); + + if (err) { + XHCI_CMD_UNLOCK(sc); + return (err); + } + + if (temp > sc->sc_noslot) { + XHCI_CMD_UNLOCK(sc); + return (USB_ERR_BAD_ADDRESS); + } + + if (sc->sc_hw.devs[temp].state != XHCI_ST_DISABLED) { + DPRINTF("slot %u already allocated.\n", temp); + XHCI_CMD_UNLOCK(sc); + return (USB_ERR_BAD_ADDRESS); + } + + /* store slot ID for later reference */ + + udev->controller_slot_id = temp; + + /* reset data structure */ + + memset(&sc->sc_hw.devs[temp], 0, sizeof(sc->sc_hw.devs[0])); + + /* set mark slot allocated */ + + sc->sc_hw.devs[temp].state = XHCI_ST_ENABLED; + + err = xhci_alloc_device_ext(udev); + + XHCI_CMD_UNLOCK(sc); + + /* get device into default state */ + + if (err == 0) + err = xhci_set_address(udev, NULL, 0); + + return (err); +} + +static void +xhci_device_uninit(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + + /* no init for root HUB */ + if (udev->parent_hub == NULL) + return; + + XHCI_CMD_LOCK(sc); + + index = udev->controller_slot_id; + + if (index <= sc->sc_noslot) { + xhci_cmd_disable_slot(sc, index); + sc->sc_hw.devs[index].state = XHCI_ST_DISABLED; + + /* free device extension */ + xhci_free_device_ext(udev); + } + + XHCI_CMD_UNLOCK(sc); +} + +static void +xhci_get_dma_delay(struct usb_device *udev, uint32_t *pus) +{ + /* + * Wait until the hardware has finished any possible use of + * the transfer descriptor(s) + */ + *pus = 2048; /* microseconds */ +} + +static void +xhci_device_resume(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + uint8_t n; + + DPRINTF("\n"); + + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + XHCI_CMD_LOCK(sc); + + /* blindly resume all endpoints */ + + USB_BUS_LOCK(udev->bus); + + for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) + XWRITE4(sc, door, XHCI_DOORBELL(index), n | XHCI_DB_SID_SET(0)); + + USB_BUS_UNLOCK(udev->bus); + + XHCI_CMD_UNLOCK(sc); +} + +static void +xhci_device_suspend(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + uint8_t index; + uint8_t n; + usb_error_t err; + + DPRINTF("\n"); + + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + XHCI_CMD_LOCK(sc); + + /* blindly suspend all endpoints */ + + for (n = 1; n != XHCI_MAX_ENDPOINTS; n++) { + err = xhci_cmd_stop_ep(sc, 1, n, index); + if (err != 0) { + DPRINTF("Failed to suspend endpoint " + "%u on slot %u (ignored).\n", n, index); + } + } + + XHCI_CMD_UNLOCK(sc); +} + +static void +xhci_set_hw_power(struct usb_bus *bus) +{ + DPRINTF("\n"); +} + +static void +xhci_device_state_change(struct usb_device *udev) +{ + struct xhci_softc *sc = XHCI_BUS2SC(udev->bus); + struct usb_page_search buf_inp; + usb_error_t err; + uint8_t index; + + /* check for root HUB */ + if (udev->parent_hub == NULL) + return; + + index = udev->controller_slot_id; + + DPRINTF("\n"); + + if (usb_get_device_state(udev) == USB_STATE_CONFIGURED) { + err = uhub_query_info(udev, &sc->sc_hw.devs[index].nports, + &sc->sc_hw.devs[index].tt); + if (err != 0) + sc->sc_hw.devs[index].nports = 0; + } + + XHCI_CMD_LOCK(sc); + + switch (usb_get_device_state(udev)) { + case USB_STATE_POWERED: + if (sc->sc_hw.devs[index].state == XHCI_ST_DEFAULT) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_DEFAULT; + + err = xhci_cmd_reset_dev(sc, index); + + if (err != 0) { + DPRINTF("Device reset failed " + "for slot %u.\n", index); + } + break; + + case USB_STATE_ADDRESSED: + if (sc->sc_hw.devs[index].state == XHCI_ST_ADDRESSED) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_ADDRESSED; + + err = xhci_cmd_configure_ep(sc, 0, 1, index); + + if (err) { + DPRINTF("Failed to deconfigure " + "slot %u.\n", index); + } + break; + + case USB_STATE_CONFIGURED: + if (sc->sc_hw.devs[index].state == XHCI_ST_CONFIGURED) + break; + + sc->sc_hw.devs[index].state = XHCI_ST_CONFIGURED; + + usbd_get_page(&sc->sc_hw.devs[index].input_pc, 0, &buf_inp); + + xhci_configure_mask(udev, 1, 0); + + err = xhci_configure_device(udev); + if (err != 0) { + DPRINTF("Could not configure device " + "at slot %u.\n", index); + } + + err = xhci_cmd_evaluate_ctx(sc, buf_inp.physaddr, index); + if (err != 0) { + DPRINTF("Could not evaluate device " + "context at slot %u.\n", index); + } + break; + + default: + break; + } + XHCI_CMD_UNLOCK(sc); +} + +struct usb_bus_methods xhci_bus_methods = { + .endpoint_init = xhci_ep_init, + .endpoint_uninit = xhci_ep_uninit, + .xfer_setup = xhci_xfer_setup, + .xfer_unsetup = xhci_xfer_unsetup, + .get_dma_delay = xhci_get_dma_delay, + .device_init = xhci_device_init, + .device_uninit = xhci_device_uninit, + .device_resume = xhci_device_resume, + .device_suspend = xhci_device_suspend, + .set_hw_power = xhci_set_hw_power, + .roothub_exec = xhci_roothub_exec, + .xfer_poll = xhci_do_poll, + .start_dma_delay = xhci_start_dma_delay, + .set_address = xhci_set_address, + .clear_stall = xhci_ep_clear_stall, + .device_state_change = xhci_device_state_change, +}; diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h new file mode 100644 index 00000000000..327289044c1 --- /dev/null +++ b/sys/dev/usb/controller/xhci.h @@ -0,0 +1,499 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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. + */ + +#ifndef _XHCI_H_ +#define _XHCI_H_ + +#define XHCI_MAX_DEVICES MIN(USB_MAX_DEVICES, 128) +#define XHCI_MAX_ENDPOINTS 32 /* hardcoded - do not change */ +#define XHCI_MAX_SCRATCHPADS 32 +#define XHCI_MAX_EVENTS (16 * 13) +#define XHCI_MAX_COMMANDS (16 * 1) +#define XHCI_MAX_RSEG 1 +#define XHCI_MAX_TRANSFERS 4 + +#define XHCI_DEV_CTX_ADDR_ALIGN 64 /* bytes */ +#define XHCI_DEV_CTX_ALIGN 64 /* bytes */ +#define XHCI_INPUT_CTX_ALIGN 64 /* bytes */ +#define XHCI_SLOT_CTX_ALIGN 32 /* bytes */ +#define XHCI_ENDP_CTX_ALIGN 32 /* bytes */ +#define XHCI_STREAM_CTX_ALIGN 16 /* bytes */ +#define XHCI_TRANS_RING_SEG_ALIGN 16 /* bytes */ +#define XHCI_CMD_RING_SEG_ALIGN 64 /* bytes */ +#define XHCI_EVENT_RING_SEG_ALIGN 64 /* bytes */ +#define XHCI_SCRATCH_BUF_ARRAY_ALIGN 64 /* bytes */ +#define XHCI_SCRATCH_BUFFER_ALIGN USB_PAGE_SIZE +#define XHCI_TRB_ALIGN 16 /* bytes */ +#define XHCI_TD_ALIGN 64 /* bytes */ +#define XHCI_PAGE_SIZE 4096 /* bytes */ + +struct xhci_dev_ctx_addr { + volatile uint64_t qwBaaDevCtxAddr[USB_MAX_DEVICES + 1]; + struct { + volatile uint64_t dummy; + } __aligned(64) padding; + volatile uint64_t qwSpBufPtr[XHCI_MAX_SCRATCHPADS]; +}; + +#define XHCI_EPNO2EPID(x) \ + ((((x) & UE_DIR_IN) ? 1 : 0) | (2 * ((x) & UE_ADDR))) + +struct xhci_slot_ctx { + volatile uint32_t dwSctx0; +#define XHCI_SCTX_0_ROUTE_SET(x) ((x) & 0xFFFFF) +#define XHCI_SCTX_0_ROUTE_GET(x) ((x) & 0xFFFFF) +#define XHCI_SCTX_0_SPEED_SET(x) (((x) & 0xF) << 20) +#define XHCI_SCTX_0_SPEED_GET(x) (((x) >> 20) & 0xF) +#define XHCI_SCTX_0_MTT_SET(x) (((x) & 0x1) << 25) +#define XHCI_SCTX_0_MTT_GET(x) (((x) >> 25) & 0x1) +#define XHCI_SCTX_0_HUB_SET(x) (((x) & 0x1) << 26) +#define XHCI_SCTX_0_HUB_GET(x) (((x) >> 26) & 0x1) +#define XHCI_SCTX_0_CTX_NUM_SET(x) (((x) & 0x1F) << 27) +#define XHCI_SCTX_0_CTX_NUM_GET(x) (((x) >> 27) & 0x1F) + volatile uint32_t dwSctx1; +#define XHCI_SCTX_1_MAX_EL_SET(x) ((x) & 0xFFFF) +#define XHCI_SCTX_1_MAX_EL_GET(x) ((x) & 0xFFFF) +#define XHCI_SCTX_1_RH_PORT_SET(x) (((x) & 0xFF) << 16) +#define XHCI_SCTX_1_RH_PORT_GET(x) (((x) >> 16) & 0xFF) +#define XHCI_SCTX_1_NUM_PORTS_SET(x) (((x) & 0xFF) << 24) +#define XHCI_SCTX_1_NUM_PORTS_GET(x) (((x) >> 24) & 0xFF) + volatile uint32_t dwSctx2; +#define XHCI_SCTX_2_TT_HUB_SID_SET(x) ((x) & 0xFF) +#define XHCI_SCTX_2_TT_HUB_SID_GET(x) ((x) & 0xFF) +#define XHCI_SCTX_2_TT_PORT_NUM_SET(x) (((x) & 0xFF) << 8) +#define XHCI_SCTX_2_TT_PORT_NUM_GET(x) (((x) >> 8) & 0xFF) +#define XHCI_SCTX_2_TT_THINK_TIME_SET(x) (((x) & 0x3) << 16) +#define XHCI_SCTX_2_TT_THINK_TIME_GET(x) (((x) >> 16) & 0x3) +#define XHCI_SCTX_2_IRQ_TARGET_SET(x) (((x) & 0x3FF) << 22) +#define XHCI_SCTX_2_IRQ_TARGET_GET(x) (((x) >> 22) & 0x3FF) + volatile uint32_t dwSctx3; +#define XHCI_SCTX_3_DEV_ADDR_SET(x) ((x) & 0xFF) +#define XHCI_SCTX_3_DEV_ADDR_GET(x) ((x) & 0xFF) +#define XHCI_SCTX_3_SLOT_STATE_SET(x) (((x) & 0x1F) << 27) +#define XHCI_SCTX_3_SLOT_STATE_GET(x) (((x) >> 27) & 0x1F) + volatile uint32_t dwSctx4; + volatile uint32_t dwSctx5; + volatile uint32_t dwSctx6; + volatile uint32_t dwSctx7; +}; + +struct xhci_endp_ctx { + volatile uint32_t dwEpCtx0; +#define XHCI_EPCTX_0_EPSTATE_SET(x) ((x) & 0x7) +#define XHCI_EPCTX_0_EPSTATE_GET(x) ((x) & 0x7) +#define XHCI_EPCTX_0_MULT_SET(x) (((x) & 0x3) << 8) +#define XHCI_EPCTX_0_MULT_GET(x) (((x) >> 8) & 0x3) +#define XHCI_EPCTX_0_MAXP_STREAMS_SET(x) (((x) & 0x1F) << 10) +#define XHCI_EPCTX_0_MAXP_STREAMS_GET(x) (((x) >> 10) & 0x1F) +#define XHCI_EPCTX_0_LSA_SET(x) (((x) & 0x1) << 15) +#define XHCI_EPCTX_0_LSA_GET(x) (((x) >> 15) & 0x1) +#define XHCI_EPCTX_0_IVAL_SET(x) (((x) & 0xFF) << 16) +#define XHCI_EPCTX_0_IVAL_GET(x) (((x) >> 16) & 0xFF) + volatile uint32_t dwEpCtx1; +#define XHCI_EPCTX_1_CERR_SET(x) (((x) & 0x3) << 1) +#define XHCI_EPCTX_1_CERR_GET(x) (((x) >> 1) & 0x3) +#define XHCI_EPCTX_1_EPTYPE_SET(x) (((x) & 0x7) << 3) +#define XHCI_EPCTX_1_EPTYPE_GET(x) (((x) >> 3) & 0x7) +#define XHCI_EPCTX_1_HID_SET(x) (((x) & 0x1) << 7) +#define XHCI_EPCTX_1_HID_GET(x) (((x) >> 7) & 0x1) +#define XHCI_EPCTX_1_MAXB_SET(x) (((x) & 0xFF) << 8) +#define XHCI_EPCTX_1_MAXB_GET(x) (((x) >> 8) & 0xFF) +#define XHCI_EPCTX_1_MAXP_SIZE_SET(x) (((x) & 0xFFFF) << 16) +#define XHCI_EPCTX_1_MAXP_SIZE_GET(x) (((x) >> 16) & 0xFFFF) + volatile uint64_t qwEpCtx2; +#define XHCI_EPCTX_2_DCS_SET(x) ((x) & 0x1) +#define XHCI_EPCTX_2_DCS_GET(x) ((x) & 0x1) +#define XHCI_EPCTX_2_TR_DQ_PTR_MASK 0xFFFFFFFFFFFFFFF0U + volatile uint32_t dwEpCtx4; +#define XHCI_EPCTX_4_AVG_TRB_LEN_SET(x) ((x) & 0xFFFF) +#define XHCI_EPCTX_4_AVG_TRB_LEN_GET(x) ((x) & 0xFFFF) +#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x) (((x) & 0xFFFF) << 16) +#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_GET(x) (((x) >> 16) & 0xFFFF) + volatile uint32_t dwEpCtx5; + volatile uint32_t dwEpCtx6; + volatile uint32_t dwEpCtx7; +}; + +struct xhci_input_ctx { +#define XHCI_INCTX_NON_CTRL_MASK 0xFFFFFFFCU + volatile uint32_t dwInCtx0; +#define XHCI_INCTX_0_DROP_MASK(n) (1U << (n)) + volatile uint32_t dwInCtx1; +#define XHCI_INCTX_1_ADD_MASK(n) (1U << (n)) + volatile uint32_t dwInCtx2; + volatile uint32_t dwInCtx3; + volatile uint32_t dwInCtx4; + volatile uint32_t dwInCtx5; + volatile uint32_t dwInCtx6; + volatile uint32_t dwInCtx7; +}; + +struct xhci_input_dev_ctx { + struct xhci_input_ctx ctx_input; + struct xhci_slot_ctx ctx_slot; + struct xhci_endp_ctx ctx_ep[XHCI_MAX_ENDPOINTS - 1]; +}; + +struct xhci_dev_ctx { + struct xhci_slot_ctx ctx_slot; + struct xhci_endp_ctx ctx_ep[XHCI_MAX_ENDPOINTS - 1]; +} __aligned(XHCI_DEV_CTX_ALIGN); + +struct xhci_stream_ctx { + volatile uint64_t qwSctx0; +#define XHCI_SCTX_0_DCS_GET(x) ((x) & 0x1) +#define XHCI_SCTX_0_DCS_SET(x) ((x) & 0x1) +#define XHCI_SCTX_0_SCT_SET(x) (((x) & 0x7) << 1) +#define XHCI_SCTX_0_SCT_GET(x) (((x) >> 1) & 0x7) +#define XHCI_SCTX_0_SCT_SEC_TR_RING 0x0 +#define XHCI_SCTX_0_SCT_PRIM_TR_RING 0x1 +#define XHCI_SCTX_0_SCT_PRIM_SSA_8 0x2 +#define XHCI_SCTX_0_SCT_PRIM_SSA_16 0x3 +#define XHCI_SCTX_0_SCT_PRIM_SSA_32 0x4 +#define XHCI_SCTX_0_SCT_PRIM_SSA_64 0x5 +#define XHCI_SCTX_0_SCT_PRIM_SSA_128 0x6 +#define XHCI_SCTX_0_SCT_PRIM_SSA_256 0x7 +#define XHCI_SCTX_0_TR_DQ_PTR_MASK 0xFFFFFFFFFFFFFFF0U + volatile uint32_t dwSctx2; + volatile uint32_t dwSctx3; +}; + +struct xhci_trb { + volatile uint64_t qwTrb0; +#define XHCI_TRB_0_WLENGTH_MASK (0xFFFFULL << 48) + volatile uint32_t dwTrb2; +#define XHCI_TRB_2_ERROR_GET(x) (((x) >> 24) & 0xFF) +#define XHCI_TRB_2_ERROR_SET(x) (((x) & 0xFF) << 24) +#define XHCI_TRB_2_TDSZ_GET(x) (((x) >> 17) & 0x1F) +#define XHCI_TRB_2_TDSZ_SET(x) (((x) & 0x1F) << 17) +#define XHCI_TRB_2_REM_GET(x) ((x) & 0xFFFFFF) +#define XHCI_TRB_2_REM_SET(x) ((x) & 0xFFFFFF) +#define XHCI_TRB_2_BYTES_GET(x) ((x) & 0x1FFFF) +#define XHCI_TRB_2_BYTES_SET(x) ((x) & 0x1FFFF) +#define XHCI_TRB_2_IRQ_GET(x) (((x) >> 22) & 0x3FF) +#define XHCI_TRB_2_IRQ_SET(x) (((x) & 0x3FF) << 22) +#define XHCI_TRB_2_STREAM_GET(x) (((x) >> 16) & 0xFFFF) +#define XHCI_TRB_2_STREAM_SET(x) (((x) & 0xFFFF) << 16) + + volatile uint32_t dwTrb3; +#define XHCI_TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F) +#define XHCI_TRB_3_TYPE_SET(x) (((x) & 0x3F) << 10) +#define XHCI_TRB_3_CYCLE_BIT (1U << 0) +#define XHCI_TRB_3_TC_BIT (1U << 1) /* command ring only */ +#define XHCI_TRB_3_ENT_BIT (1U << 1) /* transfer ring only */ +#define XHCI_TRB_3_ISP_BIT (1U << 2) +#define XHCI_TRB_3_NSNOOP_BIT (1U << 3) +#define XHCI_TRB_3_CHAIN_BIT (1U << 4) +#define XHCI_TRB_3_IOC_BIT (1U << 5) +#define XHCI_TRB_3_IDT_BIT (1U << 6) +#define XHCI_TRB_3_TBC_GET(x) (((x) >> 7) & 3) +#define XHCI_TRB_3_TBC_SET(x) (((x) & 3) << 7) +#define XHCI_TRB_3_BEI_BIT (1U << 9) +#define XHCI_TRB_3_DCEP_BIT (1U << 9) +#define XHCI_TRB_3_PRSV_BIT (1U << 9) +#define XHCI_TRB_3_BSR_BIT (1U << 9) +#define XHCI_TRB_3_TRT_MASK (3U << 16) +#define XHCI_TRB_3_TRT_NONE (0U << 16) +#define XHCI_TRB_3_TRT_OUT (2U << 16) +#define XHCI_TRB_3_TRT_IN (3U << 16) +#define XHCI_TRB_3_DIR_IN (1U << 16) +#define XHCI_TRB_3_TLBPC_GET(x) (((x) >> 16) & 0xF) +#define XHCI_TRB_3_TLBPC_SET(x) (((x) & 0xF) << 16) +#define XHCI_TRB_3_EP_GET(x) (((x) >> 16) & 0x1F) +#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 16) +#define XHCI_TRB_3_FRID_GET(x) (((x) >> 20) & 0x7FF) +#define XHCI_TRB_3_FRID_SET(x) (((x) & 0x7FF) << 20) +#define XHCI_TRB_3_ISO_SIA_BIT (1U << 31) +#define XHCI_TRB_3_SUSP_EP_BIT (1U << 23) +#define XHCI_TRB_3_SLOT_GET(x) (((x) >> 24) & 0xFF) +#define XHCI_TRB_3_SLOT_SET(x) (((x) & 0xFF) << 24) + +/* Commands */ +#define XHCI_TRB_TYPE_RESERVED 0x00 +#define XHCI_TRB_TYPE_NORMAL 0x01 +#define XHCI_TRB_TYPE_SETUP_STAGE 0x02 +#define XHCI_TRB_TYPE_DATA_STAGE 0x03 +#define XHCI_TRB_TYPE_STATUS_STAGE 0x04 +#define XHCI_TRB_TYPE_ISOCH 0x05 +#define XHCI_TRB_TYPE_LINK 0x06 +#define XHCI_TRB_TYPE_EVENT_DATA 0x07 +#define XHCI_TRB_TYPE_NOOP 0x08 +#define XHCI_TRB_TYPE_ENABLE_SLOT 0x09 +#define XHCI_TRB_TYPE_DISABLE_SLOT 0x0A +#define XHCI_TRB_TYPE_ADDRESS_DEVICE 0x0B +#define XHCI_TRB_TYPE_CONFIGURE_EP 0x0C +#define XHCI_TRB_TYPE_EVALUATE_CTX 0x0D +#define XHCI_TRB_TYPE_RESET_EP 0x0E +#define XHCI_TRB_TYPE_STOP_EP 0x0F +#define XHCI_TRB_TYPE_SET_TR_DEQUEUE 0x10 +#define XHCI_TRB_TYPE_RESET_DEVICE 0x11 +#define XHCI_TRB_TYPE_FORCE_EVENT 0x12 +#define XHCI_TRB_TYPE_NEGOTIATE_BW 0x13 +#define XHCI_TRB_TYPE_SET_LATENCY_TOL 0x14 +#define XHCI_TRB_TYPE_GET_PORT_BW 0x15 +#define XHCI_TRB_TYPE_FORCE_HEADER 0x16 +#define XHCI_TRB_TYPE_NOOP_CMD 0x17 + +/* Events */ +#define XHCI_TRB_EVENT_TRANSFER 0x20 +#define XHCI_TRB_EVENT_CMD_COMPLETE 0x21 +#define XHCI_TRB_EVENT_PORT_STS_CHANGE 0x22 +#define XHCI_TRB_EVENT_BW_REQUEST 0x23 +#define XHCI_TRB_EVENT_DOORBELL 0x24 +#define XHCI_TRB_EVENT_HOST_CTRL 0x25 +#define XHCI_TRB_EVENT_DEVICE_NOTIFY 0x26 +#define XHCI_TRB_EVENT_MFINDEX_WRAP 0x27 + +/* Error codes */ +#define XHCI_TRB_ERROR_INVALID 0x00 +#define XHCI_TRB_ERROR_SUCCESS 0x01 +#define XHCI_TRB_ERROR_DATA_BUF 0x02 +#define XHCI_TRB_ERROR_BABBLE 0x03 +#define XHCI_TRB_ERROR_XACT 0x04 +#define XHCI_TRB_ERROR_TRB 0x05 +#define XHCI_TRB_ERROR_STALL 0x06 +#define XHCI_TRB_ERROR_RESOURCE 0x07 +#define XHCI_TRB_ERROR_BANDWIDTH 0x08 +#define XHCI_TRB_ERROR_NO_SLOTS 0x09 +#define XHCI_TRB_ERROR_STREAM_TYPE 0x0A +#define XHCI_TRB_ERROR_SLOT_NOT_ON 0x0B +#define XHCI_TRB_ERROR_ENDP_NOT_ON 0x0C +#define XHCI_TRB_ERROR_SHORT_PKT 0x0D +#define XHCI_TRB_ERROR_RING_UNDERRUN 0x0E +#define XHCI_TRB_ERROR_RING_OVERRUN 0x0F +#define XHCI_TRB_ERROR_VF_RING_FULL 0x10 +#define XHCI_TRB_ERROR_PARAMETER 0x11 +#define XHCI_TRB_ERROR_BW_OVERRUN 0x12 +#define XHCI_TRB_ERROR_CONTEXT_STATE 0x13 +#define XHCI_TRB_ERROR_NO_PING_RESP 0x14 +#define XHCI_TRB_ERROR_EV_RING_FULL 0x15 +#define XHCI_TRB_ERROR_INCOMPAT_DEV 0x16 +#define XHCI_TRB_ERROR_MISSED_SERVICE 0x17 +#define XHCI_TRB_ERROR_CMD_RING_STOP 0x18 +#define XHCI_TRB_ERROR_CMD_ABORTED 0x19 +#define XHCI_TRB_ERROR_STOPPED 0x1A +#define XHCI_TRB_ERROR_LENGTH 0x1B +#define XHCI_TRB_ERROR_BAD_MELAT 0x1D +#define XHCI_TRB_ERROR_ISOC_OVERRUN 0x1F +#define XHCI_TRB_ERROR_EVENT_LOST 0x20 +#define XHCI_TRB_ERROR_UNDEFINED 0x21 +#define XHCI_TRB_ERROR_INVALID_SID 0x22 +#define XHCI_TRB_ERROR_SEC_BW 0x23 +#define XHCI_TRB_ERROR_SPLIT_XACT 0x24 +} __aligned(4); + +struct xhci_dev_endpoint_trbs { + struct xhci_trb trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS]; +}; + +#define XHCI_TD_PAGE_NBUF 17 /* units, room enough for 64Kbytes */ +#define XHCI_TD_PAGE_SIZE 4096 /* bytes */ +#define XHCI_TD_PAYLOAD_MAX (XHCI_TD_PAGE_SIZE * (XHCI_TD_PAGE_NBUF - 1)) + +struct xhci_td { + struct xhci_trb td_trb[XHCI_TD_PAGE_NBUF + 1]; + +/* + * Extra information needed: + */ + uint64_t td_self; + struct xhci_td *next; + struct xhci_td *alt_next; + struct xhci_td *obj_next; + struct usb_page_cache *page_cache; + uint32_t len; + uint32_t remainder; + uint8_t ntrb; + uint8_t status; +} __aligned(XHCI_TRB_ALIGN); + +struct xhci_command { + struct xhci_trb trb; + TAILQ_ENTRY(xhci_command) entry; +}; + +struct xhci_event_ring_seg { + volatile uint64_t qwEvrsTablePtr; + volatile uint32_t dwEvrsTableSize; + volatile uint32_t dwEvrsReserved; +}; + +struct xhci_hw_root { + struct xhci_event_ring_seg hwr_ring_seg[XHCI_MAX_RSEG]; + struct { + volatile uint64_t dummy; + } __aligned(64) padding; + struct xhci_trb hwr_events[XHCI_MAX_EVENTS]; + struct xhci_trb hwr_commands[XHCI_MAX_COMMANDS]; +}; + +struct xhci_endpoint_ext { + struct xhci_trb *trb; + struct usb_xfer *xfer[XHCI_MAX_TRANSFERS - 1]; + struct usb_page_cache *page_cache; + uint64_t physaddr; + uint8_t trb_used; + uint8_t trb_index; + uint8_t trb_halted; + uint8_t trb_running; +}; + +enum { + XHCI_ST_DISABLED, + XHCI_ST_ENABLED, + XHCI_ST_DEFAULT, + XHCI_ST_ADDRESSED, + XHCI_ST_CONFIGURED, + XHCI_ST_MAX +}; + +struct xhci_hw_dev { + struct usb_page_cache device_pc; + struct usb_page_cache input_pc; + struct usb_page_cache endpoint_pc; + + struct usb_page device_pg; + struct usb_page input_pg; + struct usb_page endpoint_pg; + + struct xhci_endpoint_ext endp[XHCI_MAX_ENDPOINTS]; + + uint8_t state; + uint8_t nports; + uint8_t tt; + uint8_t reserved; +}; + +struct xhci_hw_softc { + struct usb_page_cache root_pc; + struct usb_page_cache ctx_pc; + struct usb_page_cache scratch_pc[XHCI_MAX_SCRATCHPADS]; + + struct usb_page root_pg; + struct usb_page ctx_pg; + struct usb_page scratch_pg[XHCI_MAX_SCRATCHPADS]; + + struct xhci_hw_dev devs[XHCI_MAX_DEVICES + 1]; +}; + +struct xhci_config_desc { + struct usb_config_descriptor confd; + struct usb_interface_descriptor ifcd; + struct usb_endpoint_descriptor endpd; + struct usb_endpoint_ss_comp_descriptor endpcd; +} __packed; + +struct xhci_bos_desc { + struct usb_bos_descriptor bosd; + struct usb_devcap_usb2ext_descriptor usb2extd; + struct usb_devcap_ss_descriptor usbdcd; + struct usb_devcap_container_id_descriptor cidd; +} __packed; + +union xhci_hub_desc { + struct usb_status stat; + struct usb_port_status ps; + struct usb_hub_ss_descriptor hubd; + uint8_t temp[128]; +}; + +struct xhci_softc { + struct xhci_hw_softc sc_hw; + /* base device */ + struct usb_bus sc_bus; + /* configure process */ + struct usb_process sc_config_proc; + struct usb_bus_msg sc_config_msg[2]; + + union xhci_hub_desc sc_hub_desc; + + struct cv sc_cmd_cv; + struct sx sc_cmd_sx; + + struct usb_device *sc_devices[XHCI_MAX_DEVICES]; + struct resource *sc_io_res; + struct resource *sc_irq_res; + + void *sc_intr_hdl; + bus_size_t sc_io_size; + bus_space_tag_t sc_io_tag; + bus_space_handle_t sc_io_hdl; + /* last pending command address */ + uint64_t sc_cmd_addr; + /* result of command */ + uint32_t sc_cmd_result[2]; + /* copy of cmd register */ + uint32_t sc_cmd; + /* worst case exit latency */ + uint32_t sc_exit_lat_max; + + /* offset to operational registers */ + uint32_t sc_oper_off; + /* offset to capability registers */ + uint32_t sc_capa_off; + /* offset to runtime registers */ + uint32_t sc_runt_off; + /* offset to doorbell registers */ + uint32_t sc_door_off; + + /* chip specific */ + uint16_t sc_erst_max; + uint16_t sc_event_idx; + uint16_t sc_command_idx; + + uint8_t sc_event_ccs; + uint8_t sc_command_ccs; + /* number of XHCI device slots */ + uint8_t sc_noslot; + /* number of ports on root HUB */ + uint8_t sc_noport; + /* number of scratch pages */ + uint8_t sc_noscratch; + /* root HUB device configuration */ + uint8_t sc_conf; + uint8_t sc_hub_idata[2]; + + /* vendor string for root HUB */ + char sc_vendor[16]; +}; + +#define XHCI_CMD_LOCK(sc) sx_xlock(&(sc)->sc_cmd_sx) +#define XHCI_CMD_UNLOCK(sc) sx_xunlock(&(sc)->sc_cmd_sx) +#define XHCI_CMD_ASSERT_LOCKED(sc) sx_assert(&(sc)->sc_cmd_sx, SA_LOCKED) + +/* prototypes */ + +usb_error_t xhci_halt_controller(struct xhci_softc *); +usb_error_t xhci_init(struct xhci_softc *, device_t); +usb_error_t xhci_start_controller(struct xhci_softc *); +void xhci_interrupt(struct xhci_softc *); +void xhci_resume(struct xhci_softc *); +void xhci_shutdown(struct xhci_softc *); +void xhci_suspend(struct xhci_softc *); +void xhci_uninit(struct xhci_softc *); + +#endif /* _XHCI_H_ */ diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c new file mode 100644 index 00000000000..1cc9d11018a --- /dev/null +++ b/sys/dev/usb/controller/xhci_pci.c @@ -0,0 +1,318 @@ +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static device_probe_t xhci_pci_probe; +static device_attach_t xhci_pci_attach; +static device_detach_t xhci_pci_detach; +static device_suspend_t xhci_pci_suspend; +static device_resume_t xhci_pci_resume; +static device_shutdown_t xhci_pci_shutdown; +static void xhci_pci_takecontroller(device_t); + +static device_method_t xhci_device_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, xhci_pci_probe), + DEVMETHOD(device_attach, xhci_pci_attach), + DEVMETHOD(device_detach, xhci_pci_detach), + DEVMETHOD(device_suspend, xhci_pci_suspend), + DEVMETHOD(device_resume, xhci_pci_resume), + DEVMETHOD(device_shutdown, xhci_pci_shutdown), + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t xhci_driver = { + .name = "xhci", + .methods = xhci_device_methods, + .size = sizeof(struct xhci_softc), +}; + +static devclass_t xhci_devclass; + +DRIVER_MODULE(xhci, pci, xhci_driver, xhci_devclass, 0, 0); +MODULE_DEPEND(xhci, usb, 1, 1, 1); + +static int +xhci_pci_suspend(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + + err = bus_generic_suspend(self); + if (err) + return (err); + xhci_suspend(sc); + return (0); +} + +static int +xhci_pci_resume(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + + xhci_pci_takecontroller(self); + xhci_resume(sc); + + bus_generic_resume(self); + + return (0); +} + +static int +xhci_pci_shutdown(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + + err = bus_generic_shutdown(self); + if (err) + return (err); + xhci_shutdown(sc); + + return (0); +} + +static const char * +xhci_pci_match(device_t self) +{ + if ((pci_get_class(self) == PCIC_SERIALBUS) + && (pci_get_subclass(self) == PCIS_SERIALBUS_USB) + && (pci_get_progif(self) == PCI_INTERFACE_XHCI)) { + return ("XHCI (generic) USB 3.0 controller"); + } + return (NULL); /* dunno */ +} + +static int +xhci_pci_probe(device_t self) +{ + const char *desc = xhci_pci_match(self); + + if (desc) { + device_set_desc(self, desc); + return (0); + } else { + return (ENXIO); + } +} + +static int +xhci_pci_attach(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + int err; + int rid; + + /* XXX check for 64-bit capability */ + + if (xhci_init(sc, self)) { + device_printf(self, "Could not initialize softc\n"); + goto error; + } + + pci_enable_busmaster(self); + + rid = PCI_XHCI_CBMEM; + sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->sc_io_res) { + device_printf(self, "Could not map memory\n"); + goto error; + } + sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); + sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); + sc->sc_io_size = rman_get_size(sc->sc_io_res); + + rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (sc->sc_irq_res == NULL) { + device_printf(self, "Could not allocate IRQ\n"); + goto error; + } + sc->sc_bus.bdev = device_add_child(self, "usbus", -1); + if (sc->sc_bus.bdev == NULL) { + device_printf(self, "Could not add USB device\n"); + goto error; + } + device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); + + sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self)); + +#if (__FreeBSD_version >= 700031) + err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); +#else + err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl); +#endif + if (err) { + device_printf(self, "Could not setup IRQ, err=%d\n", err); + sc->sc_intr_hdl = NULL; + goto error; + } + xhci_pci_takecontroller(self); + + err = xhci_halt_controller(sc); + + if (err == 0) + err = xhci_start_controller(sc); + + if (err == 0) + err = device_probe_and_attach(sc->sc_bus.bdev); + + if (err) { + device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); + goto error; + } + return (0); + +error: + xhci_pci_detach(self); + return (ENXIO); +} + +static int +xhci_pci_detach(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + device_t bdev; + + if (sc->sc_bus.bdev != NULL) { + bdev = sc->sc_bus.bdev; + device_detach(bdev); + device_delete_child(self, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_all_children(self); + + pci_disable_busmaster(self); + + if (sc->sc_irq_res && sc->sc_intr_hdl) { + + xhci_halt_controller(sc); + + bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); + sc->sc_intr_hdl = NULL; + } + if (sc->sc_irq_res) { + bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + if (sc->sc_io_res) { + bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM, + sc->sc_io_res); + sc->sc_io_res = NULL; + } + + xhci_uninit(sc); + + return (0); +} + +static void +xhci_pci_takecontroller(device_t self) +{ + struct xhci_softc *sc = device_get_softc(self); + uint32_t cparams; + uint32_t eecp; + uint32_t eec; + uint16_t to; + uint8_t bios_sem; + + cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); + + eec = -1; + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = XHCI_HCS0_XECP(cparams) << 2; eecp != 0 && XHCI_XECP_NEXT(eec); + eecp += XHCI_XECP_NEXT(eec) << 2) { + eec = XREAD4(sc, capa, eecp); + + if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) + continue; + bios_sem = XREAD1(sc, capa, eecp + + XHCI_XECP_BIOS_SEM); + if (bios_sem == 0) + continue; + device_printf(sc->sc_bus.bdev, "waiting for BIOS " + "to give up control\n"); + XWRITE1(sc, capa, eecp + + XHCI_XECP_OS_SEM, 1); + to = 500; + while (1) { + bios_sem = XREAD1(sc, capa, eecp + + XHCI_XECP_BIOS_SEM); + if (bios_sem == 0) + break; + + if (--to == 0) { + device_printf(sc->sc_bus.bdev, + "timed out waiting for BIOS\n"); + break; + } + usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ + } + } +} diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h new file mode 100644 index 00000000000..fb2d1cad21e --- /dev/null +++ b/sys/dev/usb/controller/xhcireg.h @@ -0,0 +1,219 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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. + */ + +#ifndef _XHCIREG_H_ +#define _XHCIREG_H_ + +/* XHCI PCI config registers */ +#define PCI_XHCI_CBMEM 0x10 /* configuration base MEM */ +#define PCI_XHCI_USBREV 0x60 /* RO USB protocol revision */ +#define PCI_USB_REV_3_0 0x30 /* USB 3.0 */ +#define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */ +#define PCI_INTERFACE_XHCI 0x30 /* USB 3.0 - XHCI */ + +/* XHCI capability registers */ +#define XHCI_CAPLENGTH 0x00 /* RO capability */ +#define XHCI_RESERVED 0x01 /* Reserved */ +#define XHCI_HCIVERSION 0x02 /* RO Interface version number */ +#define XHCI_HCIVERSION_0_9 0x0090 /* xHCI version 0.9 */ +#define XHCI_HCIVERSION_1_0 0x0100 /* xHCI version 1.0 */ +#define XHCI_HCSPARAMS1 0x04 /* RO structual parameters 1 */ +#define XHCI_HCS1_DEVSLOT_MAX(x)((x) & 0xFF) +#define XHCI_HCS1_IRQ_MAX(x) (((x) >> 8) & 0x3FF) +#define XHCI_HCS1_N_PORTS(x) (((x) >> 24) & 0xFF) +#define XHCI_HCSPARAMS2 0x08 /* RO structual parameters 2 */ +#define XHCI_HCS2_IST(x) ((x) & 0xF) +#define XHCI_HCS2_ERST_MAX(x) (((x) >> 4) & 0xF) +#define XHCI_HCS2_SPR(x) (((x) >> 24) & 0x1) +#define XHCI_HCS2_SPB_MAX(x) (((x) >> 27) & 0x7F) +#define XHCI_HCSPARAMS3 0x0C /* RO structual parameters 3 */ +#define XHCI_HCS3_U1_DEL(x) ((x) & 0xFF) +#define XHCI_HCS3_U2_DEL(x) (((x) >> 16) & 0xFFFF) +#define XHCI_HCSPARAMS0 0x10 /* RO capability parameters */ +#define XHCI_HCS0_AC64(x) ((x) & 0x1) /* 64-bit capable */ +#define XHCI_HCS0_BNC(x) (((x) >> 1) & 0x1) /* BW negotiation */ +#define XHCI_HCS0_CSZ(x) (((x) >> 2) & 0x1) /* context size */ +#define XHCI_HCS0_PPC(x) (((x) >> 3) & 0x1) /* port power control */ +#define XHCI_HCS0_PIND(x) (((x) >> 4) & 0x1) /* port indicators */ +#define XHCI_HCS0_LHRC(x) (((x) >> 5) & 0x1) /* light HC reset */ +#define XHCI_HCS0_LTC(x) (((x) >> 6) & 0x1) /* latency tolerance msg */ +#define XHCI_HCS0_NSS(x) (((x) >> 7) & 0x1) /* no secondary sid */ +#define XHCI_HCS0_PSA_SZ_MAX(x) (((x) >> 12) & 0xF) /* max pri. stream array size */ +#define XHCI_HCS0_XECP(x) (((x) >> 16) & 0xFFFF) /* extended capabilities pointer */ +#define XHCI_DBOFF 0x14 /* RO doorbell offset */ +#define XHCI_RTSOFF 0x18 /* RO runtime register space offset */ + +/* XHCI operational registers. Offset given by XHCI_CAPLENGTH register */ +#define XHCI_USBCMD 0x00 /* XHCI command */ +#define XHCI_CMD_RS 0x00000001 /* RW Run/Stop */ +#define XHCI_CMD_HCRST 0x00000002 /* RW Host Controller Reset */ +#define XHCI_CMD_INTE 0x00000004 /* RW Interrupter Enable */ +#define XHCI_CMD_HSEE 0x00000008 /* RW Host System Error Enable */ +#define XHCI_CMD_LHCRST 0x00000080 /* RO/RW Light Host Controller Reset */ +#define XHCI_CMD_CSS 0x00000100 /* RW Controller Save State */ +#define XHCI_CMD_CRS 0x00000200 /* RW Controller Restore State */ +#define XHCI_CMD_EWE 0x00000400 /* RW Enable Wrap Event */ +#define XHCI_CMD_EU3S 0x00000800 /* RW Enable U3 MFINDEX Stop */ +#define XHCI_USBSTS 0x04 /* XHCI status */ +#define XHCI_STS_HCH 0x00000001 /* RO - Host Controller Halted */ +#define XHCI_STS_HSE 0x00000004 /* RW - Host System Error */ +#define XHCI_STS_EINT 0x00000008 /* RW - Event Interrupt */ +#define XHCI_STS_PCD 0x00000010 /* RW - Port Change Detect */ +#define XHCI_STS_SSS 0x00000100 /* RO - Save State Status */ +#define XHCI_STS_RSS 0x00000200 /* RO - Restore State Status */ +#define XHCI_STS_SRE 0x00000400 /* RW - Save/Restore Error */ +#define XHCI_STS_CNR 0x00000800 /* RO - Controller Not Ready */ +#define XHCI_STS_HCE 0x00001000 /* RO - Host Controller Error */ +#define XHCI_PAGESIZE 0x08 /* XHCI page size mask */ +#define XHCI_PAGESIZE_4K 0x00000001 /* 4K Page Size */ +#define XHCI_PAGESIZE_8K 0x00000002 /* 8K Page Size */ +#define XHCI_PAGESIZE_16K 0x00000004 /* 16K Page Size */ +#define XHCI_PAGESIZE_32K 0x00000008 /* 32K Page Size */ +#define XHCI_PAGESIZE_64K 0x00000010 /* 64K Page Size */ +#define XHCI_DNCTRL 0x14 /* XHCI device notification control */ +#define XHCI_DNCTRL_MASK(n) (1U << (n)) +#define XHCI_CRCR_LO 0x18 /* XHCI command ring control */ +#define XHCI_CRCR_LO_RCS 0x00000001 /* RW - consumer cycle state */ +#define XHCI_CRCR_LO_CS 0x00000002 /* RW - command stop */ +#define XHCI_CRCR_LO_CA 0x00000004 /* RW - command abort */ +#define XHCI_CRCR_LO_CRR 0x00000008 /* RW - command ring running */ +#define XHCI_CRCR_LO_MASK 0x0000000F +#define XHCI_CRCR_HI 0x1C /* XHCI command ring control */ +#define XHCI_DCBAAP_LO 0x30 /* XHCI dev context BA pointer */ +#define XHCI_DCBAAP_HI 0x34 /* XHCI dev context BA pointer */ +#define XHCI_CONFIG 0x38 +#define XHCI_CONFIG_SLOTS_MASK 0x000000FF /* RW - number of device slots enabled */ + +/* XHCI port status registers */ +#define XHCI_PORTSC(n) (0x3F0 + (0x10 * (n))) /* XHCI port status */ +#define XHCI_PS_CCS 0x00000001 /* RO - current connect status */ +#define XHCI_PS_PED 0x00000002 /* RW - port enabled / disabled */ +#define XHCI_PS_OCA 0x00000008 /* RO - over current active */ +#define XHCI_PS_PR 0x00000010 /* RW - port reset */ +#define XHCI_PS_PLS_GET(x) (((x) >> 5) & 0xF) /* RW - port link state */ +#define XHCI_PS_PLS_SET(x) (((x) & 0xF) << 5) /* RW - port link state */ +#define XHCI_PS_PP 0x00000100 /* RW - port power */ +#define XHCI_PS_SPEED_GET(x) (((x) >> 10) & 0xF) /* RO - port speed */ +#define XHCI_PS_PIC_GET(x) (((x) >> 14) & 0x3) /* RW - port indicator */ +#define XHCI_PS_PIC_SET(x) (((x) & 0x3) << 14) /* RW - port indicator */ +#define XHCI_PS_LWS 0x00010000 /* RW - port link state write strobe */ +#define XHCI_PS_CSC 0x00020000 /* RW - connect status change */ +#define XHCI_PS_PEC 0x00040000 /* RW - port enable/disable change */ +#define XHCI_PS_WRC 0x00080000 /* RW - warm port reset change */ +#define XHCI_PS_OCC 0x00100000 /* RW - over-current change */ +#define XHCI_PS_PRC 0x00200000 /* RW - port reset change */ +#define XHCI_PS_PLC 0x00400000 /* RW - port link state change */ +#define XHCI_PS_CEC 0x00800000 /* RW - config error change */ +#define XHCI_PS_CAS 0x01000000 /* RO - cold attach status */ +#define XHCI_PS_WCE 0x02000000 /* RW - wake on connect enable */ +#define XHCI_PS_WDE 0x04000000 /* RW - wake on disconnect enable */ +#define XHCI_PS_WOE 0x08000000 /* RW - wake on over-current enable */ +#define XHCI_PS_DR 0x40000000 /* RO - device removable */ +#define XHCI_PS_WPR 0x80000000U /* RW - warm port reset */ +#define XHCI_PS_CLEAR 0x80FF00F7U /* command bits */ + +#define XHCI_PORTPMSC(n) (0x3F4 + (0x10 * (n))) /* XHCI status and control */ +#define XHCI_PM3_U1TO_GET(x) (((x) >> 0) & 0xFF) /* RW - U1 timeout */ +#define XHCI_PM3_U1TO_SET(x) (((x) & 0xFF) << 0) /* RW - U1 timeout */ +#define XHCI_PM3_U2TO_GET(x) (((x) >> 8) & 0xFF) /* RW - U2 timeout */ +#define XHCI_PM3_U2TO_SET(x) (((x) & 0xFF) << 8) /* RW - U2 timeout */ +#define XHCI_PM3_FLA 0x00010000 /* RW - Force Link PM Accept */ +#define XHCI_PM2_L1S_GET(x) (((x) >> 0) & 0x7) /* RO - L1 status */ +#define XHCI_PM2_RWE 0x00000008 /* RW - remote wakup enable */ +#define XHCI_PM2_HIRD_GET(x) (((x) >> 4) & 0xF) /* RW - host initiated resume duration */ +#define XHCI_PM2_HIRD_SET(x) (((x) & 0xF) << 4) /* RW - host initiated resume duration */ +#define XHCI_PM2_L1SLOT_GET(x) (((x) >> 8) & 0xFF) /* RW - L1 device slot */ +#define XHCI_PM2_L1SLOT_SET(x) (((x) & 0xFF) << 8) /* RW - L1 device slot */ +#define XHCI_PM2_HLE 0x00010000 /* RW - hardware LPM enable */ +#define XHCI_PORTLI(n) (0x3F8 + (0x10 * (n))) /* XHCI port link info */ +#define XHCI_PLI3_ERR_GET(x) (((x) >> 0) & 0xFFFF) /* RO - port link errors */ +#define XHCI_PORTRSV(n) (0x3FC + (0x10 * (n))) /* XHCI port reserved */ + +/* XHCI runtime registers. Offset given by XHCI_CAPLENGTH + XHCI_RTSOFF registers */ +#define XHCI_MFINDEX 0x0000 /* RO - microframe index */ +#define XHCI_MFINDEX_GET(x) ((x) & 0x3FFF) +#define XHCI_IMAN(n) (0x0020 + (0x20 * (n))) /* XHCI interrupt management */ +#define XHCI_IMAN_INTR_PEND 0x00000001 /* RW - interrupt pending */ +#define XHCI_IMAN_INTR_ENA 0x00000002 /* RW - interrupt enable */ +#define XHCI_IMOD(n) (0x0024 + (0x20 * (n))) /* XHCI interrupt moderation */ +#define XHCI_IMOD_IVAL_GET(x) (((x) >> 0) & 0xFFFF) /* 250ns unit */ +#define XHCI_IMOD_IVAL_SET(x) (((x) & 0xFFFF) << 0) /* 250ns unit */ +#define XHCI_IMOD_ICNT_GET(x) (((x) >> 16) & 0xFFFF) /* 250ns unit */ +#define XHCI_IMOD_ICNT_SET(x) (((x) & 0xFFFF) << 16) /* 250ns unit */ +#define XHCI_IMOD_DEFAULT 0x000001F4U /* 8000 IRQ/second */ +#define XHCI_ERSTSZ(n) (0x0028 + (0x20 * (n))) /* XHCI event ring segment table size */ +#define XHCI_ERSTS_GET(x) ((x) & 0xFFFF) +#define XHCI_ERSTS_SET(x) ((x) & 0xFFFF) +#define XHCI_ERSTBA_LO(n) (0x0030 + (0x20 * (n))) /* XHCI event ring segment table BA */ +#define XHCI_ERSTBA_HI(n) (0x0034 + (0x20 * (n))) /* XHCI event ring segment table BA */ +#define XHCI_ERDP_LO(n) (0x0038 + (0x20 * (n))) /* XHCI event ring dequeue pointer */ +#define XHCI_ERDP_LO_SINDEX(x) ((x) & 0x7) /* RO - dequeue segment index */ +#define XHCI_ERDP_LO_BUSY 0x00000008 /* RW - event handler busy */ +#define XHCI_ERDP_HI(n) (0x003C + (0x20 * (n))) /* XHCI event ring dequeue pointer */ + +/* XHCI doorbell registers. Offset given by XHCI_CAPLENGTH + XHCI_DBOFF registers */ +#define XHCI_DOORBELL(n) (0x0000 + (4 * (n))) +#define XHCI_DB_TARGET_GET(x) ((x) & 0xFF) /* RW - doorbell target */ +#define XHCI_DB_TARGET_SET(x) ((x) & 0xFF) /* RW - doorbell target */ +#define XHCI_DB_SID_GET(x) (((x) >> 16) & 0xFFFF) /* RW - doorbell stream ID */ +#define XHCI_DB_SID_SET(x) (((x) & 0xFFFF) << 16) /* RW - doorbell stream ID */ + +/* XHCI legacy support */ +#define XHCI_XECP_ID(x) ((x) & 0xFF) +#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF) +#define XHCI_XECP_BIOS_SEM 0x0002 +#define XHCI_XECP_OS_SEM 0x0003 + +/* XHCI capability ID's */ +#define XHCI_ID_USB_LEGACY 0x0001 +#define XHCI_ID_PROTOCOLS 0x0002 +#define XHCI_ID_POWER_MGMT 0x0003 +#define XHCI_ID_VIRTUALIZATION 0x0004 +#define XHCI_ID_MSG_IRQ 0x0005 +#define XHCI_ID_USB_LOCAL_MEM 0x0006 + +/* XHCI register R/W wrappers */ +#define XREAD1(sc, what, a) \ + bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XREAD2(sc, what, a) \ + bus_space_read_2((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XREAD4(sc, what, a) \ + bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off) +#define XWRITE1(sc, what, a, x) \ + bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) +#define XWRITE2(sc, what, a, x) \ + bus_space_write_2((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) +#define XWRITE4(sc, what, a, x) \ + bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \ + (a) + (sc)->sc_##what##_off, (x)) + +#endif /* _XHCIREG_H_ */ diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c index c0fe6d4b386..1ec6f27b377 100644 --- a/sys/dev/usb/input/atp.c +++ b/sys/dev/usb/input/atp.c @@ -2222,3 +2222,4 @@ static devclass_t atp_devclass; DRIVER_MODULE(atp, uhub, atp_driver, atp_devclass, NULL, 0); MODULE_DEPEND(atp, usb, 1, 1, 1); +MODULE_VERSION(atp, 1); diff --git a/sys/dev/usb/input/uep.c b/sys/dev/usb/input/uep.c index 27dec1ff271..048452d84b1 100644 --- a/sys/dev/usb/input/uep.c +++ b/sys/dev/usb/input/uep.c @@ -439,3 +439,4 @@ static driver_t uep_driver = { DRIVER_MODULE(uep, uhub, uep_driver, uep_devclass, NULL, NULL); MODULE_DEPEND(uep, usb, 1, 1, 1); +MODULE_VERSION(uep, 1); diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c index d36ecf36240..5575bdf6b07 100644 --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -801,3 +801,4 @@ static driver_t uhid_driver = { DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, NULL, 0); MODULE_DEPEND(uhid, usb, 1, 1, 1); +MODULE_VERSION(uhid, 1); diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 034a781b2fe..aca5df034ca 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -720,7 +720,7 @@ ukbd_set_leds_callback(struct usb_xfer *xfer, usb_error_t error) break; default: /* Error */ - DPRINTFN(0, "error=%s\n", usbd_errstr(error)); + DPRINTFN(1, "error=%s\n", usbd_errstr(error)); break; } } @@ -1887,3 +1887,4 @@ static driver_t ukbd_driver = { DRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); MODULE_DEPEND(ukbd, usb, 1, 1, 1); +MODULE_VERSION(ukbd, 1); diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c index a41ddaaaf52..c0cab203434 100644 --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -399,6 +399,7 @@ ums_hid_parse(struct ums_softc *sc, device_t dev, const uint8_t *buf, struct ums_info *info = &sc->sc_info[index]; uint32_t flags; uint8_t i; + uint8_t j; if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), hid_input, index, &info->sc_loc_x, &flags, &info->sc_iid_x)) { @@ -476,6 +477,17 @@ ums_hid_parse(struct ums_softc *sc, device_t dev, const uint8_t *buf, break; } } + + /* detect other buttons */ + + for (j = 0; (i < UMS_BUTTON_MAX) && (j < 2); i++, j++) { + if (!hid_locate(buf, len, HID_USAGE2(HUP_MICROSOFT, (j + 1)), + hid_input, index, &info->sc_loc_btn[i], NULL, + &info->sc_iid_btn[i])) { + break; + } + } + info->sc_buttons = i; if (i > sc->sc_buttons) @@ -1010,3 +1022,4 @@ static driver_t ums_driver = { DRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, NULL, 0); MODULE_DEPEND(ums, usb, 1, 1, 1); +MODULE_VERSION(ums, 1); diff --git a/sys/dev/usb/misc/udbp.c b/sys/dev/usb/misc/udbp.c index 5eef3103c31..7e3a4b1c8eb 100644 --- a/sys/dev/usb/misc/udbp.c +++ b/sys/dev/usb/misc/udbp.c @@ -261,6 +261,7 @@ static driver_t udbp_driver = { DRIVER_MODULE(udbp, uhub, udbp_driver, udbp_devclass, udbp_modload, 0); MODULE_DEPEND(udbp, netgraph, NG_ABI_VERSION, NG_ABI_VERSION, NG_ABI_VERSION); MODULE_DEPEND(udbp, usb, 1, 1, 1); +MODULE_VERSION(udbp, 1); static int udbp_modload(module_t mod, int event, void *data) diff --git a/sys/dev/usb/misc/ufm.c b/sys/dev/usb/misc/ufm.c index 136182a1c3e..5889dafe959 100644 --- a/sys/dev/usb/misc/ufm.c +++ b/sys/dev/usb/misc/ufm.c @@ -117,6 +117,7 @@ static driver_t ufm_driver = { DRIVER_MODULE(ufm, uhub, ufm_driver, ufm_devclass, NULL, 0); MODULE_DEPEND(ufm, usb, 1, 1, 1); +MODULE_VERSION(ufm, 1); static int ufm_probe(device_t dev) diff --git a/sys/dev/usb/net/if_aue.c b/sys/dev/usb/net/if_aue.c index a8c0a548b51..7783b2aeb2a 100644 --- a/sys/dev/usb/net/if_aue.c +++ b/sys/dev/usb/net/if_aue.c @@ -281,6 +281,7 @@ MODULE_DEPEND(aue, uether, 1, 1, 1); MODULE_DEPEND(aue, usb, 1, 1, 1); MODULE_DEPEND(aue, ether, 1, 1, 1); MODULE_DEPEND(aue, miibus, 1, 1, 1); +MODULE_VERSION(aue, 1); static const struct usb_ether_methods aue_ue_methods = { .ue_attach_post = aue_attach_post, diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c index e255c855c94..9476e5c0993 100644 --- a/sys/dev/usb/net/if_axe.c +++ b/sys/dev/usb/net/if_axe.c @@ -155,7 +155,9 @@ static const struct usb_device_id axe_devs[] = { AXE_DEV(JVC, MP_PRX1, 0), AXE_DEV(LINKSYS2, USB200M, 0), AXE_DEV(LINKSYS4, USB1000, AXE_FLAG_178), + AXE_DEV(LOGITEC, LAN_GTJU2A, AXE_FLAG_178), AXE_DEV(MELCO, LUAU2KTX, 0), + AXE_DEV(MELCO, LUA3U2AGT, AXE_FLAG_178), AXE_DEV(NETGEAR, FA120, 0), AXE_DEV(OQO, ETHER01PLUS, AXE_FLAG_772), AXE_DEV(PLANEX3, GU1000T, AXE_FLAG_178), @@ -169,7 +171,6 @@ static device_probe_t axe_probe; static device_attach_t axe_attach; static device_detach_t axe_detach; -static usb_callback_t axe_intr_callback; static usb_callback_t axe_bulk_read_callback; static usb_callback_t axe_bulk_write_callback; @@ -213,15 +214,6 @@ static const struct usb_config axe_config[AXE_N_TRANSFER] = { .callback = axe_bulk_read_callback, .timeout = 0, /* no timeout */ }, - - [AXE_INTR_DT_RD] = { - .type = UE_INTERRUPT, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, - .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, - .bufsize = 0, /* use wMaxPacketSize */ - .callback = axe_intr_callback, - }, }; static device_method_t axe_methods[] = { @@ -256,6 +248,7 @@ MODULE_DEPEND(axe, uether, 1, 1, 1); MODULE_DEPEND(axe, usb, 1, 1, 1); MODULE_DEPEND(axe, ether, 1, 1, 1); MODULE_DEPEND(axe, miibus, 1, 1, 1); +MODULE_VERSION(axe, 1); static const struct usb_ether_methods axe_ue_methods = { .ue_attach_post = axe_attach_post, @@ -514,12 +507,19 @@ axe_get_phyno(struct axe_softc *sc, int sel) return (phyno); } +#define AXE_GPIO_WRITE(x, y) do { \ + axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ + uether_pause(ue, (y)); \ +} while (0) + static void axe_ax88178_init(struct axe_softc *sc) { - int gpio0 = 0, phymode = 0; - uint16_t eeprom; + struct usb_ether *ue; + int gpio0, phymode; + uint16_t eeprom, val; + ue = &sc->sc_ue; axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); /* XXX magic */ axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); @@ -528,46 +528,89 @@ axe_ax88178_init(struct axe_softc *sc) /* if EEPROM is invalid we have to use to GPIO0 */ if (eeprom == 0xffff) { - phymode = 0; + phymode = AXE_PHY_MODE_MARVELL; gpio0 = 1; } else { - phymode = eeprom & 7; + phymode = eeprom & 0x7f; gpio0 = (eeprom & 0x80) ? 0 : 1; } - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL); - uether_pause(&sc->sc_ue, hz / 16); - - if ((eeprom >> 8) != 0x01) { - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); - uether_pause(&sc->sc_ue, hz / 32); - - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL); - uether_pause(&sc->sc_ue, hz / 3); - - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL); - uether_pause(&sc->sc_ue, hz / 32); - } else { - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL); - uether_pause(&sc->sc_ue, hz / 32); - - axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL); - uether_pause(&sc->sc_ue, hz / 32); + if (bootverbose) + device_printf(sc->sc_ue.ue_dev, "EEPROM data : 0x%04x\n", + eeprom); + /* Program GPIOs depending on PHY hardware. */ + switch (phymode) { + case AXE_PHY_MODE_MARVELL: + if (gpio0 == 1) { + AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, + hz / 32); + AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, + hz / 32); + AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); + AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, + hz / 32); + } else + AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | + AXE_GPIO1_EN, hz / 32); + break; + case AXE_PHY_MODE_CICADA: + if (gpio0 == 1) + AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | + AXE_GPIO0_EN, hz / 32); + else + AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | + AXE_GPIO1_EN, hz / 32); + break; + case AXE_PHY_MODE_AGERE: + AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | + AXE_GPIO1_EN, hz / 32); + AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | + AXE_GPIO2_EN, hz / 32); + AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); + AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | + AXE_GPIO2_EN, hz / 32); + break; + case AXE_PHY_MODE_REALTEK_8211CL: + case AXE_PHY_MODE_REALTEK_8211BN: + case AXE_PHY_MODE_REALTEK_8251CL: + val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : + AXE_GPIO1 | AXE_GPIO1_EN; + AXE_GPIO_WRITE(val, hz / 32); + AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); + AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); + AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); + if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { + axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, + 0x1F, 0x0005); + axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, + 0x0C, 0x0000); + val = axe_miibus_readreg(ue->ue_dev, sc->sc_phyno, + 0x0001); + axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, + 0x01, val | 0x0080); + axe_miibus_writereg(ue->ue_dev, sc->sc_phyno, + 0x1F, 0x0000); + } + break; + default: + /* Unknown PHY model or no need to program GPIOs. */ + break; } /* soft reset */ axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); - uether_pause(&sc->sc_ue, hz / 4); + uether_pause(ue, hz / 4); axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); - uether_pause(&sc->sc_ue, hz / 4); + uether_pause(ue, hz / 4); /* Enable MII/GMII/RGMII interface to work with external PHY. */ axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); - uether_pause(&sc->sc_ue, hz / 4); + uether_pause(ue, hz / 4); axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); } +#undef AXE_GPIO_WRITE static void axe_ax88772_init(struct axe_softc *sc) @@ -636,10 +679,9 @@ axe_attach_post(struct usb_ether *ue) * Load PHY indexes first. Needed by axe_xxx_init(). */ axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs); -#if 1 - device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", - sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); -#endif + if (bootverbose) + device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n", + sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]); sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); if (sc->sc_phyno == -1) sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); @@ -744,27 +786,6 @@ axe_detach(device_t dev) return (0); } -static void -axe_intr_callback(struct usb_xfer *xfer, usb_error_t error) -{ - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - case USB_ST_SETUP: -tr_setup: - usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); - usbd_transfer_submit(xfer); - return; - - default: /* Error */ - if (error != USB_ERR_CANCELLED) { - /* try to clear stall first */ - usbd_xfer_set_stall(xfer); - goto tr_setup; - } - return; - } -} - #if (AXE_BULK_BUF_SIZE >= 0x10000) #error "Please update axe_bulk_read_callback()!" #endif @@ -811,13 +832,12 @@ axe_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) err = EINVAL; break; } - err = uether_rxbuf(ue, pc, pos, len); + uether_rxbuf(ue, pc, pos, len); pos += len + (len % 2); } - } else { - err = uether_rxbuf(ue, pc, 0, actlen); - } + } else + uether_rxbuf(ue, pc, 0, actlen); if (err != 0) ifp->if_ierrors++; @@ -860,13 +880,15 @@ axe_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete\n"); - ifp->if_opackets++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: - if ((sc->sc_flags & AXE_FLAG_LINK) == 0) { + if ((sc->sc_flags & AXE_FLAG_LINK) == 0 || + (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) { /* - * don't send anything if there is no link ! + * Don't send anything if there is no link or + * controller is busy. */ return; } @@ -905,6 +927,17 @@ tr_setup: usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len); pos += m->m_pkthdr.len; + /* + * XXX + * Update TX packet counter here. This is not + * correct way but it seems that there is no way + * to know how many packets are sent at the end + * of transfer because controller combines + * multiple writes into single one if there is + * room in TX buffer of controller. + */ + ifp->if_opackets++; + /* * if there's a BPF listener, bounce a copy * of this frame to him: @@ -926,6 +959,7 @@ tr_setup: usbd_xfer_set_frame_len(xfer, 0, pos); usbd_transfer_submit(xfer); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; return; default: /* Error */ @@ -933,6 +967,7 @@ tr_setup: usbd_errstr(error)); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ @@ -968,7 +1003,6 @@ axe_start(struct usb_ether *ue) /* * start the USB transfers, if not already started: */ - usbd_transfer_start(sc->sc_xfer[AXE_INTR_DT_RD]); usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]); usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]); } @@ -1065,7 +1099,7 @@ axe_stop(struct usb_ether *ue) AXE_LOCK_ASSERT(sc, MA_OWNED); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); sc->sc_flags &= ~AXE_FLAG_LINK; /* @@ -1073,7 +1107,6 @@ axe_stop(struct usb_ether *ue) */ usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]); usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]); - usbd_transfer_stop(sc->sc_xfer[AXE_INTR_DT_RD]); axe_reset(sc); } diff --git a/sys/dev/usb/net/if_axereg.h b/sys/dev/usb/net/if_axereg.h index ae1a1d6450c..bcc9b4279c3 100644 --- a/sys/dev/usb/net/if_axereg.h +++ b/sys/dev/usb/net/if_axereg.h @@ -153,6 +153,25 @@ #define AXE_772_PHY_NO_EPHY 0x10 /* Embedded 10/100 PHY of AX88772 */ +#define AXE_GPIO0_EN 0x01 +#define AXE_GPIO0 0x02 +#define AXE_GPIO1_EN 0x04 +#define AXE_GPIO1 0x08 +#define AXE_GPIO2_EN 0x10 +#define AXE_GPIO2 0x20 +#define AXE_GPIO_RELOAD_EEPROM 0x80 + +#define AXE_PHY_MODE_MARVELL 0x00 +#define AXE_PHY_MODE_CICADA 0x01 +#define AXE_PHY_MODE_AGERE 0x02 +#define AXE_PHY_MODE_CICADA_V2 0x05 +#define AXE_PHY_MODE_AGERE_GMII 0x06 +#define AXE_PHY_MODE_CICADA_V2_ASIX 0x09 +#define AXE_PHY_MODE_REALTEK_8211CL 0x0C +#define AXE_PHY_MODE_REALTEK_8211BN 0x0D +#define AXE_PHY_MODE_REALTEK_8251CL 0x0E +#define AXE_PHY_MODE_ATTANSIC 0x40 + #define AXE_BULK_BUF_SIZE 16384 /* bytes */ #define AXE_CTL_READ 0x01 @@ -172,7 +191,6 @@ struct axe_sframe_hdr { enum { AXE_BULK_DT_WR, AXE_BULK_DT_RD, - AXE_INTR_DT_RD, AXE_N_TRANSFER, }; diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index b5e7fd464bd..b223577bd8f 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -110,10 +110,13 @@ static uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); #ifdef USB_DEBUG static int cdce_debug = 0; +static int cdce_tx_interval = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); SYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, "Debug level"); +SYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RW, &cdce_tx_interval, 0, + "NCM transmit interval in ms"); #endif static const struct usb_config cdce_config[CDCE_N_TRANSFER] = { @@ -192,7 +195,7 @@ static const struct usb_config cdce_ncm_config[CDCE_N_TRANSFER] = { .if_index = 0, .frames = CDCE_NCM_TX_FRAMES_MAX, .bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN), - .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, + .flags = {.pipe_bof = 1,}, .callback = cdce_ncm_bulk_write_callback, .timeout = 10000, /* 10 seconds */ .usb_mode = USB_MODE_DUAL, /* both modes */ @@ -294,9 +297,22 @@ cdce_ncm_init(struct cdce_softc *sc) { struct usb_ncm_parameters temp; struct usb_device_request req; - uDWord value; + struct usb_ncm_func_descriptor *ufd; + uint8_t value[8]; int err; + ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL, + sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0 - 1, + UCDC_NCM_FUNC_DESC_SUBTYPE, 0 - 1); + + /* verify length of NCM functional descriptor */ + if (ufd != NULL) { + if (ufd->bLength < sizeof(*ufd)) + ufd = NULL; + else + DPRINTFN(1, "Found NCM functional descriptor.\n"); + } + req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS; USETW(req.wValue, 0); @@ -312,22 +328,24 @@ cdce_ncm_init(struct cdce_softc *sc) /* Read correct set of parameters according to device mode */ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { - sc->sc_ncm.rx_max = UGETW(temp.dwNtbInMaxSize); - sc->sc_ncm.tx_max = UGETW(temp.dwNtbOutMaxSize); + sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize); + sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize); sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder); sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor); sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment); + sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); } else { - sc->sc_ncm.rx_max = UGETW(temp.dwNtbOutMaxSize); - sc->sc_ncm.tx_max = UGETW(temp.dwNtbInMaxSize); + sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize); + sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize); sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder); sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor); sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment); + sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); } /* Verify maximum receive length */ - if (err || (sc->sc_ncm.rx_max < 32) || + if ((sc->sc_ncm.rx_max < 32) || (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) { DPRINTFN(1, "Using default maximum receive length\n"); sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN; @@ -335,7 +353,7 @@ cdce_ncm_init(struct cdce_softc *sc) /* Verify maximum transmit length */ - if (err || (sc->sc_ncm.tx_max < 32) || + if ((sc->sc_ncm.tx_max < 32) || (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) { DPRINTFN(1, "Using default maximum transmit length\n"); sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN; @@ -347,7 +365,7 @@ cdce_ncm_init(struct cdce_softc *sc) * - not greater than the maximum transmit length * - not less than four bytes */ - if (err || (sc->sc_ncm.tx_struct_align < 4) || + if ((sc->sc_ncm.tx_struct_align < 4) || (sc->sc_ncm.tx_struct_align != ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) || (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) { @@ -361,7 +379,7 @@ cdce_ncm_init(struct cdce_softc *sc) * - not greater than the maximum transmit length * - not less than four bytes */ - if (err || (sc->sc_ncm.tx_modulus < 4) || + if ((sc->sc_ncm.tx_modulus < 4) || (sc->sc_ncm.tx_modulus != ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) || (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) { @@ -371,11 +389,30 @@ cdce_ncm_init(struct cdce_softc *sc) /* Verify that the payload remainder */ - if (err || (sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) { + if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) { DPRINTFN(1, "Using default transmit remainder: 0 bytes\n"); sc->sc_ncm.tx_remainder = 0; } + /* + * Offset the TX remainder so that IP packet payload starts at + * the tx_modulus. This is not too clear in the specification. + */ + + sc->sc_ncm.tx_remainder = + (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) & + (sc->sc_ncm.tx_modulus - 1); + + /* Verify max datagrams */ + + if (sc->sc_ncm.tx_nframe == 0 || + sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) { + DPRINTFN(1, "Using default max " + "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1); + /* need to reserve one entry for zero padding */ + sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1); + } + /* Additional configuration, will fail in device side mode, which is OK. */ req.bmRequestType = UT_WRITE_CLASS_INTERFACE; @@ -383,8 +420,17 @@ cdce_ncm_init(struct cdce_softc *sc) USETW(req.wValue, 0); req.wIndex[0] = sc->sc_ifaces_index[1]; req.wIndex[1] = 0; - USETW(req.wLength, 4); - USETDW(value, sc->sc_ncm.rx_max); + + if (ufd != NULL && + (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) { + USETW(req.wLength, 8); + USETDW(value, sc->sc_ncm.rx_max); + USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1)); + USETW(value + 6, 0); + } else { + USETW(req.wLength, 4); + USETDW(value, sc->sc_ncm.rx_max); + } err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, &value, 0, NULL, 1000 /* ms */); @@ -567,7 +613,7 @@ alloc_transfers: } else { - bzero(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr)); + memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr)); for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) { @@ -983,6 +1029,18 @@ cdce_handle_request(device_t dev, } #if CDCE_HAVE_NCM +static void +cdce_ncm_tx_zero(struct usb_page_cache *pc, + uint32_t start, uint32_t end) +{ + if (start >= CDCE_NCM_TX_MAXLEN) + return; + if (end > CDCE_NCM_TX_MAXLEN) + end = CDCE_NCM_TX_MAXLEN; + + usbd_frame_zero(pc, start, end - start); +} + static uint8_t cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) { @@ -993,7 +1051,8 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) uint32_t rem; uint32_t offset; uint32_t last_offset; - uint32_t n; + uint16_t n; + uint8_t retval; usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index); @@ -1003,11 +1062,17 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) /* Store last valid offset before alignment */ last_offset = offset; - /* Align offset correctly */ - offset = sc->sc_ncm.tx_remainder - - ((0UL - offset) & (0UL - sc->sc_ncm.tx_modulus)); + /* Align offset */ + offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, + offset, sc->sc_ncm.tx_modulus); - for (n = 0; n != CDCE_NCM_SUBFRAMES_MAX; n++) { + /* Zero pad */ + cdce_ncm_tx_zero(pc, last_offset, offset); + + /* buffer full */ + retval = 2; + + for (n = 0; n != sc->sc_ncm.tx_nframe; n++) { /* check if end of transmit buffer is reached */ @@ -1020,8 +1085,11 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) IFQ_DRV_DEQUEUE(&(ifp->if_snd), m); - if (m == NULL) + if (m == NULL) { + /* buffer not full */ + retval = 1; break; + } if (m->m_pkthdr.len > rem) { if (n == 0) { @@ -1047,9 +1115,12 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) /* Store last valid offset before alignment */ last_offset = offset; - /* Align offset correctly */ - offset = sc->sc_ncm.tx_remainder - - ((0UL - offset) & (0UL - sc->sc_ncm.tx_modulus)); + /* Align offset */ + offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, + offset, sc->sc_ncm.tx_modulus); + + /* Zero pad */ + cdce_ncm_tx_zero(pc, last_offset, offset); /* * If there's a BPF listener, bounce a copy @@ -1067,7 +1138,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) } if (n == 0) - return (1); + return (0); rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4); @@ -1079,8 +1150,22 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) USETW(sc->sc_ncm.dp[n].wFrameIndex, 0); } + offset = last_offset; + + /* Align offset */ + offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN); + + /* Optimise, save bandwidth and force short termination */ + if (offset >= sc->sc_ncm.tx_max) + offset = sc->sc_ncm.tx_max; + else + offset ++; + + /* Zero pad */ + cdce_ncm_tx_zero(pc, last_offset, offset); + /* set frame length */ - usbd_xfer_set_frame_len(xfer, index, last_offset); + usbd_xfer_set_frame_len(xfer, index, offset); /* Fill out 16-bit header */ sc->sc_ncm.hdr.dwSignature[0] = 'N'; @@ -1088,7 +1173,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) sc->sc_ncm.hdr.dwSignature[2] = 'M'; sc->sc_ncm.hdr.dwSignature[3] = 'H'; USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr)); - USETW(sc->sc_ncm.hdr.wBlockLength, last_offset); + USETW(sc->sc_ncm.hdr.wBlockLength, offset); USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq); USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr)); @@ -1106,7 +1191,7 @@ cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) sizeof(sc->sc_ncm.dpt)); usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt), &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp)); - return (0); + return (retval); } static void @@ -1115,6 +1200,7 @@ cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) struct cdce_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); uint16_t x; + uint8_t temp; int actlen; int aframes; @@ -1128,11 +1214,19 @@ cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) case USB_ST_SETUP: for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) { - if (cdce_ncm_fill_tx_frames(xfer, x)) + temp = cdce_ncm_fill_tx_frames(xfer, x); + if (temp == 0) break; + if (temp == 1) { + x++; + break; + } } if (x != 0) { +#ifdef USB_DEBUG + usbd_xfer_set_interval(xfer, cdce_tx_interval); +#endif usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); } diff --git a/sys/dev/usb/net/if_cdcereg.h b/sys/dev/usb/net/if_cdcereg.h index 55931698b63..5594a2fd0bc 100644 --- a/sys/dev/usb/net/if_cdcereg.h +++ b/sys/dev/usb/net/if_cdcereg.h @@ -38,7 +38,8 @@ #define CDCE_FRAMES_MAX 8 /* units */ #define CDCE_IND_SIZE_MAX 32 /* bytes */ -#define CDCE_NCM_TX_MAXLEN 2048UL /* bytes */ +#define CDCE_NCM_TX_MINLEN 512 /* bytes, must be power of two */ +#define CDCE_NCM_TX_MAXLEN (1UL << 14) /* bytes */ #define CDCE_NCM_TX_FRAMES_MAX 8 /* units */ #define CDCE_NCM_RX_MAXLEN (1UL << 14) /* bytes */ @@ -46,6 +47,10 @@ #define CDCE_NCM_SUBFRAMES_MAX 32 /* units */ +#define CDCE_NCM_ALIGN(rem,off,mod) \ + ((uint32_t)(((uint32_t)(rem)) - \ + ((uint32_t)((-(uint32_t)(off)) & (-(uint32_t)(mod)))))) + #ifndef CDCE_HAVE_NCM #define CDCE_HAVE_NCM 1 #endif @@ -68,6 +73,7 @@ struct cdce_ncm { uint16_t tx_modulus; uint16_t tx_struct_align; uint16_t tx_seq; + uint16_t tx_nframe; }; struct cdce_softc { diff --git a/sys/dev/usb/net/if_cue.c b/sys/dev/usb/net/if_cue.c index e26b29f6fd2..46ccc08f848 100644 --- a/sys/dev/usb/net/if_cue.c +++ b/sys/dev/usb/net/if_cue.c @@ -173,6 +173,7 @@ DRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0); MODULE_DEPEND(cue, uether, 1, 1, 1); MODULE_DEPEND(cue, usb, 1, 1, 1); MODULE_DEPEND(cue, ether, 1, 1, 1); +MODULE_VERSION(cue, 1); static const struct usb_ether_methods cue_ue_methods = { .ue_attach_post = cue_attach_post, diff --git a/sys/dev/usb/net/if_ipheth.c b/sys/dev/usb/net/if_ipheth.c new file mode 100644 index 00000000000..7e437341cd6 --- /dev/null +++ b/sys/dev/usb/net/if_ipheth.c @@ -0,0 +1,528 @@ +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2009 Diego Giagio. 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. + */ + +/* + * Thanks to Diego Giagio for figuring out the programming details for + * the Apple iPhone Ethernet driver. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "usbdevs.h" + +#define USB_DEBUG_VAR ipheth_debug +#include +#include + +#include +#include + +static device_probe_t ipheth_probe; +static device_attach_t ipheth_attach; +static device_detach_t ipheth_detach; + +static usb_callback_t ipheth_bulk_write_callback; +static usb_callback_t ipheth_bulk_read_callback; + +static uether_fn_t ipheth_attach_post; +static uether_fn_t ipheth_tick; +static uether_fn_t ipheth_init; +static uether_fn_t ipheth_stop; +static uether_fn_t ipheth_start; +static uether_fn_t ipheth_setmulti; +static uether_fn_t ipheth_setpromisc; + +#ifdef USB_DEBUG +static int ipheth_debug = 0; + +SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet"); +SYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level"); +#endif + +static const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { + + [IPHETH_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_RX, + .frames = IPHETH_RX_FRAMES_MAX, + .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), + .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, + .callback = ipheth_bulk_read_callback, + .timeout = 0, /* no timeout */ + }, + + [IPHETH_BULK_TX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_TX, + .frames = IPHETH_TX_FRAMES_MAX, + .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), + .flags = {.force_short_xfer = 1,}, + .callback = ipheth_bulk_write_callback, + .timeout = IPHETH_TX_TIMEOUT, + }, +}; + +static device_method_t ipheth_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ipheth_probe), + DEVMETHOD(device_attach, ipheth_attach), + DEVMETHOD(device_detach, ipheth_detach), + + {0, 0} +}; + +static driver_t ipheth_driver = { + .name = "ipheth", + .methods = ipheth_methods, + .size = sizeof(struct ipheth_softc), +}; + +static devclass_t ipheth_devclass; + +DRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0); +MODULE_VERSION(ipheth, 1); +MODULE_DEPEND(ipheth, uether, 1, 1, 1); +MODULE_DEPEND(ipheth, usb, 1, 1, 1); +MODULE_DEPEND(ipheth, ether, 1, 1, 1); + +static const struct usb_ether_methods ipheth_ue_methods = { + .ue_attach_post = ipheth_attach_post, + .ue_start = ipheth_start, + .ue_init = ipheth_init, + .ue_tick = ipheth_tick, + .ue_stop = ipheth_stop, + .ue_setmulti = ipheth_setmulti, + .ue_setpromisc = ipheth_setpromisc, +}; + +#define IPHETH_ID(v,p,c,sc,pt) \ + USB_VENDOR(v), USB_PRODUCT(p), \ + USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \ + USB_IFACE_PROTOCOL(pt) + +static const struct usb_device_id ipheth_devs[] = { + {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO)}, + {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO)}, + {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO)}, + {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO)}, +}; + +static int +ipheth_get_mac_addr(struct ipheth_softc *sc) +{ + struct usb_device_request req; + int error; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = IPHETH_CMD_GET_MACADDR; + req.wValue[0] = 0; + req.wValue[1] = 0; + req.wIndex[0] = sc->sc_iface_no; + req.wIndex[1] = 0; + req.wLength[0] = ETHER_ADDR_LEN; + req.wLength[1] = 0; + + error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data); + + if (error) + return (error); + + memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN); + + return (0); +} + +static int +ipheth_probe(device_t dev) +{ + struct usb_attach_arg *uaa = device_get_ivars(dev); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa)); +} + +static int +ipheth_attach(device_t dev) +{ + struct ipheth_softc *sc = device_get_softc(dev); + struct usb_ether *ue = &sc->sc_ue; + struct usb_attach_arg *uaa = device_get_ivars(dev); + int error; + + sc->sc_iface_no = uaa->info.bIfaceIndex; + + device_set_usb_desc(dev); + + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + error = usbd_set_alt_interface_index(uaa->device, + uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM); + if (error) { + device_printf(dev, "Cannot set alternate setting\n"); + goto detach; + } + error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, + sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); + if (error) { + device_printf(dev, "Cannot setup USB transfers\n"); + goto detach; + } + ue->ue_sc = sc; + ue->ue_dev = dev; + ue->ue_udev = uaa->device; + ue->ue_mtx = &sc->sc_mtx; + ue->ue_methods = &ipheth_ue_methods; + + error = ipheth_get_mac_addr(sc); + if (error) { + device_printf(dev, "Cannot get MAC address\n"); + goto detach; + } + + error = uether_ifattach(ue); + if (error) { + device_printf(dev, "could not attach interface\n"); + goto detach; + } + return (0); /* success */ + +detach: + ipheth_detach(dev); + return (ENXIO); /* failure */ +} + +static int +ipheth_detach(device_t dev) +{ + struct ipheth_softc *sc = device_get_softc(dev); + struct usb_ether *ue = &sc->sc_ue; + + /* stop all USB transfers first */ + usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER); + + uether_ifdetach(ue); + + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static void +ipheth_start(struct usb_ether *ue) +{ + struct ipheth_softc *sc = uether_getsc(ue); + + /* + * Start the USB transfers, if not already started: + */ + usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]); + usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]); +} + +static void +ipheth_stop(struct usb_ether *ue) +{ + struct ipheth_softc *sc = uether_getsc(ue); + + /* + * Stop the USB transfers, if not already stopped: + */ + usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]); + usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]); +} + +static void +ipheth_tick(struct usb_ether *ue) +{ + struct ipheth_softc *sc = uether_getsc(ue); + struct usb_device_request req; + int error; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = IPHETH_CMD_CARRIER_CHECK; + req.wValue[0] = 0; + req.wValue[1] = 0; + req.wIndex[0] = sc->sc_iface_no; + req.wIndex[1] = 0; + req.wLength[0] = IPHETH_CTRL_BUF_SIZE; + req.wLength[1] = 0; + + error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT); + + if (error) + return; + + sc->sc_carrier_on = + (sc->sc_data[0] == IPHETH_CARRIER_ON); +} + +static void +ipheth_attach_post(struct usb_ether *ue) +{ + +} + +static void +ipheth_init(struct usb_ether *ue) +{ + struct ipheth_softc *sc = uether_getsc(ue); + struct ifnet *ifp = uether_getifp(ue); + + IPHETH_LOCK_ASSERT(sc, MA_OWNED); + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + + /* stall data write direction, which depends on USB mode */ + usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]); + + /* start data transfers */ + ipheth_start(ue); +} + +static void +ipheth_setmulti(struct usb_ether *ue) +{ + +} + +static void +ipheth_setpromisc(struct usb_ether *ue) +{ + +} + +static void +ipheth_free_queue(struct mbuf **ppm, uint8_t n) +{ + uint8_t x; + + for (x = 0; x != n; x++) { + if (ppm[x] != NULL) { + m_freem(ppm[x]); + ppm[x] = NULL; + } + } +} + +static void +ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct ifnet *ifp = uether_getifp(&sc->sc_ue); + struct usb_page_cache *pc; + struct mbuf *m; + uint8_t x; + int actlen; + int aframes; + + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); + + DPRINTFN(1, "\n"); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", + actlen, aframes); + + ifp->if_opackets++; + + /* free all previous TX buffers */ + ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); + + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { + + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + + if (m == NULL) + break; + + usbd_xfer_set_frame_offset(xfer, + x * IPHETH_BUF_SIZE, x); + + pc = usbd_xfer_get_frame(xfer, x); + + sc->sc_tx_buf[x] = m; + + if (m->m_pkthdr.len > IPHETH_BUF_SIZE) + m->m_pkthdr.len = IPHETH_BUF_SIZE; + + usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); + + usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); + + if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { + usbd_frame_zero(pc, m->m_pkthdr.len, + IPHETH_BUF_SIZE - m->m_pkthdr.len); + } + + /* + * If there's a BPF listener, bounce a copy of + * this frame to him: + */ + BPF_MTAP(ifp, m); + } + if (x != 0) { + usbd_xfer_set_frames(xfer, x); + + usbd_transfer_submit(xfer); + } + break; + + default: /* Error */ + DPRINTFN(11, "transfer error, %s\n", + usbd_errstr(error)); + + /* free all previous TX buffers */ + ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); + + /* count output errors */ + ifp->if_oerrors++; + + if (error != USB_ERR_CANCELLED) { + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static void +ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct ipheth_softc *sc = usbd_xfer_softc(xfer); + struct mbuf *m; + uint8_t x; + int actlen; + int aframes; + int len; + + usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + + DPRINTF("received %u bytes in %u frames\n", actlen, aframes); + + for (x = 0; x != aframes; x++) { + + m = sc->sc_rx_buf[x]; + sc->sc_rx_buf[x] = NULL; + len = usbd_xfer_frame_len(xfer, x); + + if (len < (sizeof(struct ether_header) + + IPHETH_RX_ADJ)) { + m_freem(m); + continue; + } + + m_adj(m, IPHETH_RX_ADJ); + + /* queue up mbuf */ + uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); + } + + /* FALLTHROUGH */ + case USB_ST_SETUP: + + for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { + if (sc->sc_rx_buf[x] == NULL) { + m = uether_newbuf(); + if (m == NULL) + goto tr_stall; + + /* cancel alignment for ethernet */ + m_adj(m, ETHER_ALIGN); + + sc->sc_rx_buf[x] = m; + } else { + m = sc->sc_rx_buf[x]; + } + + usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); + } + /* set number of frames and start hardware */ + usbd_xfer_set_frames(xfer, x); + usbd_transfer_submit(xfer); + /* flush any received frames */ + uether_rxflush(&sc->sc_ue); + break; + + default: /* Error */ + DPRINTF("error = %s\n", usbd_errstr(error)); + + if (error != USB_ERR_CANCELLED) { + tr_stall: + /* try to clear stall first */ + usbd_xfer_set_stall(xfer); + usbd_xfer_set_frames(xfer, 0); + usbd_transfer_submit(xfer); + break; + } + /* need to free the RX-mbufs when we are cancelled */ + ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX); + break; + } +} diff --git a/sys/dev/usb/net/if_iphethvar.h b/sys/dev/usb/net/if_iphethvar.h new file mode 100644 index 00000000000..65b0c940c60 --- /dev/null +++ b/sys/dev/usb/net/if_iphethvar.h @@ -0,0 +1,84 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2009 Diego Giagio. 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. + */ + +/* + * Thanks to Diego Giagio for figuring out the programming details for + * the Apple iPhone Ethernet driver. + */ + +#ifndef _IF_IPHETHVAR_H_ +#define _IF_IPHETHVAR_H_ + +#define IPHETH_USBINTF_CLASS 255 +#define IPHETH_USBINTF_SUBCLASS 253 +#define IPHETH_USBINTF_PROTO 1 + +#define IPHETH_BUF_SIZE 1516 +#define IPHETH_TX_TIMEOUT 5000 /* ms */ + +#define IPHETH_RX_FRAMES_MAX 1 +#define IPHETH_TX_FRAMES_MAX 8 + +#define IPHETH_RX_ADJ 2 + +#define IPHETH_CFG_INDEX 0 +#define IPHETH_IF_INDEX 2 +#define IPHETH_ALT_INTFNUM 1 + +#define IPHETH_CTRL_ENDP 0x00 +#define IPHETH_CTRL_BUF_SIZE 0x40 +#define IPHETH_CTRL_TIMEOUT 5000 /* ms */ + +#define IPHETH_CMD_GET_MACADDR 0x00 +#define IPHETH_CMD_CARRIER_CHECK 0x45 + +#define IPHETH_CARRIER_ON 0x04 + +enum { + IPHETH_BULK_TX, + IPHETH_BULK_RX, + IPHETH_N_TRANSFER, +}; + +struct ipheth_softc { + struct usb_ether sc_ue; + struct mtx sc_mtx; + + struct usb_xfer *sc_xfer[IPHETH_N_TRANSFER]; + struct mbuf *sc_rx_buf[IPHETH_RX_FRAMES_MAX]; + struct mbuf *sc_tx_buf[IPHETH_TX_FRAMES_MAX]; + + uint8_t sc_data[IPHETH_CTRL_BUF_SIZE]; + uint8_t sc_iface_no; + uint8_t sc_carrier_on; +}; + +#define IPHETH_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define IPHETH_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define IPHETH_LOCK_ASSERT(_sc, t) mtx_assert(&(_sc)->sc_mtx, t) + +#endif /* _IF_IPHETHVAR_H_ */ diff --git a/sys/dev/usb/net/if_kue.c b/sys/dev/usb/net/if_kue.c index 4eee0945d9f..7c8bf8bb357 100644 --- a/sys/dev/usb/net/if_kue.c +++ b/sys/dev/usb/net/if_kue.c @@ -215,6 +215,7 @@ DRIVER_MODULE(kue, uhub, kue_driver, kue_devclass, NULL, 0); MODULE_DEPEND(kue, uether, 1, 1, 1); MODULE_DEPEND(kue, usb, 1, 1, 1); MODULE_DEPEND(kue, ether, 1, 1, 1); +MODULE_VERSION(kue, 1); static const struct usb_ether_methods kue_ue_methods = { .ue_attach_post = kue_attach_post, diff --git a/sys/dev/usb/net/if_rue.c b/sys/dev/usb/net/if_rue.c index 7741b8d0ecb..75343c8f86e 100644 --- a/sys/dev/usb/net/if_rue.c +++ b/sys/dev/usb/net/if_rue.c @@ -213,6 +213,7 @@ MODULE_DEPEND(rue, uether, 1, 1, 1); MODULE_DEPEND(rue, usb, 1, 1, 1); MODULE_DEPEND(rue, ether, 1, 1, 1); MODULE_DEPEND(rue, miibus, 1, 1, 1); +MODULE_VERSION(rue, 1); static const struct usb_ether_methods rue_ue_methods = { .ue_attach_post = rue_attach_post, diff --git a/sys/dev/usb/net/if_udav.c b/sys/dev/usb/net/if_udav.c index f56e9b03829..bc687b612b3 100644 --- a/sys/dev/usb/net/if_udav.c +++ b/sys/dev/usb/net/if_udav.c @@ -172,6 +172,7 @@ MODULE_DEPEND(udav, uether, 1, 1, 1); MODULE_DEPEND(udav, usb, 1, 1, 1); MODULE_DEPEND(udav, ether, 1, 1, 1); MODULE_DEPEND(udav, miibus, 1, 1, 1); +MODULE_VERSION(udav, 1); static const struct usb_ether_methods udav_ue_methods = { .ue_attach_post = udav_attach_post, diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c index e0a9bb36ae2..857145819d2 100644 --- a/sys/dev/usb/net/uhso.c +++ b/sys/dev/usb/net/uhso.c @@ -62,13 +62,11 @@ __FBSDID("$FreeBSD$"); #define USB_DEBUG_VAR uhso_debug #include #include -#include #include -#include -#include -#include #include +#include + struct uhso_tty { struct uhso_softc *ht_sc; struct usb_xfer *ht_xfer[3]; @@ -513,7 +511,7 @@ uhso_probe(device_t self) return (ENXIO); if (uaa->info.bConfigIndex != 0) return (ENXIO); - if (uaa->device->ddesc.bDeviceClass != 0xff) + if (uaa->info.bDeviceClass != 0xff) return (ENXIO); error = usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa); @@ -603,8 +601,9 @@ uhso_attach(device_t self) /* Announce device */ device_printf(self, "<%s port> at <%s %s> on %s\n", uhso_port_type[UHSO_IFACE_PORT_TYPE(sc->sc_type)], - uaa->device->manufacturer, uaa->device->product, - device_get_nameunit(uaa->device->bus->bdev)); + usb_get_manufacturer(uaa->device), + usb_get_product(uaa->device), + device_get_nameunit(device_get_parent(self))); if (sc->sc_ttys > 0) { SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "ports", @@ -1561,7 +1560,7 @@ uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface, int type) ifp->if_init = uhso_if_init; ifp->if_start = uhso_if_start; ifp->if_output = uhso_if_output; - ifp->if_flags = 0; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_NOARP; ifp->if_softc = sc; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; diff --git a/sys/dev/usb/net/usb_ethernet.c b/sys/dev/usb/net/usb_ethernet.c index bd75cef9657..de702f6a1ed 100644 --- a/sys/dev/usb/net/usb_ethernet.c +++ b/sys/dev/usb/net/usb_ethernet.c @@ -222,11 +222,12 @@ ue_attach_post_task(struct usb_proc_msg *_task) if (ue->ue_methods->ue_mii_upd != NULL && ue->ue_methods->ue_mii_sts != NULL) { mtx_lock(&Giant); /* device_xxx() depends on this */ - error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, - ue_ifmedia_upd, ue->ue_methods->ue_mii_sts); + error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp, + ue_ifmedia_upd, ue->ue_methods->ue_mii_sts, + BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); mtx_unlock(&Giant); if (error) { - device_printf(ue->ue_dev, "MII without any PHY\n"); + device_printf(ue->ue_dev, "attaching PHYs failed\n"); goto error; } } @@ -558,7 +559,7 @@ uether_rxbuf(struct usb_ether *ue, struct usb_page_cache *pc, m = uether_newbuf(); if (m == NULL) { - ifp->if_ierrors++; + ifp->if_iqdrops++; return (ENOMEM); } diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index d6d54845f99..e375adcbb94 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -159,10 +159,8 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(ALCOR, AU6390, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ALCOR, UMCR_9361, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN), - USB_QUIRK(ALCOR, TRANSCEND, 0x0142, 0x0142, UQ_MSC_FORCE_WIRE_BBB, - UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(ALCOR, TRANSCEND, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, - UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_GETMAXLUN), + USB_QUIRK(ALCOR, TRANSCEND, 0x0000, 0xffff, UQ_MSC_NO_GETMAXLUN, + UQ_MSC_NO_SYNC_CACHE, UQ_MSC_NO_TEST_UNIT_READY), USB_QUIRK(APACER, HT202, 0x0000, 0xffff, UQ_MSC_NO_TEST_UNIT_READY, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ASAHIOPTICAL, OPTIO230, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, @@ -195,7 +193,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(FREECOM, DVD, 0x0000, 0xffff, UQ_MSC_FORCE_PROTO_SCSI), USB_QUIRK(FREECOM, HDD, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(FUJIPHOTO, MASS0100, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_CBI_I, - UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA), + UQ_MSC_FORCE_PROTO_ATAPI, UQ_MSC_NO_RS_CLEAR_UA, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(GENESYS, GL641USB2IDE, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_FORCE_SHORT_INQ, UQ_MSC_NO_START_STOP, UQ_MSC_IGNORE_RESIDUE, UQ_MSC_NO_SYNC_CACHE), @@ -456,8 +454,9 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(ACTIONS, MP4, 0x0000, 0xffff, UQ_MSC_FORCE_WIRE_BBB, UQ_MSC_FORCE_PROTO_SCSI, UQ_MSC_NO_SYNC_CACHE), USB_QUIRK(ASUS, GMSC, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(UNKNOWN4, USBMEMSTICK, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), - USB_QUIRK(UNKNOWN5, USB2IDEBRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), + USB_QUIRK(CHIPSBANK, USBMEMSTICK, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), + USB_QUIRK(CHIPSBANK, USBMEMSTICK1, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), + USB_QUIRK(NEWLINK, USB2IDEBRIDGE, 0x0000, 0xffff, UQ_MSC_NO_SYNC_CACHE), }; #undef USB_QUIRK_VP #undef USB_QUIRK diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 1b1a13e8a8d..4bc42aebf8b 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -93,6 +93,7 @@ SYSCTL_INT(_hw_usb_u3g, OID_AUTO, debug, CTLFLAG_RW, #define U3GINIT_WAIT 7 /* Device reappears after a delay */ #define U3GINIT_SAEL_M460 8 /* Requires vendor init */ #define U3GINIT_HUAWEISCSI 9 /* Requires Huawei SCSI init command */ +#define U3GINIT_TCT 10 /* Requires TCT Mobile init command */ enum { U3G_BULK_WR, @@ -178,6 +179,7 @@ static driver_t u3g_driver = { DRIVER_MODULE(u3g, uhub, u3g_driver, u3g_devclass, u3g_driver_loaded, 0); MODULE_DEPEND(u3g, ucom, 1, 1, 1); MODULE_DEPEND(u3g, usb, 1, 1, 1); +MODULE_VERSION(u3g, 1); static const struct usb_device_id u3g_devs[] = { #define U3G_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } @@ -283,10 +285,12 @@ static const struct usb_device_id u3g_devs[] = { U3G_DEV(HUAWEI, E220BIS, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, MOBILE, U3GINIT_HUAWEI), U3G_DEV(HUAWEI, E1752, U3GINIT_HUAWEISCSI), + U3G_DEV(HUAWEI, K3765, U3GINIT_HUAWEI), U3G_DEV(KYOCERA2, CDMA_MSM_K, 0), U3G_DEV(KYOCERA2, KPC680, 0), U3G_DEV(LONGCHEER, WM66, U3GINIT_HUAWEI), U3G_DEV(MERLIN, V620, 0), + U3G_DEV(NEOTEL, PRIME, 0), U3G_DEV(NOVATEL, E725, 0), U3G_DEV(NOVATEL, ES620, 0), U3G_DEV(NOVATEL, ES620_2, 0), @@ -407,6 +411,7 @@ static const struct usb_device_id u3g_devs[] = { U3G_DEV(QUALCOMMINC, E0078, 0), U3G_DEV(QUALCOMMINC, E0082, 0), U3G_DEV(QUALCOMMINC, E0086, 0), + U3G_DEV(QUALCOMMINC, E2000, U3GINIT_SCSIEJECT), U3G_DEV(QUALCOMMINC, E2002, 0), U3G_DEV(QUALCOMMINC, E2003, 0), U3G_DEV(QUALCOMMINC, MF626, 0), @@ -491,6 +496,7 @@ static const struct usb_device_id u3g_devs[] = { U3G_DEV(STELERA, E1011, 0), U3G_DEV(STELERA, E1012, 0), U3G_DEV(TCTMOBILE, X060S, 0), + U3G_DEV(TCTMOBILE, X080S, U3GINIT_TCT), U3G_DEV(TELIT, UC864E, 0), U3G_DEV(TELIT, UC864G, 0), U3G_DEV(TLAYTECH, TEU800, 0), @@ -668,6 +674,9 @@ u3g_test_autoinst(void *arg, struct usb_device *udev, case U3GINIT_CMOTECH: error = usb_msc_eject(udev, 0, MSC_EJECT_CMOTECH); break; + case U3GINIT_TCT: + error = usb_msc_eject(udev, 0, MSC_EJECT_TCT); + break; case U3GINIT_SIERRA: error = u3g_sierra_init(udev); break; diff --git a/sys/dev/usb/serial/uark.c b/sys/dev/usb/serial/uark.c index 7dfb0f83f6e..10476c2133e 100644 --- a/sys/dev/usb/serial/uark.c +++ b/sys/dev/usb/serial/uark.c @@ -169,6 +169,7 @@ static driver_t uark_driver = { DRIVER_MODULE(uark, uhub, uark_driver, uark_devclass, NULL, 0); MODULE_DEPEND(uark, ucom, 1, 1, 1); MODULE_DEPEND(uark, usb, 1, 1, 1); +MODULE_VERSION(uark, 1); static const struct usb_device_id uark_devs[] = { {USB_VPI(USB_VENDOR_ARKMICRO, USB_PRODUCT_ARKMICRO_ARK3116, 0)}, diff --git a/sys/dev/usb/serial/ubsa.c b/sys/dev/usb/serial/ubsa.c index 58175094922..83ae1c97e1c 100644 --- a/sys/dev/usb/serial/ubsa.c +++ b/sys/dev/usb/serial/ubsa.c @@ -277,6 +277,7 @@ static driver_t ubsa_driver = { DRIVER_MODULE(ubsa, uhub, ubsa_driver, ubsa_devclass, NULL, 0); MODULE_DEPEND(ubsa, ucom, 1, 1, 1); MODULE_DEPEND(ubsa, usb, 1, 1, 1); +MODULE_VERSION(ubsa, 1); static int ubsa_probe(device_t dev) diff --git a/sys/dev/usb/serial/ubser.c b/sys/dev/usb/serial/ubser.c index 3f2dc2d30c7..7119177e990 100644 --- a/sys/dev/usb/serial/ubser.c +++ b/sys/dev/usb/serial/ubser.c @@ -104,7 +104,6 @@ __FBSDID("$FreeBSD$"); #define USB_DEBUG_VAR ubser_debug #include #include -#include #include @@ -215,6 +214,7 @@ static driver_t ubser_driver = { DRIVER_MODULE(ubser, uhub, ubser_driver, ubser_devclass, NULL, 0); MODULE_DEPEND(ubser, ucom, 1, 1, 1); MODULE_DEPEND(ubser, usb, 1, 1, 1); +MODULE_VERSION(ubser, 1); static int ubser_probe(device_t dev) @@ -225,7 +225,7 @@ ubser_probe(device_t dev) return (ENXIO); } /* check if this is a BWCT vendor specific ubser interface */ - if ((strcmp(uaa->device->manufacturer, "BWCT") == 0) && + if ((strcmp(usb_get_manufacturer(uaa->device), "BWCT") == 0) && (uaa->info.bInterfaceClass == 0xff) && (uaa->info.bInterfaceSubClass == 0x00)) return (0); diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c index 92f3a922345..3bcb49f8428 100644 --- a/sys/dev/usb/serial/uchcom.c +++ b/sys/dev/usb/serial/uchcom.c @@ -855,3 +855,4 @@ static devclass_t uchcom_devclass; DRIVER_MODULE(uchcom, uhub, uchcom_driver, uchcom_devclass, NULL, 0); MODULE_DEPEND(uchcom, ucom, 1, 1, 1); MODULE_DEPEND(uchcom, usb, 1, 1, 1); +MODULE_VERSION(uchcom, 1); diff --git a/sys/dev/usb/serial/ucycom.c b/sys/dev/usb/serial/ucycom.c index 1cce28eb580..decd03ceabd 100644 --- a/sys/dev/usb/serial/ucycom.c +++ b/sys/dev/usb/serial/ucycom.c @@ -176,6 +176,7 @@ static driver_t ucycom_driver = { DRIVER_MODULE(ucycom, uhub, ucycom_driver, ucycom_devclass, NULL, 0); MODULE_DEPEND(ucycom, ucom, 1, 1, 1); MODULE_DEPEND(ucycom, usb, 1, 1, 1); +MODULE_VERSION(ucycom, 1); /* * Supported devices diff --git a/sys/dev/usb/serial/ufoma.c b/sys/dev/usb/serial/ufoma.c index b1a73494945..e7d5a9d5a74 100644 --- a/sys/dev/usb/serial/ufoma.c +++ b/sys/dev/usb/serial/ufoma.c @@ -326,6 +326,7 @@ static driver_t ufoma_driver = { DRIVER_MODULE(ufoma, uhub, ufoma_driver, ufoma_devclass, NULL, 0); MODULE_DEPEND(ufoma, ucom, 1, 1, 1); MODULE_DEPEND(ufoma, usb, 1, 1, 1); +MODULE_VERSION(ufoma, 1); static int ufoma_probe(device_t dev) diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c index 9b84bcecec8..64ddc005959 100644 --- a/sys/dev/usb/serial/uftdi.c +++ b/sys/dev/usb/serial/uftdi.c @@ -205,6 +205,7 @@ static driver_t uftdi_driver = { DRIVER_MODULE(uftdi, uhub, uftdi_driver, uftdi_devclass, NULL, 0); MODULE_DEPEND(uftdi, ucom, 1, 1, 1); MODULE_DEPEND(uftdi, usb, 1, 1, 1); +MODULE_VERSION(uftdi, 1); static struct usb_device_id uftdi_devs[] = { #define UFTDI_DEV(v,p,t) \ @@ -225,6 +226,7 @@ static struct usb_device_id uftdi_devs[] = { UFTDI_DEV(FTDI, CFA_633, 8U232AM), UFTDI_DEV(FTDI, CFA_634, 8U232AM), UFTDI_DEV(FTDI, CFA_635, 8U232AM), + UFTDI_DEV(FTDI, USB_UIRT, 8U232AM), UFTDI_DEV(FTDI, USBSERIAL, 8U232AM), UFTDI_DEV(FTDI, KBS, 8U232AM), UFTDI_DEV(FTDI, MX2_3, 8U232AM), @@ -246,6 +248,7 @@ static struct usb_device_id uftdi_devs[] = { UFTDI_DEV(INTREPIDCS, VALUECAN, 8U232AM), UFTDI_DEV(INTREPIDCS, NEOVI, 8U232AM), UFTDI_DEV(BBELECTRONICS, USOTL4, 8U232AM), + UFTDI_DEV(MATRIXORBITAL, MOUA, 8U232AM), UFTDI_DEV(MARVELL, SHEEVAPLUG, 8U232AM), UFTDI_DEV(MELCO, PCOPRS1, 8U232AM), UFTDI_DEV(RATOC, REXUSB60F, 8U232AM), diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c index e80660744a3..dd699863a5b 100644 --- a/sys/dev/usb/serial/ugensa.c +++ b/sys/dev/usb/serial/ugensa.c @@ -153,6 +153,7 @@ static driver_t ugensa_driver = { DRIVER_MODULE(ugensa, uhub, ugensa_driver, ugensa_devclass, NULL, 0); MODULE_DEPEND(ugensa, ucom, 1, 1, 1); MODULE_DEPEND(ugensa, usb, 1, 1, 1); +MODULE_VERSION(ugensa, 1); static const struct usb_device_id ugensa_devs[] = { {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)}, diff --git a/sys/dev/usb/serial/uipaq.c b/sys/dev/usb/serial/uipaq.c index 687130910f8..3bc915f985f 100644 --- a/sys/dev/usb/serial/uipaq.c +++ b/sys/dev/usb/serial/uipaq.c @@ -1085,6 +1085,7 @@ static driver_t uipaq_driver = { DRIVER_MODULE(uipaq, uhub, uipaq_driver, uipaq_devclass, NULL, 0); MODULE_DEPEND(uipaq, ucom, 1, 1, 1); MODULE_DEPEND(uipaq, usb, 1, 1, 1); +MODULE_VERSION(uipaq, 1); static int uipaq_probe(device_t dev) diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c index 58dc367237b..a75eb16b13c 100644 --- a/sys/dev/usb/serial/ulpt.c +++ b/sys/dev/usb/serial/ulpt.c @@ -745,3 +745,4 @@ static driver_t ulpt_driver = { DRIVER_MODULE(ulpt, uhub, ulpt_driver, ulpt_devclass, NULL, 0); MODULE_DEPEND(ulpt, usb, 1, 1, 1); MODULE_DEPEND(ulpt, ucom, 1, 1, 1); +MODULE_VERSION(ulpt, 1); diff --git a/sys/dev/usb/serial/umct.c b/sys/dev/usb/serial/umct.c index 524f8c4f4c0..d05a9f90154 100644 --- a/sys/dev/usb/serial/umct.c +++ b/sys/dev/usb/serial/umct.c @@ -219,6 +219,7 @@ static driver_t umct_driver = { DRIVER_MODULE(umct, uhub, umct_driver, umct_devclass, NULL, 0); MODULE_DEPEND(umct, ucom, 1, 1, 1); MODULE_DEPEND(umct, usb, 1, 1, 1); +MODULE_VERSION(umct, 1); static int umct_probe(device_t dev) diff --git a/sys/dev/usb/serial/umoscom.c b/sys/dev/usb/serial/umoscom.c index 3a36a44f71c..b79290b6879 100644 --- a/sys/dev/usb/serial/umoscom.c +++ b/sys/dev/usb/serial/umoscom.c @@ -279,6 +279,7 @@ static driver_t umoscom_driver = { DRIVER_MODULE(umoscom, uhub, umoscom_driver, umoscom_devclass, NULL, 0); MODULE_DEPEND(umoscom, ucom, 1, 1, 1); MODULE_DEPEND(umoscom, usb, 1, 1, 1); +MODULE_VERSION(umoscom, 1); static const struct usb_device_id umoscom_devs[] = { {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)} diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c index 6573d8e0c2e..5404bd87a86 100644 --- a/sys/dev/usb/serial/usb_serial.c +++ b/sys/dev/usb/serial/usb_serial.c @@ -942,6 +942,7 @@ ucom_cfg_status_change(struct usb_proc_msg *_task) uint8_t new_msr; uint8_t new_lsr; uint8_t onoff; + uint8_t lsr_delta; tp = sc->sc_tty; @@ -965,6 +966,7 @@ ucom_cfg_status_change(struct usb_proc_msg *_task) return; } onoff = ((sc->sc_msr ^ new_msr) & SER_DCD); + lsr_delta = (sc->sc_lsr ^ new_lsr); sc->sc_msr = new_msr; sc->sc_lsr = new_lsr; @@ -977,6 +979,30 @@ ucom_cfg_status_change(struct usb_proc_msg *_task) ttydisc_modem(tp, onoff); } + + if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) { + + DPRINTF("BREAK detected\n"); + + ttydisc_rint(tp, 0, TRE_BREAK); + ttydisc_rint_done(tp); + } + + if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) { + + DPRINTF("Frame error detected\n"); + + ttydisc_rint(tp, 0, TRE_FRAMING); + ttydisc_rint_done(tp); + } + + if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) { + + DPRINTF("Parity error detected\n"); + + ttydisc_rint(tp, 0, TRE_PARITY); + ttydisc_rint_done(tp); + } } void diff --git a/sys/dev/usb/serial/uvisor.c b/sys/dev/usb/serial/uvisor.c index 77ff31f5bd2..96a33894080 100644 --- a/sys/dev/usb/serial/uvisor.c +++ b/sys/dev/usb/serial/uvisor.c @@ -252,6 +252,7 @@ static driver_t uvisor_driver = { DRIVER_MODULE(uvisor, uhub, uvisor_driver, uvisor_devclass, NULL, 0); MODULE_DEPEND(uvisor, ucom, 1, 1, 1); MODULE_DEPEND(uvisor, usb, 1, 1, 1); +MODULE_VERSION(uvisor, 1); static const struct usb_device_id uvisor_devs[] = { #define UVISOR_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c index a66357b5db5..c270dfa5942 100644 --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -124,7 +124,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "usbdevs.h" #include @@ -231,6 +231,7 @@ TUNABLE_INT("hw.usb.umass.debug", &umass_debug); /* Approximate maximum transfer speeds (assumes 33% overhead). */ #define UMASS_FULL_TRANSFER_SPEED 1000 #define UMASS_HIGH_TRANSFER_SPEED 40000 +#define UMASS_SUPER_TRANSFER_SPEED 400000 #define UMASS_FLOPPY_TRANSFER_SPEED 20 #define UMASS_TIMEOUT 5000 /* ms */ @@ -715,6 +716,7 @@ static driver_t umass_driver = { DRIVER_MODULE(umass, uhub, umass_driver, umass_devclass, NULL, 0); MODULE_DEPEND(umass, usb, 1, 1, 1); MODULE_DEPEND(umass, cam, 1, 1, 1); +MODULE_VERSION(umass, 1); /* * USB device probe/attach/detach @@ -2303,23 +2305,24 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (umass_std_transform(sc, ccb, cmd, ccb->csio.cdb_len)) { if (sc->sc_transfer.cmd_data[0] == INQUIRY) { + const char *pserial; + + pserial = usb_get_serial(sc->sc_udev); /* * Umass devices don't generally report their serial numbers * in the usual SCSI way. Emulate it here. */ if ((sc->sc_transfer.cmd_data[1] & SI_EVPD) && - sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER && - sc->sc_udev != NULL && - sc->sc_udev->serial != NULL && - sc->sc_udev->serial[0] != '\0') { + (sc->sc_transfer.cmd_data[2] == SVPD_UNIT_SERIAL_NUMBER) && + (pserial[0] != '\0')) { struct scsi_vpd_unit_serial_number *vpd_serial; vpd_serial = (struct scsi_vpd_unit_serial_number *)ccb->csio.data_ptr; - vpd_serial->length = strlen(sc->sc_udev->serial); + vpd_serial->length = strlen(pserial); if (vpd_serial->length > sizeof(vpd_serial->serial_num)) vpd_serial->length = sizeof(vpd_serial->serial_num); - memcpy(vpd_serial->serial_num, sc->sc_udev->serial, vpd_serial->length); + memcpy(vpd_serial->serial_num, pserial, vpd_serial->length); ccb->csio.scsi_status = SCSI_STATUS_OK; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); @@ -2410,13 +2413,22 @@ umass_cam_action(struct cam_sim *sim, union ccb *ccb) if (sc->sc_quirks & FLOPPY_SPEED) { cpi->base_transfer_speed = UMASS_FLOPPY_TRANSFER_SPEED; - } else if (usbd_get_speed(sc->sc_udev) == - USB_SPEED_HIGH) { - cpi->base_transfer_speed = - UMASS_HIGH_TRANSFER_SPEED; } else { - cpi->base_transfer_speed = - UMASS_FULL_TRANSFER_SPEED; + switch (usbd_get_speed(sc->sc_udev)) { + case USB_SPEED_SUPER: + cpi->base_transfer_speed = + UMASS_SUPER_TRANSFER_SPEED; + cpi->maxio = MAXPHYS; + break; + case USB_SPEED_HIGH: + cpi->base_transfer_speed = + UMASS_HIGH_TRANSFER_SPEED; + break; + default: + cpi->base_transfer_speed = + UMASS_FULL_TRANSFER_SPEED; + break; + } } cpi->max_lun = sc->sc_maxlun; } @@ -2552,9 +2564,7 @@ umass_cam_cb(struct umass_softc *sc, union ccb *ccb, uint32_t residue, sc->sc_transfer.cmd_data[0] == INQUIRY && (sc->sc_transfer.cmd_data[1] & SI_EVPD) && sc->sc_transfer.cmd_data[2] == SVPD_SUPPORTED_PAGE_LIST && - sc->sc_udev != NULL && - sc->sc_udev->serial != NULL && - sc->sc_udev->serial[0] != '\0') { + (usb_get_serial(sc->sc_udev)[0] != '\0')) { struct ccb_scsiio *csio; struct scsi_vpd_supported_page_list *page_list; diff --git a/sys/dev/usb/storage/urio.c b/sys/dev/usb/storage/urio.c index 1aef8469f43..bf2d3147f7a 100644 --- a/sys/dev/usb/storage/urio.c +++ b/sys/dev/usb/storage/urio.c @@ -197,6 +197,7 @@ static driver_t urio_driver = { DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, NULL, 0); MODULE_DEPEND(urio, usb, 1, 1, 1); +MODULE_VERSION(urio, 1); static int urio_probe(device_t dev) diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 8ebaeecb720..89bc2c44a2a 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -208,6 +208,7 @@ typedef struct usb_device_request usb_device_request_t; #define UDESC_CS_INTERFACE 0x24 #define UDESC_CS_ENDPOINT 0x25 #define UDESC_HUB 0x29 +#define UDESC_SS_HUB 0x2A /* super speed */ #define UDESC_ENDPOINT_SS_COMP 0x30 /* super speed */ #define UR_SET_DESCRIPTOR 0x07 #define UR_GET_CONFIG 0x08 @@ -225,6 +226,7 @@ typedef struct usb_device_request usb_device_request_t; #define UR_GET_TT_STATE 0x0a #define UR_STOP_TT 0x0b #define UR_SET_HUB_DEPTH 0x0c +#define USB_SS_HUB_DEPTH_MAX 5 #define UR_GET_PORT_ERR_COUNT 0x0d /* Feature numbers */ @@ -332,7 +334,7 @@ struct usb_devcap_ss_descriptor { uByte bDevCapabilityType; uByte bmAttributes; uWord wSpeedsSupported; - uByte bFunctionaltySupport; + uByte bFunctionalitySupport; uByte bU1DevExitLat; uByte bU2DevExitLat; } __packed; @@ -343,7 +345,7 @@ struct usb_devcap_container_id_descriptor { uByte bDescriptorType; uByte bDevCapabilityType; uByte bReserved; - uByte ContainerID; + uByte bContainerID; } __packed; typedef struct usb_devcap_container_id_descriptor usb_devcap_container_id_descriptor_t; @@ -356,6 +358,7 @@ typedef struct usb_devcap_container_id_descriptor #define UDPROTO_FSHUB 0x00 #define UDPROTO_HSHUBSTT 0x01 #define UDPROTO_HSHUBMTT 0x02 +#define UDPROTO_SSHUB 0x03 #define UDCLASS_DIAGNOSTIC 0xdc #define UDCLASS_WIRELESS 0xe0 #define UDSUBCLASS_RF 0x01 @@ -533,7 +536,7 @@ typedef struct usb_endpoint_descriptor usb_endpoint_descriptor_t; struct usb_endpoint_ss_comp_descriptor { uByte bLength; uByte bDescriptorType; - uWord bMaxBurst; + uByte bMaxBurst; uByte bmAttributes; uWord wBytesPerInterval; } __packed; @@ -591,15 +594,15 @@ struct usb_hub_descriptor { typedef struct usb_hub_descriptor usb_hub_descriptor_t; struct usb_hub_ss_descriptor { - uByte bDescLength; + uByte bLength; uByte bDescriptorType; - uByte bNbrPorts; /* max 15 */ + uByte bNbrPorts; uWord wHubCharacteristics; uByte bPwrOn2PwrGood; /* delay in 2 ms units */ uByte bHubContrCurrent; uByte bHubHdrDecLat; uWord wHubDelay; - uByte DeviceRemovable[2]; /* max 15 ports */ + uByte DeviceRemovable[32]; /* max 255 ports */ } __packed; typedef struct usb_hub_ss_descriptor usb_hub_ss_descriptor_t; @@ -668,9 +671,25 @@ struct usb_port_status { #define UPS_SUSPEND 0x0004 #define UPS_OVERCURRENT_INDICATOR 0x0008 #define UPS_RESET 0x0010 +/* The link-state bits are valid for Super-Speed USB HUBs */ +#define UPS_PORT_LINK_STATE_GET(x) (((x) >> 5) & 0xF) +#define UPS_PORT_LINK_STATE_SET(x) (((x) & 0xF) << 5) +#define UPS_PORT_LS_U0 0x00 +#define UPS_PORT_LS_U1 0x01 +#define UPS_PORT_LS_U2 0x02 +#define UPS_PORT_LS_U3 0x03 +#define UPS_PORT_LS_SS_DIS 0x04 +#define UPS_PORT_LS_RX_DET 0x05 +#define UPS_PORT_LS_SS_INA 0x06 +#define UPS_PORT_LS_POLL 0x07 +#define UPS_PORT_LS_RECOVER 0x08 +#define UPS_PORT_LS_HOT_RST 0x09 +#define UPS_PORT_LS_COMP_MODE 0x0A +#define UPS_PORT_LS_LOOPBACK 0x0B #define UPS_PORT_POWER 0x0100 #define UPS_LOW_SPEED 0x0200 #define UPS_HIGH_SPEED 0x0400 +#define UPS_OTHER_SPEED 0x0600 /* currently FreeBSD specific */ #define UPS_PORT_TEST 0x0800 #define UPS_PORT_INDICATOR 0x1000 #define UPS_PORT_MODE_DEVICE 0x8000 /* currently FreeBSD specific */ @@ -680,6 +699,9 @@ struct usb_port_status { #define UPS_C_SUSPEND 0x0004 #define UPS_C_OVERCURRENT_INDICATOR 0x0008 #define UPS_C_PORT_RESET 0x0010 +#define UPS_C_BH_PORT_RESET 0x0020 +#define UPS_C_PORT_LINK_STATE 0x0040 +#define UPS_C_PORT_CONFIG_ERROR 0x0080 } __packed; typedef struct usb_port_status usb_port_status_t; diff --git a/sys/dev/usb/usb_busdma.c b/sys/dev/usb/usb_busdma.c index 45482e25da7..a2856946cc1 100644 --- a/sys/dev/usb/usb_busdma.c +++ b/sys/dev/usb/usb_busdma.c @@ -366,9 +366,9 @@ usb_dma_tag_create(struct usb_dma_tag *udt, /* filter */ NULL, /* filterarg */ NULL, /* maxsize */ size, - /* nsegments */ (align == 1) ? + /* nsegments */ (align == 1 && size > 1) ? (2 + (size / USB_PAGE_SIZE)) : 1, - /* maxsegsz */ (align == 1) ? + /* maxsegsz */ (align == 1 && size > USB_PAGE_SIZE) ? USB_PAGE_SIZE : size, /* flags */ BUS_DMA_KEEP_PG_OFFSET, /* lockfn */ &usb_dma_lock_cb, diff --git a/sys/dev/usb/usb_cdc.h b/sys/dev/usb/usb_cdc.h index c5a13f66509..b8f59faeca6 100644 --- a/sys/dev/usb/usb_cdc.h +++ b/sys/dev/usb/usb_cdc.h @@ -241,6 +241,7 @@ struct usb_ncm_func_descriptor { #define UCDC_NCM_CAP_ENCAP 0x04 #define UCDC_NCM_CAP_MAX_DATA 0x08 #define UCDC_NCM_CAP_CRCMODE 0x10 +#define UCDC_NCM_CAP_MAX_DGRAM 0x20 } __packed; /* Communications interface specific class request codes */ @@ -276,7 +277,7 @@ struct usb_ncm_parameters { uWord wNdpOutDivisor; uWord wNdpOutPayloadRemainder; uWord wNdpOutAlignment; - uWord wReserved26; + uWord wNtbOutMaxDatagrams; } __packed; /* Communications interface specific class notification codes */ diff --git a/sys/dev/usb/usb_compat_linux.c b/sys/dev/usb/usb_compat_linux.c index 89aaa8f7aac..7d44456b70f 100644 --- a/sys/dev/usb/usb_compat_linux.c +++ b/sys/dev/usb/usb_compat_linux.c @@ -122,6 +122,7 @@ static driver_t usb_linux_driver = { static devclass_t usb_linux_devclass; DRIVER_MODULE(usb_linux, uhub, usb_linux_driver, usb_linux_devclass, NULL, 0); +MODULE_VERSION(usb_linux, 1); /*------------------------------------------------------------------------* * usb_linux_lookup_id diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h index 6e355420e6e..6b15dab993d 100644 --- a/sys/dev/usb/usb_controller.h +++ b/sys/dev/usb/usb_controller.h @@ -62,7 +62,7 @@ struct usb_bus_methods { struct usb_endpoint_descriptor *, struct usb_endpoint *); void (*xfer_setup) (struct usb_setup_params *); void (*xfer_unsetup) (struct usb_xfer *); - void (*get_dma_delay) (struct usb_bus *, uint32_t *); + void (*get_dma_delay) (struct usb_device *, uint32_t *); void (*device_suspend) (struct usb_device *); void (*device_resume) (struct usb_device *); void (*set_hw_power) (struct usb_bus *); @@ -97,11 +97,40 @@ struct usb_bus_methods { void (*get_hw_ep_profile) (struct usb_device *udev, const struct usb_hw_ep_profile **ppf, uint8_t ep_addr); void (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep, uint8_t *did_stall); + + /* USB Device mode mandatory. USB Host mode optional. */ + void (*clear_stall) (struct usb_device *udev, struct usb_endpoint *ep); /* Optional transfer polling support */ void (*xfer_poll) (struct usb_bus *); + + /* Optional fixed power mode support */ + + void (*get_power_mode) (struct usb_device *udev, int8_t *pmode); + + /* Optional endpoint uninit */ + + void (*endpoint_uninit) (struct usb_device *, struct usb_endpoint *); + + /* Optional device init */ + + usb_error_t (*device_init) (struct usb_device *); + + /* Optional device uninit */ + + void (*device_uninit) (struct usb_device *); + + /* Optional for device and host mode */ + + void (*start_dma_delay) (struct usb_xfer *); + + void (*device_state_change) (struct usb_device *); + + /* Optional for host mode */ + + usb_error_t (*set_address) (struct usb_device *, struct mtx *, uint16_t); }; /* diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index 857d57a0085..5ccbae656b7 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -964,7 +964,6 @@ usb_dev_uninit(void *arg) if (usb_dev != NULL) { destroy_dev(usb_dev); usb_dev = NULL; - } mtx_destroy(&usb_ref_lock); sx_destroy(&usb_sym_lock); @@ -1058,21 +1057,45 @@ usb_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int fflag, struct thread* err = usb_ioctl_f_sub(f, cmd, addr, td); } KASSERT(f != NULL, ("fifo not found")); - if (err == ENOIOCTL) { - err = (f->methods->f_ioctl) (f, cmd, addr, fflags); - DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err); - if (err == ENOIOCTL) { - if (usb_usb_ref_device(cpd, &refs)) { - err = ENXIO; - goto done; - } - err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags); - DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err); + if (err != ENOIOCTL) + goto done; + + err = (f->methods->f_ioctl) (f, cmd, addr, fflags); + + DPRINTFN(2, "f_ioctl cmd 0x%lx = %d\n", cmd, err); + + if (err != ENOIOCTL) + goto done; + + if (usb_usb_ref_device(cpd, &refs)) { + err = ENXIO; + goto done; + } + + err = (f->methods->f_ioctl_post) (f, cmd, addr, fflags); + + DPRINTFN(2, "f_ioctl_post cmd 0x%lx = %d\n", cmd, err); + + if (err == ENOIOCTL) + err = ENOTTY; + + if (err) + goto done; + + /* Wait for re-enumeration, if any */ + + while (f->udev->re_enumerate_wait != 0) { + + usb_unref_device(cpd, &refs); + + usb_pause_mtx(NULL, hz / 128); + + if (usb_ref_device(cpd, &refs, 1 /* need uref */)) { + err = ENXIO; + goto done; } } - if (err == ENOIOCTL) { - err = ENOTTY; - } + done: usb_unref_device(cpd, &refs); return (err); @@ -1456,7 +1479,7 @@ usb_static_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct usb_read_dir *urd; void* data; } u; - int err = ENOTTY; + int err; u.data = data; switch (cmd) { @@ -1472,6 +1495,7 @@ usb_static_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, break; case USB_GET_TEMPLATE: *(int *)data = usb_template; + err = 0; break; case USB_SET_TEMPLATE: err = priv_check(curthread, PRIV_DRIVER); @@ -1479,6 +1503,9 @@ usb_static_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, break; usb_template = *(int *)data; break; + default: + err = ENOTTY; + break; } return (err); } diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 62f59b8632f..8887fc16c96 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -45,12 +45,16 @@ #include #include #include -#include #include #include #include #include + +#if USB_HAVE_UGEN +#include +#endif + #include "usbdevs.h" #define USB_DEBUG_VAR usb_debug @@ -79,7 +83,9 @@ /* function prototypes */ static void usb_init_endpoint(struct usb_device *, uint8_t, - struct usb_endpoint_descriptor *, struct usb_endpoint *); + struct usb_endpoint_descriptor *, + struct usb_endpoint_ss_comp_descriptor *, + struct usb_endpoint *); static void usb_unconfigure(struct usb_device *, uint8_t); static void usb_detach_device_sub(struct usb_device *, device_t *, uint8_t); @@ -90,10 +96,12 @@ static void usb_init_attach_arg(struct usb_device *, static void usb_suspend_resume_sub(struct usb_device *, device_t, uint8_t); static void usbd_clear_stall_proc(struct usb_proc_msg *_pm); -usb_error_t usb_config_parse(struct usb_device *, uint8_t, uint8_t); +static usb_error_t usb_config_parse(struct usb_device *, uint8_t, uint8_t); static void usbd_set_device_strings(struct usb_device *); -#if USB_HAVE_UGEN +#if USB_HAVE_DEVCTL static void usb_notify_addq(const char *type, struct usb_device *); +#endif +#if USB_HAVE_UGEN static void usb_fifo_free_wrap(struct usb_device *, uint8_t, uint8_t); static struct cdev *usb_make_dev(struct usb_device *, int, int); static void usb_cdev_create(struct usb_device *); @@ -136,6 +144,24 @@ usb_statestr(enum usb_dev_state state) return ((state < USB_STATE_MAX) ? statestr[state] : "UNKNOWN"); } +const char * +usb_get_manufacturer(struct usb_device *udev) +{ + return (udev->manufacturer ? udev->manufacturer : "Unknown"); +} + +const char * +usb_get_product(struct usb_device *udev) +{ + return (udev->product ? udev->product : ""); +} + +const char * +usb_get_serial(struct usb_device *udev) +{ + return (udev->serial ? udev->serial : ""); +} + /*------------------------------------------------------------------------* * usbd_get_ep_by_addr * @@ -342,7 +368,9 @@ usbd_interface_count(struct usb_device *udev, uint8_t *count) *------------------------------------------------------------------------*/ static void usb_init_endpoint(struct usb_device *udev, uint8_t iface_index, - struct usb_endpoint_descriptor *edesc, struct usb_endpoint *ep) + struct usb_endpoint_descriptor *edesc, + struct usb_endpoint_ss_comp_descriptor *ecomp, + struct usb_endpoint *ep) { struct usb_bus_methods *methods; @@ -352,6 +380,7 @@ usb_init_endpoint(struct usb_device *udev, uint8_t iface_index, /* initialise USB endpoint structure */ ep->edesc = edesc; + ep->ecomp = ecomp; ep->iface_index = iface_index; TAILQ_INIT(&ep->endpoint_q.head); ep->endpoint_q.command = &usbd_pipe_start; @@ -622,7 +651,7 @@ done: * 0: Success * Else: Failure *------------------------------------------------------------------------*/ -usb_error_t +static usb_error_t usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd) { struct usb_idesc_parse_state ips; @@ -745,8 +774,14 @@ usb_config_parse(struct usb_device *udev, uint8_t iface_index, uint8_t cmd) ep = udev->endpoints + temp; if (do_init) { + void *ecomp; + + ecomp = usb_ed_comp_foreach(udev->cdesc, (void *)ed); + if (ecomp != NULL) + DPRINTFN(5, "Found endpoint companion descriptor\n"); + usb_init_endpoint(udev, - ips.iface_index, ed, ep); + ips.iface_index, ed, ecomp, ep); } temp ++; @@ -886,8 +921,8 @@ done: /*------------------------------------------------------------------------* * usbd_set_endpoint_stall * - * This function is used to make a BULK or INTERRUPT endpoint - * send STALL tokens. + * This function is used to make a BULK or INTERRUPT endpoint send + * STALL tokens in USB device mode. * * Returns: * 0: Success @@ -1518,13 +1553,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, udev->bus = bus; udev->address = USB_START_ADDR; /* default value */ udev->plugtime = (usb_ticks_t)ticks; - usb_set_device_state(udev, USB_STATE_POWERED); /* * We need to force the power mode to "on" because there are plenty * of USB devices out there that do not work very well with * automatic suspend and resume! */ - udev->power_mode = USB_POWER_MODE_ON; + udev->power_mode = usbd_filter_power_mode(udev, USB_POWER_MODE_ON); udev->pwr_save.last_xfer_time = ticks; /* we are not ready yet */ udev->refcount = 1; @@ -1537,6 +1571,11 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, udev->ctrl_ep_desc.wMaxPacketSize[0] = USB_MAX_IPACKET; udev->ctrl_ep_desc.wMaxPacketSize[1] = 0; udev->ctrl_ep_desc.bInterval = 0; + + /* set up default endpoint companion descriptor */ + udev->ctrl_ep_comp_desc.bLength = sizeof(udev->ctrl_ep_comp_desc); + udev->ctrl_ep_comp_desc.bDescriptorType = UDESC_ENDPOINT_SS_COMP; + udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; udev->speed = speed; @@ -1561,6 +1600,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, /* init the default endpoint */ usb_init_endpoint(udev, 0, &udev->ctrl_ep_desc, + &udev->ctrl_ep_comp_desc, &udev->ctrl_ep); /* set device index */ @@ -1579,13 +1619,29 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, /* Create a link from /dev/ugenX.X to the default endpoint */ make_dev_alias(udev->ctrl_dev, "%s", udev->ugen_name); #endif + /* Initialise device */ + if (bus->methods->device_init != NULL) { + err = (bus->methods->device_init) (udev); + if (err != 0) { + DPRINTFN(0, "device init %d failed " + "(%s, ignored)\n", device_index, + usbd_errstr(err)); + goto done; + } + } + /* set powered device state after device init is complete */ + usb_set_device_state(udev, USB_STATE_POWERED); + if (udev->flags.usb_mode == USB_MODE_HOST) { err = usbd_req_set_address(udev, NULL, device_index); - /* This is the new USB device address from now on */ - - udev->address = device_index; + /* + * This is the new USB device address from now on, if + * the set address request didn't set it already. + */ + if (udev->address == USB_START_ADDR) + udev->address = device_index; /* * We ignore any set-address errors, hence there are @@ -1601,9 +1657,6 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, "(%s, ignored)\n", udev->address, usbd_errstr(err)); } - /* allow device time to set new address */ - usb_pause_mtx(NULL, - USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); } else { /* We are not self powered */ udev->flags.self_powered = 0; @@ -1622,45 +1675,16 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, } usb_set_device_state(udev, USB_STATE_ADDRESSED); - /* - * Get the first 8 bytes of the device descriptor ! - * - * NOTE: "usbd_do_request" will check the device descriptor - * next time we do a request to see if the maximum packet size - * changed! The 8 first bytes of the device descriptor - * contains the maximum packet size to use on control endpoint - * 0. If this value is different from "USB_MAX_IPACKET" a new - * USB control request will be setup! - */ - err = usbd_req_get_desc(udev, NULL, NULL, &udev->ddesc, - USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); - if (err) { - DPRINTFN(0, "getting device descriptor " - "at addr %d failed, %s\n", udev->address, - usbd_errstr(err)); + /* setup the device descriptor and the initial "wMaxPacketSize" */ + err = usbd_setup_device_desc(udev, NULL); + + if (err != 0) { /* XXX try to re-enumerate the device */ err = usbd_req_re_enumerate(udev, NULL); - if (err) { + if (err) goto done; - } } - DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " - "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", - udev->address, UGETW(udev->ddesc.bcdUSB), - udev->ddesc.bDeviceClass, - udev->ddesc.bDeviceSubClass, - udev->ddesc.bDeviceProtocol, - udev->ddesc.bMaxPacketSize, - udev->ddesc.bLength, - udev->speed); - /* get the full device descriptor */ - err = usbd_req_get_device_desc(udev, NULL, &udev->ddesc); - if (err) { - DPRINTF("addr=%d, getting full desc failed\n", - udev->address); - goto done; - } /* * Setup temporary USB attach args so that we can figure out some * basic quirks for this device. @@ -1833,9 +1857,12 @@ config_done: udev->ugen_symlink = usb_alloc_symlink(udev->ugen_name); /* Announce device */ - printf("%s: <%s> at %s\n", udev->ugen_name, udev->manufacturer, + printf("%s: <%s> at %s\n", udev->ugen_name, + usb_get_manufacturer(udev), device_get_nameunit(udev->bus->bdev)); +#endif +#if USB_HAVE_DEVCTL usb_notify_addq("ATTACH", udev); #endif done: @@ -1981,11 +2008,13 @@ usb_free_device(struct usb_device *udev, uint8_t flag) bus = udev->bus; usb_set_device_state(udev, USB_STATE_DETACHED); -#if USB_HAVE_UGEN +#if USB_HAVE_DEVCTL usb_notify_addq("DETACH", udev); +#endif +#if USB_HAVE_UGEN printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name, - udev->manufacturer, device_get_nameunit(bus->bdev)); + usb_get_manufacturer(udev), device_get_nameunit(bus->bdev)); /* Destroy UGEN symlink, if any */ if (udev->ugen_symlink) { @@ -2049,6 +2078,10 @@ usb_free_device(struct usb_device *udev, uint8_t flag) KASSERT(LIST_FIRST(&udev->pd_list) == NULL, ("leaked cdev entries")); #endif + /* Uninitialise device */ + if (bus->methods->device_uninit != NULL) + (bus->methods->device_uninit) (udev); + /* free device */ free(udev->serial, M_USB); free(udev->manufacturer, M_USB); @@ -2150,7 +2183,8 @@ usb_devinfo(struct usb_device *udev, char *dst_ptr, uint16_t dst_len) if (udd->bDeviceClass != 0xFF) { snprintf(dst_ptr, dst_len, "%s %s, class %d/%d, rev %x.%02x/" "%x.%02x, addr %d", - udev->manufacturer, udev->product, + usb_get_manufacturer(udev), + usb_get_product(udev), udd->bDeviceClass, udd->bDeviceSubClass, (bcdUSB >> 8), bcdUSB & 0xFF, (bcdDevice >> 8), bcdDevice & 0xFF, @@ -2158,7 +2192,8 @@ usb_devinfo(struct usb_device *udev, char *dst_ptr, uint16_t dst_len) } else { snprintf(dst_ptr, dst_len, "%s %s, rev %x.%02x/" "%x.%02x, addr %d", - udev->manufacturer, udev->product, + usb_get_manufacturer(udev), + usb_get_product(udev), (bcdUSB >> 8), bcdUSB & 0xFF, (bcdDevice >> 8), bcdDevice & 0xFF, udev->address); @@ -2344,7 +2379,7 @@ usbd_get_device_index(struct usb_device *udev) return (udev->device_index); } -#if USB_HAVE_UGEN +#if USB_HAVE_DEVCTL /*------------------------------------------------------------------------* * usb_notify_addq * @@ -2380,7 +2415,9 @@ usb_notify_addq_compat(const char *type, struct usb_device *udev) /* String it all together. */ snprintf(data, buf_size, "%s" +#if USB_HAVE_UGEN "%s " +#endif "vendor=0x%04x " "product=0x%04x " "devclass=0x%02x " @@ -2389,20 +2426,27 @@ usb_notify_addq_compat(const char *type, struct usb_device *udev) "release=0x%04x " "at " "port=%u " - "on " - "%s\n", +#if USB_HAVE_UGEN + "on %s\n" +#endif + "", ntype, +#if USB_HAVE_UGEN udev->ugen_name, +#endif UGETW(udev->ddesc.idVendor), UGETW(udev->ddesc.idProduct), udev->ddesc.bDeviceClass, udev->ddesc.bDeviceSubClass, - udev->serial, + usb_get_serial(udev), UGETW(udev->ddesc.bcdDevice), - udev->port_no, - udev->parent_hub != NULL ? + udev->port_no +#if USB_HAVE_UGEN + , udev->parent_hub != NULL ? udev->parent_hub->ugen_name : - device_get_nameunit(device_get_parent(udev->bus->bdev))); + device_get_nameunit(device_get_parent(udev->bus->bdev)) +#endif + ); devctl_queue_data(data); } @@ -2422,7 +2466,9 @@ usb_notify_addq(const char *type, struct usb_device *udev) /* announce the device */ sb = sbuf_new_auto(); sbuf_printf(sb, - "cdev=%s " +#if USB_HAVE_UGEN + "ugen=%s " +#endif "vendor=0x%04x " "product=0x%04x " "devclass=0x%02x " @@ -2431,19 +2477,27 @@ usb_notify_addq(const char *type, struct usb_device *udev) "release=0x%04x " "mode=%s " "port=%u " - "parent=%s\n", +#if USB_HAVE_UGEN + "parent=%s\n" +#endif + "", +#if USB_HAVE_UGEN udev->ugen_name, +#endif UGETW(udev->ddesc.idVendor), UGETW(udev->ddesc.idProduct), udev->ddesc.bDeviceClass, udev->ddesc.bDeviceSubClass, - udev->serial, + usb_get_serial(udev), UGETW(udev->ddesc.bcdDevice), (udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device", - udev->port_no, - udev->parent_hub != NULL ? - udev->parent_hub->ugen_name : - device_get_nameunit(device_get_parent(udev->bus->bdev))); + udev->port_no +#if USB_HAVE_UGEN + , udev->parent_hub != NULL ? + udev->parent_hub->ugen_name : + device_get_nameunit(device_get_parent(udev->bus->bdev)) +#endif + ); sbuf_finish(sb); devctl_notify("USB", "DEVICE", type, sbuf_data(sb)); sbuf_delete(sb); @@ -2458,7 +2512,9 @@ usb_notify_addq(const char *type, struct usb_device *udev) sb = sbuf_new_auto(); sbuf_printf(sb, - "cdev=%s " +#if USB_HAVE_UGEN + "ugen=%s " +#endif "vendor=0x%04x " "product=0x%04x " "devclass=0x%02x " @@ -2471,12 +2527,14 @@ usb_notify_addq(const char *type, struct usb_device *udev) "intclass=0x%02x " "intsubclass=0x%02x " "intprotocol=0x%02x\n", +#if USB_HAVE_UGEN udev->ugen_name, +#endif UGETW(udev->ddesc.idVendor), UGETW(udev->ddesc.idProduct), udev->ddesc.bDeviceClass, udev->ddesc.bDeviceSubClass, - udev->serial, + usb_get_serial(udev), UGETW(udev->ddesc.bcdDevice), (udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device", iface->idesc->bInterfaceNumber, @@ -2489,7 +2547,9 @@ usb_notify_addq(const char *type, struct usb_device *udev) sbuf_delete(sb); } } +#endif +#if USB_HAVE_UGEN /*------------------------------------------------------------------------* * usb_fifo_free_wrap * @@ -2577,6 +2637,17 @@ usb_set_device_state(struct usb_device *udev, enum usb_dev_state state) DPRINTF("udev %p state %s -> %s\n", udev, usb_statestr(udev->state), usb_statestr(state)); udev->state = state; + + if (udev->bus->methods->device_state_change != NULL) + (udev->bus->methods->device_state_change) (udev); +} + +enum usb_dev_state +usb_get_device_state(struct usb_device *udev) +{ + if (udev == NULL) + return (USB_STATE_DETACHED); + return (udev->state); } uint8_t diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h index 6a02f505618..c8bc5eb95a1 100644 --- a/sys/dev/usb/usb_device.h +++ b/sys/dev/usb/usb_device.h @@ -151,6 +151,7 @@ struct usb_device { uint8_t address; /* device addess */ uint8_t device_index; /* device index in "bus->devices" */ + uint8_t controller_slot_id; /* controller specific value */ uint8_t curr_config_index; /* current configuration index */ uint8_t curr_config_no; /* current configuration number */ uint8_t depth; /* distance from root HUB */ @@ -160,6 +161,7 @@ struct usb_device { uint8_t hs_port_no; /* high-speed HUB port number */ uint8_t driver_added_refcount; /* our driver added generation count */ uint8_t power_mode; /* see USB_POWER_XXX */ + uint8_t re_enumerate_wait; /* set if re-enum. is in progress */ uint8_t ifaces_max; /* number of interfaces present */ uint8_t endpoints_max; /* number of endpoints present */ @@ -168,11 +170,12 @@ struct usb_device { struct usb_device_flags flags; struct usb_endpoint_descriptor ctrl_ep_desc; /* for endpoint 0 */ + struct usb_endpoint_ss_comp_descriptor ctrl_ep_comp_desc; /* for endpoint 0 */ struct usb_device_descriptor ddesc; /* device descriptor */ - char *serial; /* serial number */ - char *manufacturer; /* manufacturer string */ - char *product; /* product string */ + char *serial; /* serial number, can be NULL */ + char *manufacturer; /* manufacturer string, can be NULL */ + char *product; /* product string, can be NULL */ #if USB_HAVE_COMPAT_LINUX /* Linux compat */ @@ -212,8 +215,9 @@ void usb_free_device(struct usb_device *, uint8_t); void usb_linux_free_device(struct usb_device *dev); uint8_t usb_peer_can_wakeup(struct usb_device *udev); struct usb_endpoint *usb_endpoint_foreach(struct usb_device *udev, struct usb_endpoint *ep); -void usb_set_device_state(struct usb_device *udev, - enum usb_dev_state state); +void usb_set_device_state(struct usb_device *, enum usb_dev_state); +enum usb_dev_state usb_get_device_state(struct usb_device *); + void usbd_enum_lock(struct usb_device *); void usbd_enum_unlock(struct usb_device *); void usbd_sr_lock(struct usb_device *); diff --git a/sys/dev/usb/usb_freebsd.h b/sys/dev/usb/usb_freebsd.h index 8a008cd47dd..efc27f20990 100644 --- a/sys/dev/usb/usb_freebsd.h +++ b/sys/dev/usb/usb_freebsd.h @@ -33,6 +33,7 @@ /* Default USB configuration */ #define USB_HAVE_UGEN 1 +#define USB_HAVE_DEVCTL 1 #define USB_HAVE_BUSDMA 1 #define USB_HAVE_COMPAT_LINUX 1 #define USB_HAVE_USER_IO 1 diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index 66677518a14..872979b1dd2 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -109,7 +109,7 @@ static int usb_gen_fill_deviceinfo(struct usb_fifo *, static int ugen_re_enumerate(struct usb_fifo *); static int ugen_iface_ioctl(struct usb_fifo *, u_long, void *, int); static uint8_t ugen_fs_get_complete(struct usb_fifo *, uint8_t *); -static int ugen_fs_uninit(struct usb_fifo *f); +static int ugen_fs_uninit(struct usb_fifo *f); /* structures */ @@ -825,9 +825,9 @@ usb_gen_fill_deviceinfo(struct usb_fifo *f, struct usb_device_info *di) di->udi_bus = device_get_unit(udev->bus->bdev); di->udi_addr = udev->address; di->udi_index = udev->device_index; - strlcpy(di->udi_serial, udev->serial, sizeof(di->udi_serial)); - strlcpy(di->udi_vendor, udev->manufacturer, sizeof(di->udi_vendor)); - strlcpy(di->udi_product, udev->product, sizeof(di->udi_product)); + strlcpy(di->udi_serial, usb_get_serial(udev), sizeof(di->udi_serial)); + strlcpy(di->udi_vendor, usb_get_manufacturer(udev), sizeof(di->udi_vendor)); + strlcpy(di->udi_product, usb_get_product(udev), sizeof(di->udi_product)); usb_printbcd(di->udi_release, sizeof(di->udi_release), UGETW(udev->ddesc.bcdDevice)); di->udi_vendorNo = UGETW(udev->ddesc.idVendor); @@ -951,23 +951,19 @@ ugen_re_enumerate(struct usb_fifo *f) if (error) { return (error); } - /* get the device unconfigured */ - error = ugen_set_config(f, USB_UNCONFIG_INDEX); - if (error) { - return (error); + if (udev->flags.usb_mode != USB_MODE_HOST) { + /* not possible in device side mode */ + return (ENOTTY); } - /* do a bus-reset */ - mtx_lock(f->priv_mtx); - error = usbd_req_re_enumerate(udev, f->priv_mtx); - mtx_unlock(f->priv_mtx); - - if (error) { - return (ENXIO); + /* make sure all FIFO's are gone */ + /* else there can be a deadlock */ + if (ugen_fs_uninit(f)) { + /* ignore any errors */ + DPRINTFN(6, "no FIFOs\n"); } - /* restore configuration to index 0 */ - error = ugen_set_config(f, 0); - if (error) { - return (error); + if (udev->re_enumerate_wait == 0) { + udev->re_enumerate_wait = 1; + usb_needs_explore(udev->bus, 0); } return (0); } @@ -1775,9 +1771,11 @@ ugen_set_power_mode(struct usb_fifo *f, int mode) /* if we are powered off we need to re-enumerate first */ if (old_mode == USB_POWER_MODE_OFF) { - err = ugen_re_enumerate(f); - if (err) - return (err); + if (udev->flags.usb_mode == USB_MODE_HOST) { + if (udev->re_enumerate_wait == 0) + udev->re_enumerate_wait = 1; + } + /* set power mode will wake up the explore thread */ } /* set new power mode */ @@ -1791,10 +1789,9 @@ ugen_get_power_mode(struct usb_fifo *f) { struct usb_device *udev = f->udev; - if ((udev == NULL) || - (udev->parent_hub == NULL)) { + if (udev == NULL) return (USB_POWER_MODE_ON); - } + return (udev->power_mode); } diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c index 92bf8329eb8..c79a9cc2182 100644 --- a/sys/dev/usb/usb_handle_request.c +++ b/sys/dev/usb/usb_handle_request.c @@ -438,8 +438,10 @@ usb_handle_remote_wakeup(struct usb_xfer *xfer, uint8_t is_on) USB_BUS_UNLOCK(bus); +#if USB_HAVE_POWERD /* In case we are out of sync, update the power state. */ usb_bus_power_update(udev->bus); +#endif return (0); /* success */ } diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 95e9b294b96..afeadaa4c39 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -2,7 +2,7 @@ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. * Copyright (c) 1998 Lennart Augustsson. All rights reserved. - * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. + * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,6 +53,7 @@ #include #include #include +#include #define USB_DEBUG_VAR uhub_debug @@ -109,6 +110,7 @@ struct uhub_softc { #define UHUB_PROTO(sc) ((sc)->sc_udev->ddesc.bDeviceProtocol) #define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB) #define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT) +#define UHUB_IS_SUPER_SPEED(sc) (UHUB_PROTO(sc) == UDPROTO_SSHUB) /* prototypes for type checking: */ @@ -170,6 +172,7 @@ static driver_t uhub_driver = { DRIVER_MODULE(uhub, usbus, uhub_driver, uhub_devclass, 0, 0); DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, NULL, 0); +MODULE_VERSION(uhub, 1); static void uhub_intr_callback(struct usb_xfer *xfer, usb_error_t error) @@ -234,6 +237,27 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up) /* nothing to do */ goto done; } + + /* check if device should be re-enumerated */ + + if (child->flags.usb_mode == USB_MODE_HOST) { + usbd_enum_lock(child); + if (child->re_enumerate_wait) { + err = usbd_set_config_index(child, USB_UNCONFIG_INDEX); + if (err == 0) + err = usbd_req_re_enumerate(child, NULL); + if (err == 0) + err = usbd_set_config_index(child, 0); + if (err == 0) { + err = usb_probe_and_attach(child, + USB_IFACE_INDEX_ANY); + } + child->re_enumerate_wait = 0; + err = 0; + } + usbd_enum_unlock(child); + } + /* check if probe and attach should be done */ if (child->driver_added_refcount != refcount) { @@ -246,14 +270,14 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up) } /* start control transfer, if device mode */ - if (child->flags.usb_mode == USB_MODE_DEVICE) { + if (child->flags.usb_mode == USB_MODE_DEVICE) usbd_ctrl_transfer_setup(child); - } + /* if a HUB becomes present, do a recursive HUB explore */ - if (child->hub) { + if (child->hub) err = (child->hub->explore) (child); - } + done: return (err); } @@ -352,11 +376,17 @@ repeat: DPRINTF("Port %d is in Host Mode\n", portno); if (sc->sc_st.port_status & UPS_SUSPEND) { + /* + * NOTE: Should not get here in SuperSpeed + * mode, because the HUB should report this + * bit as zero. + */ DPRINTF("Port %d was still " "suspended, clearing.\n", portno); - err = usbd_req_clear_port_feature(sc->sc_udev, + err = usbd_req_clear_port_feature(udev, NULL, portno, UHF_PORT_SUSPEND); } + /* USB Host Mode */ /* wait for maximum device power up time */ @@ -417,11 +447,49 @@ repeat: case USB_SPEED_LOW: speed = USB_SPEED_LOW; break; + case USB_SPEED_SUPER: + if (udev->parent_hub == NULL) { + /* Root HUB - special case */ + switch (sc->sc_st.port_status & UPS_OTHER_SPEED) { + case 0: + speed = USB_SPEED_FULL; + break; + case UPS_LOW_SPEED: + speed = USB_SPEED_LOW; + break; + case UPS_HIGH_SPEED: + speed = USB_SPEED_HIGH; + break; + default: + speed = USB_SPEED_SUPER; + break; + } + } else { + speed = USB_SPEED_SUPER; + } + break; default: /* same speed like parent */ speed = udev->speed; break; } + if (speed == USB_SPEED_SUPER) { + err = usbd_req_set_hub_u1_timeout(udev, NULL, + portno, 128 - (2 * udev->depth)); + if (err) { + DPRINTFN(0, "port %d U1 timeout " + "failed, error=%s\n", + portno, usbd_errstr(err)); + } + err = usbd_req_set_hub_u2_timeout(udev, NULL, + portno, 128 - (2 * udev->depth)); + if (err) { + DPRINTFN(0, "port %d U2 timeout " + "failed, error=%s\n", + portno, usbd_errstr(err)); + } + } + /* * Figure out the device mode * @@ -463,6 +531,28 @@ error: return (err); } +/*------------------------------------------------------------------------* + * usb_device_20_compatible + * + * Returns: + * 0: HUB does not support suspend and resume + * Else: HUB supports suspend and resume + *------------------------------------------------------------------------*/ +static uint8_t +usb_device_20_compatible(struct usb_device *udev) +{ + if (udev == NULL) + return (0); + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + return (1); + default: + return (0); + } +} + /*------------------------------------------------------------------------* * uhub_suspend_resume_port * @@ -486,8 +576,14 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno) /* first clear the port suspend change bit */ - err = usbd_req_clear_port_feature(udev, NULL, - portno, UHF_C_PORT_SUSPEND); + if (usb_device_20_compatible(udev)) { + err = usbd_req_clear_port_feature(udev, NULL, + portno, UHF_C_PORT_SUSPEND); + } else { + err = usbd_req_clear_port_feature(udev, NULL, + portno, UHF_C_PORT_LINK_STATE); + } + if (err) { DPRINTF("clearing suspend failed.\n"); goto done; @@ -499,12 +595,24 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno) DPRINTF("reading port status failed.\n"); goto done; } - /* get current state */ + /* convert current state */ - if (sc->sc_st.port_status & UPS_SUSPEND) { - is_suspend = 1; + if (usb_device_20_compatible(udev)) { + if (sc->sc_st.port_status & UPS_SUSPEND) { + is_suspend = 1; + } else { + is_suspend = 0; + } } else { - is_suspend = 0; + switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) { + case UPS_PORT_LS_U0: + case UPS_PORT_LS_U1: + is_suspend = 0; + break; + default: + is_suspend = 1; + break; + } } DPRINTF("suspended=%u\n", is_suspend); @@ -519,7 +627,8 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno) */ if (is_suspend == 0) usb_dev_resume_peer(child); - else if (child->flags.usb_mode == USB_MODE_DEVICE) + else if ((child->flags.usb_mode == USB_MODE_DEVICE) || + (usb_device_20_compatible(child) == 0)) usb_dev_suspend_peer(child); } done: @@ -541,6 +650,26 @@ uhub_root_intr(struct usb_bus *bus, const uint8_t *ptr, uint8_t len) usb_needs_explore(bus, 0); } +static uint8_t +uhub_is_too_deep(struct usb_device *udev) +{ + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + case USB_SPEED_HIGH: + if (udev->depth > USB_HUB_MAX_DEPTH) + return (1); + break; + case USB_SPEED_SUPER: + if (udev->depth > USB_SS_HUB_DEPTH_MAX) + return (1); + break; + default: + break; + } + return (0); +} + /*------------------------------------------------------------------------* * uhub_explore * @@ -563,11 +692,11 @@ uhub_explore(struct usb_device *udev) DPRINTFN(11, "udev=%p addr=%d\n", udev, udev->address); - /* ignore hubs that are too deep */ - if (udev->depth > USB_HUB_MAX_DEPTH) { + /* ignore devices that are too deep */ + if (uhub_is_too_deep(udev)) return (USB_ERR_TOO_DEEP); - } + /* check if device is suspended */ if (udev->flags.self_suspended) { /* need to wait until the child signals resume */ DPRINTF("Device is suspended!\n"); @@ -634,7 +763,7 @@ uhub_explore(struct usb_device *udev) break; } } - if (sc->sc_st.port_change & UPS_C_SUSPEND) { + if (sc->sc_st.port_change & (UPS_C_SUSPEND | UPS_C_PORT_LINK_STATE)) { err = uhub_suspend_resume_port(sc, portno); if (err) { /* most likely the HUB is gone */ @@ -662,20 +791,81 @@ uhub_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } + /* - * The subclass for USB HUBs is ignored because it is 0 for - * some and 1 for others. + * The subclass for USB HUBs is currently ignored because it + * is 0 for some and 1 for others. */ - if ((uaa->info.bConfigIndex == 0) && - (uaa->info.bDeviceClass == UDCLASS_HUB)) { + if (uaa->info.bConfigIndex == 0 && + uaa->info.bDeviceClass == UDCLASS_HUB) return (0); - } + return (ENXIO); } +/* NOTE: The information returned by this function can be wrong. */ +usb_error_t +uhub_query_info(struct usb_device *udev, uint8_t *pnports, uint8_t *ptt) +{ + struct usb_hub_descriptor hubdesc20; + struct usb_hub_ss_descriptor hubdesc30; + usb_error_t err; + uint8_t nports; + uint8_t tt; + + if (udev->ddesc.bDeviceClass != UDCLASS_HUB) + return (USB_ERR_INVAL); + + nports = 0; + tt = 0; + + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + /* assuming that there is one port */ + err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1); + if (err) { + DPRINTFN(0, "getting USB 2.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + break; + } + nports = hubdesc20.bNbrPorts; + if (nports > 127) + nports = 127; + + if (udev->speed == USB_SPEED_HIGH) + tt = (UGETW(hubdesc20.wHubCharacteristics) >> 5) & 3; + break; + + case USB_SPEED_SUPER: + err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, 1); + if (err) { + DPRINTFN(0, "Getting USB 3.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + break; + } + nports = hubdesc30.bNbrPorts; + if (nports > 16) + nports = 16; + break; + + default: + err = USB_ERR_INVAL; + break; + } + + if (pnports != NULL) + *pnports = nports; + + if (ptt != NULL) + *ptt = tt; + + return (err); +} + static int uhub_attach(device_t dev) { @@ -684,7 +874,8 @@ uhub_attach(device_t dev) struct usb_device *udev = uaa->device; struct usb_device *parent_hub = udev->parent_hub; struct usb_hub *hub; - struct usb_hub_descriptor hubdesc; + struct usb_hub_descriptor hubdesc20; + struct usb_hub_ss_descriptor hubdesc30; uint16_t pwrdly; uint8_t x; uint8_t nports; @@ -711,38 +902,114 @@ uhub_attach(device_t dev) parent_hub ? parent_hub->flags.self_powered : 0); - if (udev->depth > USB_HUB_MAX_DEPTH) { - DPRINTFN(0, "hub depth, %d, exceeded. HUB ignored\n", - USB_HUB_MAX_DEPTH); + if (uhub_is_too_deep(udev)) { + DPRINTFN(0, "HUB at depth %d, " + "exceeds maximum. HUB ignored\n", (int)udev->depth); goto error; } + if (!udev->flags.self_powered && parent_hub && - (!parent_hub->flags.self_powered)) { - DPRINTFN(0, "bus powered HUB connected to " + !parent_hub->flags.self_powered) { + DPRINTFN(0, "Bus powered HUB connected to " "bus powered HUB. HUB ignored\n"); goto error; } /* get HUB descriptor */ - DPRINTFN(2, "getting HUB descriptor\n"); + DPRINTFN(2, "Getting HUB descriptor\n"); - /* assuming that there is one port */ - err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc, 1); + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + /* assuming that there is one port */ + err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1); + if (err) { + DPRINTFN(0, "getting USB 2.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + goto error; + } + /* get number of ports */ + nports = hubdesc20.bNbrPorts; - nports = hubdesc.bNbrPorts; + /* get power delay */ + pwrdly = ((hubdesc20.bPwrOn2PwrGood * UHD_PWRON_FACTOR) + + USB_EXTRA_POWER_UP_TIME); - if (!err && (nports >= 8)) { /* get complete HUB descriptor */ - err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc, nports); - } - if (err) { - DPRINTFN(0, "getting hub descriptor failed," - "error=%s\n", usbd_errstr(err)); - goto error; - } - if (hubdesc.bNbrPorts != nports) { - DPRINTFN(0, "number of ports changed\n"); - goto error; + if (nports >= 8) { + /* check number of ports */ + if (nports > 127) { + DPRINTFN(0, "Invalid number of USB 2.0 ports," + "error=%s\n", usbd_errstr(err)); + goto error; + } + /* get complete HUB descriptor */ + err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, nports); + + if (err) { + DPRINTFN(0, "Getting USB 2.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + goto error; + } + if (hubdesc20.bNbrPorts != nports) { + DPRINTFN(0, "Number of ports changed\n"); + goto error; + } + } + break; + case USB_SPEED_SUPER: + if (udev->parent_hub != NULL) { + err = usbd_req_set_hub_depth(udev, NULL, + udev->depth - 1); + if (err) { + DPRINTFN(0, "Setting USB 3.0 HUB depth failed," + "error=%s\n", usbd_errstr(err)); + goto error; + } + } + err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, 1); + if (err) { + DPRINTFN(0, "Getting USB 3.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + goto error; + } + /* get number of ports */ + nports = hubdesc30.bNbrPorts; + + /* get power delay */ + pwrdly = ((hubdesc30.bPwrOn2PwrGood * UHD_PWRON_FACTOR) + + USB_EXTRA_POWER_UP_TIME); + + /* get complete HUB descriptor */ + if (nports >= 8) { + /* check number of ports */ + if (nports > ((udev->parent_hub != NULL) ? 15 : 127)) { + DPRINTFN(0, "Invalid number of USB 3.0 ports," + "error=%s\n", usbd_errstr(err)); + goto error; + } + /* get complete HUB descriptor */ + err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, nports); + + if (err) { + DPRINTFN(0, "Getting USB 2.0 HUB descriptor failed," + "error=%s\n", usbd_errstr(err)); + goto error; + } + if (hubdesc30.bNbrPorts != nports) { + DPRINTFN(0, "Number of ports changed\n"); + goto error; + } + } + break; + default: + DPRINTF("Assuming HUB has only one port\n"); + /* default number of ports */ + nports = 1; + /* default power delay */ + pwrdly = ((10 * UHD_PWRON_FACTOR) + USB_EXTRA_POWER_UP_TIME); + break; } if (nports == 0) { DPRINTFN(0, "portless HUB\n"); @@ -763,7 +1030,7 @@ uhub_attach(device_t dev) /* initialize HUB structure */ hub->hubsoftc = sc; hub->explore = &uhub_explore; - hub->nports = hubdesc.bNbrPorts; + hub->nports = nports; hub->hubudev = udev; /* if self powered hub, give ports maximum current */ @@ -819,8 +1086,6 @@ uhub_attach(device_t dev) /* XXX should check for none, individual, or ganged power? */ removable = 0; - pwrdly = ((hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR) + - USB_EXTRA_POWER_UP_TIME); for (x = 0; x != nports; x++) { /* set up data structures */ @@ -831,8 +1096,21 @@ uhub_attach(device_t dev) portno = x + 1; /* check if port is removable */ - if (!UHD_NOT_REMOV(&hubdesc, portno)) { + switch (udev->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + if (!UHD_NOT_REMOV(&hubdesc20, portno)) + removable++; + break; + case USB_SPEED_SUPER: + if (!UHD_NOT_REMOV(&hubdesc30, portno)) + removable++; + break; + default: + DPRINTF("Assuming removable port\n"); removable++; + break; } if (!err) { /* turn the power on */ @@ -893,9 +1171,8 @@ uhub_detach(device_t dev) struct usb_device *child; uint8_t x; - if (hub == NULL) { /* must be partially working */ + if (hub == NULL) /* must be partially working */ return (0); - } /* Make sure interrupt transfer is gone. */ usbd_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER); @@ -1058,7 +1335,7 @@ uhub_child_pnpinfo_string(device_t parent, device_t child, UGETW(res.udev->ddesc.idProduct), res.udev->ddesc.bDeviceClass, res.udev->ddesc.bDeviceSubClass, - res.udev->serial, + usb_get_serial(res.udev), UGETW(res.udev->ddesc.bcdDevice), iface->idesc->bInterfaceClass, iface->idesc->bInterfaceSubClass); @@ -1761,10 +2038,13 @@ static uint8_t usb_peer_should_wakeup(struct usb_device *udev) { return ((udev->power_mode == USB_POWER_MODE_ON) || + (udev->driver_added_refcount != udev->bus->driver_added_refcount) || + (udev->re_enumerate_wait != 0) || (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0) || (udev->pwr_save.write_refs != 0) || ((udev->pwr_save.read_refs != 0) && (udev->flags.usb_mode == USB_MODE_HOST) && + (usb_device_20_compatible(udev) != 0) && (usb_peer_can_wakeup(udev) == 0))); } @@ -1936,13 +2216,16 @@ usb_dev_resume_peer(struct usb_device *udev) /* reduce chance of instant resume failure by waiting a little bit */ usb_pause_mtx(NULL, USB_MS_TO_TICKS(20)); - /* resume current port (Valid in Host and Device Mode) */ - err = usbd_req_clear_port_feature(udev->parent_hub, - NULL, udev->port_no, UHF_PORT_SUSPEND); - if (err) { - DPRINTFN(0, "Resuming port failed\n"); - return; + if (usb_device_20_compatible(udev)) { + /* resume current port (Valid in Host and Device Mode) */ + err = usbd_req_clear_port_feature(udev->parent_hub, + NULL, udev->port_no, UHF_PORT_SUSPEND); + if (err) { + DPRINTFN(0, "Resuming port failed\n"); + return; + } } + /* resume settle time */ usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_PORT_RESUME_DELAY)); @@ -1982,7 +2265,8 @@ usb_dev_resume_peer(struct usb_device *udev) usbd_sr_unlock(udev); /* check if peer has wakeup capability */ - if (usb_peer_can_wakeup(udev)) { + if (usb_peer_can_wakeup(udev) && + usb_device_20_compatible(udev)) { /* clear remote wakeup */ err = usbd_req_clear_device_feature(udev, NULL, UF_DEVICE_REMOTE_WAKEUP); @@ -1992,7 +2276,6 @@ usb_dev_resume_peer(struct usb_device *udev) usbd_errstr(err)); } } - return; } /*------------------------------------------------------------------------* @@ -2030,7 +2313,6 @@ repeat: /* check if all devices on the HUB are suspended */ for (x = 0; x != nports; x++) { - child = usb_bus_port_get_device(udev->bus, udev->hub->ports + x); @@ -2045,6 +2327,22 @@ repeat: } } + if (usb_peer_can_wakeup(udev) && + usb_device_20_compatible(udev)) { + /* + * This request needs to be done before we set + * "udev->flags.self_suspended": + */ + + /* allow device to do remote wakeup */ + err = usbd_req_set_device_feature(udev, + NULL, UF_DEVICE_REMOTE_WAKEUP); + if (err) { + DPRINTFN(0, "Setting device " + "remote wakeup failed\n"); + } + } + USB_BUS_LOCK(udev->bus); /* * Checking for suspend condition and setting suspended bit @@ -2062,6 +2360,17 @@ repeat: USB_BUS_UNLOCK(udev->bus); if (err != 0) { + if (usb_peer_can_wakeup(udev) && + usb_device_20_compatible(udev)) { + /* allow device to do remote wakeup */ + err = usbd_req_clear_device_feature(udev, + NULL, UF_DEVICE_REMOTE_WAKEUP); + if (err) { + DPRINTFN(0, "Setting device " + "remote wakeup failed\n"); + } + } + if (udev->flags.usb_mode == USB_MODE_DEVICE) { /* resume parent HUB first */ usb_dev_resume_peer(udev->parent_hub); @@ -2087,16 +2396,6 @@ repeat: usbd_sr_unlock(udev); - if (usb_peer_can_wakeup(udev)) { - /* allow device to do remote wakeup */ - err = usbd_req_set_device_feature(udev, - NULL, UF_DEVICE_REMOTE_WAKEUP); - if (err) { - DPRINTFN(0, "Setting device " - "remote wakeup failed\n"); - } - } - if (udev->bus->methods->device_suspend != NULL) { usb_timeout_t temp; @@ -2104,16 +2403,20 @@ repeat: (udev->bus->methods->device_suspend) (udev); /* do DMA delay */ - temp = usbd_get_dma_delay(udev->bus); - usb_pause_mtx(NULL, USB_MS_TO_TICKS(temp)); + temp = usbd_get_dma_delay(udev); + if (temp != 0) + usb_pause_mtx(NULL, USB_MS_TO_TICKS(temp)); } - /* suspend current port */ - err = usbd_req_set_port_feature(udev->parent_hub, - NULL, udev->port_no, UHF_PORT_SUSPEND); - if (err) { - DPRINTFN(0, "Suspending port failed\n"); - return; + + if (usb_device_20_compatible(udev)) { + /* suspend current port */ + err = usbd_req_set_port_feature(udev->parent_hub, + NULL, udev->port_no, UHF_PORT_SUSPEND); + if (err) { + DPRINTFN(0, "Suspending port failed\n"); + return; + } } udev = udev->parent_hub; @@ -2131,12 +2434,39 @@ usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode) { /* filter input argument */ if ((power_mode != USB_POWER_MODE_ON) && - (power_mode != USB_POWER_MODE_OFF)) { + (power_mode != USB_POWER_MODE_OFF)) power_mode = USB_POWER_MODE_SAVE; - } + + power_mode = usbd_filter_power_mode(udev, power_mode); + udev->power_mode = power_mode; /* update copy of power mode */ #if USB_HAVE_POWERD usb_bus_power_update(udev->bus); #endif } + +/*------------------------------------------------------------------------* + * usbd_filter_power_mode + * + * This function filters the power mode based on hardware requirements. + *------------------------------------------------------------------------*/ +uint8_t +usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode) +{ + struct usb_bus_methods *mtod; + int8_t temp; + + mtod = udev->bus->methods; + temp = -1; + + if (mtod->get_power_mode != NULL) + (mtod->get_power_mode) (udev, &temp); + + /* check if we should not filter */ + if (temp < 0) + return (power_mode); + + /* use fixed power mode given by hardware driver */ + return (temp); +} diff --git a/sys/dev/usb/usb_hub.h b/sys/dev/usb/usb_hub.h index 5b8dedf6e64..0f595997708 100644 --- a/sys/dev/usb/usb_hub.h +++ b/sys/dev/usb/usb_hub.h @@ -78,5 +78,6 @@ void usb_needs_explore_all(void); void usb_bus_power_update(struct usb_bus *bus); void usb_bus_powerd(struct usb_bus *bus); void uhub_root_intr(struct usb_bus *, const uint8_t *, uint8_t); +usb_error_t uhub_query_info(struct usb_device *, uint8_t *, uint8_t *); #endif /* _USB_HUB_H_ */ diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h index f9018e283ec..8fe55e18bd2 100644 --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -41,13 +41,21 @@ #define USB_GENERIC_NAME "ugen" struct usb_read_dir { +#ifdef COMPAT_32BIT + uint64_t urd_data; +#else void *urd_data; +#endif uint32_t urd_startentry; uint32_t urd_maxlen; }; struct usb_ctl_request { +#ifdef COMPAT_32BIT + uint64_t ucr_data; +#else void *ucr_data; +#endif uint16_t ucr_flags; uint16_t ucr_actlen; /* actual length transferred */ uint8_t ucr_addr; /* zero - currently not used */ @@ -60,7 +68,11 @@ struct usb_alt_interface { }; struct usb_gen_descriptor { +#ifdef COMPAT_32BIT + uint64_t ugd_data; +#else void *ugd_data; +#endif uint16_t ugd_lang_id; uint16_t ugd_maxlen; uint16_t ugd_actlen; @@ -126,9 +138,14 @@ struct usb_fs_endpoint { * NOTE: isochronous USB transfer only use one buffer, but can have * multiple frame lengths ! */ +#ifdef COMPAT_32BIT + uint64_t ppBuffer; + uint64_t pLength; +#else void **ppBuffer; /* pointer to userland buffers */ uint32_t *pLength; /* pointer to frame lengths, updated * to actual length */ +#endif uint32_t nFrames; /* number of frames */ uint32_t aFrames; /* actual number of frames */ uint16_t flags; @@ -150,7 +167,11 @@ struct usb_fs_endpoint { struct usb_fs_init { /* userland pointer to endpoints structure */ +#ifdef COMPAT_32BIT + uint64_t pEndpoints; +#else struct usb_fs_endpoint *pEndpoints; +#endif /* maximum number of endpoints */ uint8_t ep_index_max; }; diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c index ed9eac40ba7..d488196b160 100644 --- a/sys/dev/usb/usb_msctest.c +++ b/sys/dev/usb/usb_msctest.c @@ -97,6 +97,7 @@ static uint8_t scsi_cmotech_eject[] = { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43, static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 }; #define BULK_SIZE 64 /* dummy */ #define ERR_CSW_FAILED -1 @@ -467,7 +468,6 @@ bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, sc->data_rem = data_len; sc->data_timeout = (data_timeout + USB_MS_HZ); sc->actlen = 0; - sc->data_ptr = data_ptr; sc->cmd_len = cmd_len; bzero(&sc->cbw.CBWCDB, sizeof(sc->cbw.CBWCDB)); bcopy(cmd_ptr, &sc->cbw.CBWCDB, cmd_len); @@ -619,6 +619,15 @@ usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method) &scsi_huawei_eject, sizeof(scsi_huawei_eject), USB_MS_HZ); break; + case MSC_EJECT_TCT: + /* + * TCTMobile needs DIR_IN flag. To get it, we + * supply a dummy data with the command. + */ + err = bbb_command_start(sc, DIR_IN, 0, &sc->buffer, + sizeof(sc->buffer), &scsi_tct_eject, + sizeof(scsi_tct_eject), USB_MS_HZ); + break; default: printf("usb_msc_eject: unknown eject method (%d)\n", method); break; diff --git a/sys/dev/usb/usb_msctest.h b/sys/dev/usb/usb_msctest.h index ce763df3fbe..807d5f5d5d5 100644 --- a/sys/dev/usb/usb_msctest.h +++ b/sys/dev/usb/usb_msctest.h @@ -33,6 +33,7 @@ enum { MSC_EJECT_ZTESTOR, MSC_EJECT_CMOTECH, MSC_EJECT_HUAWEI, + MSC_EJECT_TCT, }; int usb_iface_is_cdrom(struct usb_device *udev, diff --git a/sys/dev/usb/usb_parse.c b/sys/dev/usb/usb_parse.c index deb52ea50e8..8663c1e0783 100644 --- a/sys/dev/usb/usb_parse.c +++ b/sys/dev/usb/usb_parse.c @@ -180,7 +180,7 @@ usb_edesc_foreach(struct usb_config_descriptor *cd, } if (desc->bDescriptorType == UDESC_ENDPOINT) { if (desc->bLength < sizeof(*ped)) { - /* endpoint index is invalid */ + /* endpoint descriptor is invalid */ break; } return ((struct usb_endpoint_descriptor *)desc); @@ -189,6 +189,42 @@ usb_edesc_foreach(struct usb_config_descriptor *cd, return (NULL); } +/*------------------------------------------------------------------------* + * usb_ed_comp_foreach + * + * This function will iterate all the endpoint companion descriptors + * within an endpoint descriptor in an interface descriptor. Starting + * value for the "ped" argument should be a valid endpoint companion + * descriptor. + * + * Return values: + * NULL: End of descriptors + * Else: A valid endpoint companion descriptor + *------------------------------------------------------------------------*/ +struct usb_endpoint_ss_comp_descriptor * +usb_ed_comp_foreach(struct usb_config_descriptor *cd, + struct usb_endpoint_ss_comp_descriptor *ped) +{ + struct usb_descriptor *desc; + + desc = ((struct usb_descriptor *)ped); + + while ((desc = usb_desc_foreach(cd, desc))) { + if (desc->bDescriptorType == UDESC_INTERFACE) + break; + if (desc->bDescriptorType == UDESC_ENDPOINT) + break; + if (desc->bDescriptorType == UDESC_ENDPOINT_SS_COMP) { + if (desc->bLength < sizeof(*ped)) { + /* endpoint companion descriptor is invalid */ + break; + } + return ((struct usb_endpoint_ss_comp_descriptor *)desc); + } + } + return (NULL); +} + /*------------------------------------------------------------------------* * usbd_get_no_descriptors * diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c index a3c685d3123..859af692f52 100644 --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -245,6 +245,8 @@ usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error) ep->is_stalled) { ep->toggle_next = 0; ep->is_stalled = 0; + /* some hardware needs a callback to clear the data toggle */ + usbd_clear_stall_locked(udev, ep); /* start up the current or next transfer, if any */ usb_command_wrapper(&ep->endpoint_q, ep->endpoint_q.curr); @@ -1018,14 +1020,21 @@ usbd_req_get_string_any(struct usb_device *udev, struct mtx *mtx, char *buf, } /* - * Filter by default - we don't allow greater and less than - * signs because they might confuse the dmesg printouts! + * Filter by default - We only allow alphanumerical + * and a few more to avoid any problems with scripts + * and daemons. */ - if ((*s == '<') || (*s == '>') || (!isprint(*s))) { - /* silently skip bad character */ - continue; + if (isalpha(*s) || + isdigit(*s) || + *s == '-' || + *s == '+' || + *s == ' ' || + *s == '.' || + *s == ',') { + /* allowed */ + s++; } - s++; + /* silently skip bad character */ } *s = 0; /* zero terminate resulting string */ return (USB_ERR_NORMAL_COMPLETION); @@ -1292,6 +1301,28 @@ usbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, return (usbd_do_request(udev, mtx, &req, hd)); } +/*------------------------------------------------------------------------* + * usbd_req_get_ss_hub_descriptor + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_get_ss_hub_descriptor(struct usb_device *udev, struct mtx *mtx, + struct usb_hub_ss_descriptor *hd, uint8_t nports) +{ + struct usb_device_request req; + uint16_t len = sizeof(*hd) - 32 + 1 + ((nports + 7) / 8); + + req.bmRequestType = UT_READ_CLASS_DEVICE; + req.bRequest = UR_GET_DESCRIPTOR; + USETW2(req.wValue, UDESC_SS_HUB, 0); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (usbd_do_request(udev, mtx, &req, hd)); +} + /*------------------------------------------------------------------------* * usbd_req_get_hub_status * @@ -1327,6 +1358,7 @@ usb_error_t usbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) { struct usb_device_request req; + usb_error_t err; DPRINTFN(6, "setting device address=%d\n", addr); @@ -1336,9 +1368,25 @@ usbd_req_set_address(struct usb_device *udev, struct mtx *mtx, uint16_t addr) USETW(req.wIndex, 0); USETW(req.wLength, 0); + err = USB_ERR_INVAL; + + /* check if USB controller handles set address */ + if (udev->bus->methods->set_address != NULL) + err = (udev->bus->methods->set_address) (udev, mtx, addr); + + if (err != USB_ERR_INVAL) + goto done; + /* Setting the address should not take more than 1 second ! */ - return (usbd_do_request_flags(udev, mtx, &req, NULL, - USB_DELAY_STATUS_STAGE, NULL, 1000)); + err = usbd_do_request_flags(udev, mtx, &req, NULL, + USB_DELAY_STATUS_STAGE, NULL, 1000); + +done: + /* allow device time to set new address */ + usb_pause_mtx(mtx, + USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); + + return (err); } /*------------------------------------------------------------------------* @@ -1405,6 +1453,71 @@ usbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, return (usbd_do_request(udev, mtx, &req, 0)); } +/*------------------------------------------------------------------------* + * usbd_req_set_hub_u1_timeout + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_set_hub_u1_timeout(struct usb_device *udev, struct mtx *mtx, + uint8_t port, uint8_t timeout) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_CLASS_OTHER; + req.bRequest = UR_SET_FEATURE; + USETW(req.wValue, UHF_PORT_U1_TIMEOUT); + req.wIndex[0] = port; + req.wIndex[1] = timeout; + USETW(req.wLength, 0); + return (usbd_do_request(udev, mtx, &req, 0)); +} + +/*------------------------------------------------------------------------* + * usbd_req_set_hub_u2_timeout + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_set_hub_u2_timeout(struct usb_device *udev, struct mtx *mtx, + uint8_t port, uint8_t timeout) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_CLASS_OTHER; + req.bRequest = UR_SET_FEATURE; + USETW(req.wValue, UHF_PORT_U2_TIMEOUT); + req.wIndex[0] = port; + req.wIndex[1] = timeout; + USETW(req.wLength, 0); + return (usbd_do_request(udev, mtx, &req, 0)); +} + +/*------------------------------------------------------------------------* + * usbd_req_set_hub_depth + * + * Returns: + * 0: Success + * Else: Failure + *------------------------------------------------------------------------*/ +usb_error_t +usbd_req_set_hub_depth(struct usb_device *udev, struct mtx *mtx, + uint16_t depth) +{ + struct usb_device_request req; + + req.bmRequestType = UT_WRITE_CLASS_DEVICE; + req.bRequest = UR_SET_HUB_DEPTH; + USETW(req.wValue, depth); + USETW(req.wIndex, 0); + USETW(req.wLength, 0); + return (usbd_do_request(udev, mtx, &req, 0)); +} + /*------------------------------------------------------------------------* * usbd_req_clear_port_feature * @@ -1637,6 +1750,68 @@ usbd_req_get_config(struct usb_device *udev, struct mtx *mtx, uint8_t *pconf) return (usbd_do_request(udev, mtx, &req, pconf)); } +/*------------------------------------------------------------------------* + * usbd_setup_device_desc + *------------------------------------------------------------------------*/ +usb_error_t +usbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx) +{ + usb_error_t err; + + /* + * Get the first 8 bytes of the device descriptor ! + * + * NOTE: "usbd_do_request()" will check the device descriptor + * next time we do a request to see if the maximum packet size + * changed! The 8 first bytes of the device descriptor + * contains the maximum packet size to use on control endpoint + * 0. If this value is different from "USB_MAX_IPACKET" a new + * USB control request will be setup! + */ + switch (udev->speed) { + case USB_SPEED_FULL: + case USB_SPEED_LOW: + err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, + USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); + if (err != 0) { + DPRINTFN(0, "getting device descriptor " + "at addr %d failed, %s\n", udev->address, + usbd_errstr(err)); + return (err); + } + break; + default: + DPRINTF("Minimum MaxPacketSize is large enough " + "to hold the complete device descriptor\n"); + break; + } + + /* get the full device descriptor */ + err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); + + /* try one more time, if error */ + if (err) + err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); + + if (err) { + DPRINTF("addr=%d, getting full desc failed\n", + udev->address); + return (err); + } + + DPRINTF("adding unit addr=%d, rev=%02x, class=%d, " + "subclass=%d, protocol=%d, maxpacket=%d, len=%d, speed=%d\n", + udev->address, UGETW(udev->ddesc.bcdUSB), + udev->ddesc.bDeviceClass, + udev->ddesc.bDeviceSubClass, + udev->ddesc.bDeviceProtocol, + udev->ddesc.bMaxPacketSize, + udev->ddesc.bLength, + udev->speed); + + return (err); +} + /*------------------------------------------------------------------------* * usbd_req_re_enumerate * @@ -1671,6 +1846,7 @@ retry: old_addr, usbd_errstr(err)); goto done; } + /* * After that the port has been reset our device should be at * address zero: @@ -1680,6 +1856,9 @@ retry: /* reset "bMaxPacketSize" */ udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; + /* reset USB state */ + usb_set_device_state(udev, USB_STATE_POWERED); + /* * Restore device address: */ @@ -1689,29 +1868,16 @@ retry: DPRINTFN(0, "addr=%d, set address failed! (%s, ignored)\n", old_addr, usbd_errstr(err)); } - /* restore device address */ - udev->address = old_addr; + /* + * Restore device address, if the controller driver did not + * set a new one: + */ + if (udev->address == USB_START_ADDR) + udev->address = old_addr; - /* allow device time to set new address */ - usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_SET_ADDRESS_SETTLE)); + /* setup the device descriptor and the initial "wMaxPacketSize" */ + err = usbd_setup_device_desc(udev, mtx); - /* get the device descriptor */ - err = usbd_req_get_desc(udev, mtx, NULL, &udev->ddesc, - USB_MAX_IPACKET, USB_MAX_IPACKET, 0, UDESC_DEVICE, 0, 0); - if (err) { - DPRINTFN(0, "getting device descriptor " - "at addr %d failed, %s\n", udev->address, - usbd_errstr(err)); - goto done; - } - /* get the full device descriptor */ - err = usbd_req_get_device_desc(udev, mtx, &udev->ddesc); - if (err) { - DPRINTFN(0, "addr=%d, getting device " - "descriptor failed, %s\n", old_addr, - usbd_errstr(err)); - goto done; - } done: if (err && do_retry) { /* give the USB firmware some time to load */ @@ -1722,7 +1888,11 @@ done: goto retry; } /* restore address */ - udev->address = old_addr; + if (udev->address == USB_START_ADDR) + udev->address = old_addr; + /* update state, if successful */ + if (err == 0) + usb_set_device_state(udev, USB_STATE_ADDRESSED); return (err); } diff --git a/sys/dev/usb/usb_request.h b/sys/dev/usb/usb_request.h index 21585651c19..1ce8b563b88 100644 --- a/sys/dev/usb/usb_request.h +++ b/sys/dev/usb/usb_request.h @@ -56,6 +56,9 @@ usb_error_t usbd_req_get_device_status(struct usb_device *udev, usb_error_t usbd_req_get_hub_descriptor(struct usb_device *udev, struct mtx *mtx, struct usb_hub_descriptor *hd, uint8_t nports); +usb_error_t usbd_req_get_ss_hub_descriptor(struct usb_device *udev, + struct mtx *mtx, struct usb_hub_ss_descriptor *hd, + uint8_t nports); usb_error_t usbd_req_get_hub_status(struct usb_device *udev, struct mtx *mtx, struct usb_hub_status *st); usb_error_t usbd_req_get_port_status(struct usb_device *udev, struct mtx *mtx, @@ -68,8 +71,17 @@ usb_error_t usbd_req_set_hub_feature(struct usb_device *udev, struct mtx *mtx, uint16_t sel); usb_error_t usbd_req_set_port_feature(struct usb_device *udev, struct mtx *mtx, uint8_t port, uint16_t sel); +usb_error_t usbd_setup_device_desc(struct usb_device *udev, struct mtx *mtx); usb_error_t usbd_req_re_enumerate(struct usb_device *udev, struct mtx *mtx); -usb_error_t usbd_req_clear_device_feature(struct usb_device *udev, struct mtx *mtx, uint16_t sel); -usb_error_t usbd_req_set_device_feature(struct usb_device *udev, struct mtx *mtx, uint16_t sel); +usb_error_t usbd_req_clear_device_feature(struct usb_device *udev, + struct mtx *mtx, uint16_t sel); +usb_error_t usbd_req_set_device_feature(struct usb_device *udev, + struct mtx *mtx, uint16_t sel); +usb_error_t usbd_req_set_hub_u1_timeout(struct usb_device *udev, + struct mtx *mtx, uint8_t port, uint8_t timeout); +usb_error_t usbd_req_set_hub_u2_timeout(struct usb_device *udev, + struct mtx *mtx, uint8_t port, uint8_t timeout); +usb_error_t usbd_req_set_hub_depth(struct usb_device *udev, + struct mtx *mtx, uint16_t depth); #endif /* _USB_REQUEST_H_ */ diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index e9bd64eafc3..e0f5a3bc7cd 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -109,7 +109,6 @@ static int usbd_setup_ctrl_transfer(struct usb_xfer *); static void usb_callback_proc(struct usb_proc_msg *); static void usbd_callback_ss_done_defer(struct usb_xfer *); static void usbd_callback_wrapper(struct usb_xfer_queue *); -static void usb_dma_delay_done_cb(void *); static void usbd_transfer_start_cb(void *); static uint8_t usbd_callback_wrapper_sub(struct usb_xfer *); static void usbd_get_std_packet_size(struct usb_std_packet_size *ptr, @@ -137,14 +136,10 @@ static void usbd_update_max_frame_size(struct usb_xfer *xfer) { /* compute maximum frame size */ + /* this computation should not overflow 16-bit */ + /* max = 15 * 1024 */ - if (xfer->max_packet_count == 2) { - xfer->max_frame_size = 2 * xfer->max_packet_size; - } else if (xfer->max_packet_count == 3) { - xfer->max_frame_size = 3 * xfer->max_packet_size; - } else { - xfer->max_frame_size = xfer->max_packet_size; - } + xfer->max_frame_size = xfer->max_packet_size * xfer->max_packet_count; } /*------------------------------------------------------------------------* @@ -158,12 +153,16 @@ usbd_update_max_frame_size(struct usb_xfer *xfer) * Else: milliseconds of DMA delay *------------------------------------------------------------------------*/ usb_timeout_t -usbd_get_dma_delay(struct usb_bus *bus) +usbd_get_dma_delay(struct usb_device *udev) { - uint32_t temp = 0; + struct usb_bus_methods *mtod; + uint32_t temp; - if (bus->methods->get_dma_delay) { - (bus->methods->get_dma_delay) (bus, &temp); + mtod = udev->bus->methods; + temp = 0; + + if (mtod->get_dma_delay) { + (mtod->get_dma_delay) (udev, &temp); /* * Round up and convert to milliseconds. Note that we use * 1024 milliseconds per second. to save a division. @@ -316,6 +315,7 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) }; struct usb_xfer *xfer = parm->curr_xfer; const struct usb_config *setup = parm->curr_setup; + struct usb_endpoint_ss_comp_descriptor *ecomp; struct usb_endpoint_descriptor *edesc; struct usb_std_packet_size std_size; usb_frcount_t n_frlengths; @@ -335,6 +335,7 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) goto done; } edesc = xfer->endpoint->edesc; + ecomp = xfer->endpoint->ecomp; type = (edesc->bmAttributes & UE_XFERTYPE); @@ -351,9 +352,54 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) parm->bufsize = setup->bufsize; - if (parm->speed == USB_SPEED_HIGH) { - xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3; + switch (parm->speed) { + case USB_SPEED_HIGH: + switch (type) { + case UE_ISOCHRONOUS: + case UE_INTERRUPT: + xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3; + + /* check for invalid max packet count */ + if (xfer->max_packet_count > 3) + xfer->max_packet_count = 3; + break; + default: + break; + } xfer->max_packet_size &= 0x7FF; + break; + case USB_SPEED_SUPER: + xfer->max_packet_count += (xfer->max_packet_size >> 11) & 3; + + if (ecomp != NULL) + xfer->max_packet_count += ecomp->bMaxBurst; + + if ((xfer->max_packet_count == 0) || + (xfer->max_packet_count > 16)) + xfer->max_packet_count = 16; + + switch (type) { + case UE_CONTROL: + xfer->max_packet_count = 1; + break; + case UE_ISOCHRONOUS: + if (ecomp != NULL) { + uint8_t mult; + + mult = (ecomp->bmAttributes & 3) + 1; + if (mult > 3) + mult = 3; + + xfer->max_packet_count *= mult; + } + break; + default: + break; + } + xfer->max_packet_size &= 0x7FF; + break; + default: + break; } /* range check "max_packet_count" */ @@ -446,41 +492,57 @@ usbd_transfer_setup_sub(struct usb_setup_params *parm) } else { /* - * if a value is specified use that else check the endpoint - * descriptor + * If a value is specified use that else check the + * endpoint descriptor! */ - if (xfer->interval == 0) { + if (type == UE_INTERRUPT) { - if (type == UE_INTERRUPT) { + uint32_t temp; + + if (xfer->interval == 0) { xfer->interval = edesc->bInterval; switch (parm->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_VARIABLE: + case USB_SPEED_LOW: + case USB_SPEED_FULL: + break; + default: /* 125us -> 1ms */ if (xfer->interval < 4) xfer->interval = 1; else if (xfer->interval > 16) - xfer->interval = (1<<(16-4)); + xfer->interval = (1 << (16 - 4)); else xfer->interval = - (1 << (xfer->interval-4)); - break; - case USB_SPEED_HIGH: - /* 125us -> 1ms */ - xfer->interval /= 8; - break; - default: + (1 << (xfer->interval - 4)); break; } - if (xfer->interval == 0) { - /* - * One millisecond is the smallest - * interval we support: - */ - xfer->interval = 1; - } + } + + if (xfer->interval == 0) { + /* + * One millisecond is the smallest + * interval we support: + */ + xfer->interval = 1; + } + + xfer->fps_shift = 0; + temp = 1; + + while ((temp != 0) && (temp < xfer->interval)) { + xfer->fps_shift++; + temp *= 2; + } + + switch (parm->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + break; + default: + xfer->fps_shift += 3; + break; } } } @@ -1094,9 +1156,11 @@ usbd_transfer_unsetup_sub(struct usb_xfer_root *info, uint8_t needs_delay) if (needs_delay) { usb_timeout_t temp; - temp = usbd_get_dma_delay(info->bus); - usb_pause_mtx(&info->bus->bus_mtx, - USB_MS_TO_TICKS(temp)); + temp = usbd_get_dma_delay(info->udev); + if (temp != 0) { + usb_pause_mtx(&info->bus->bus_mtx, + USB_MS_TO_TICKS(temp)); + } } /* make sure that our done messages are not queued anywhere */ @@ -2179,11 +2243,9 @@ done: * transfer. This code path is ususally only used when there is an USB * error like USB_ERR_CANCELLED. *------------------------------------------------------------------------*/ -static void -usb_dma_delay_done_cb(void *arg) +void +usb_dma_delay_done_cb(struct usb_xfer *xfer) { - struct usb_xfer *xfer = arg; - USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); DPRINTFN(3, "Completed %p\n", xfer); @@ -2549,14 +2611,17 @@ static uint8_t usbd_callback_wrapper_sub(struct usb_xfer *xfer) { struct usb_endpoint *ep; + struct usb_bus *bus; usb_frcount_t x; + bus = xfer->xroot->bus; + if ((!xfer->flags_int.open) && (!xfer->flags_int.did_close)) { DPRINTF("close\n"); - USB_BUS_LOCK(xfer->xroot->bus); + USB_BUS_LOCK(bus); (xfer->endpoint->methods->close) (xfer); - USB_BUS_UNLOCK(xfer->xroot->bus); + USB_BUS_UNLOCK(bus); /* only close once */ xfer->flags_int.did_close = 1; return (1); /* wait for new callback */ @@ -2565,9 +2630,10 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer) * If we have a non-hardware induced error we * need to do the DMA delay! */ - if (((xfer->error == USB_ERR_CANCELLED) || - (xfer->error == USB_ERR_TIMEOUT)) && - (!xfer->flags_int.did_dma_delay)) { + if (xfer->error != 0 && !xfer->flags_int.did_dma_delay && + (xfer->error == USB_ERR_CANCELLED || + xfer->error == USB_ERR_TIMEOUT || + bus->methods->start_dma_delay != NULL)) { usb_timeout_t temp; @@ -2577,16 +2643,26 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer) /* we can not cancel this delay */ xfer->flags_int.can_cancel_immed = 0; - temp = usbd_get_dma_delay(xfer->xroot->bus); + temp = usbd_get_dma_delay(xfer->xroot->udev); DPRINTFN(3, "DMA delay, %u ms, " "on %p\n", temp, xfer); if (temp != 0) { - USB_BUS_LOCK(xfer->xroot->bus); - usbd_transfer_timeout_ms(xfer, - &usb_dma_delay_done_cb, temp); - USB_BUS_UNLOCK(xfer->xroot->bus); + USB_BUS_LOCK(bus); + /* + * Some hardware solutions have dedicated + * events when it is safe to free DMA'ed + * memory. For the other hardware platforms we + * use a static delay. + */ + if (bus->methods->start_dma_delay != NULL) { + (bus->methods->start_dma_delay) (xfer); + } else { + usbd_transfer_timeout_ms(xfer, + (void *)&usb_dma_delay_done_cb, temp); + } + USB_BUS_UNLOCK(bus); return (1); /* wait for new callback */ } } @@ -2678,7 +2754,7 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer) * If the current USB transfer is completing we need to start the * next one: */ - USB_BUS_LOCK(xfer->xroot->bus); + USB_BUS_LOCK(bus); if (ep->endpoint_q.curr == xfer) { usb_command_wrapper(&ep->endpoint_q, NULL); @@ -2690,7 +2766,7 @@ usbd_callback_wrapper_sub(struct usb_xfer *xfer) xfer->endpoint->is_synced = 0; } } - USB_BUS_UNLOCK(xfer->xroot->bus); + USB_BUS_UNLOCK(bus); done: return (0); } @@ -2836,12 +2912,34 @@ repeat: * data toggle. *------------------------------------------------------------------------*/ void +usbd_clear_stall_locked(struct usb_device *udev, struct usb_endpoint *ep) +{ + USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); + + /* check that we have a valid case */ + if (udev->flags.usb_mode == USB_MODE_HOST && + udev->parent_hub != NULL && + udev->bus->methods->clear_stall != NULL && + ep->methods != NULL) { + (udev->bus->methods->clear_stall) (udev, ep); + } +} + +/*------------------------------------------------------------------------* + * usbd_clear_data_toggle - factored out code + * + * NOTE: the intention of this function is not to reset the hardware + * data toggle on the USB device side. + *------------------------------------------------------------------------*/ +void usbd_clear_data_toggle(struct usb_device *udev, struct usb_endpoint *ep) { DPRINTFN(5, "udev=%p endpoint=%p\n", udev, ep); USB_BUS_LOCK(udev->bus); ep->toggle_next = 0; + /* some hardware needs a callback to clear the data toggle */ + usbd_clear_stall_locked(udev, ep); USB_BUS_UNLOCK(udev->bus); } diff --git a/sys/dev/usb/usb_transfer.h b/sys/dev/usb/usb_transfer.h index 6e08df09ef8..71157ca7115 100644 --- a/sys/dev/usb/usb_transfer.h +++ b/sys/dev/usb/usb_transfer.h @@ -101,7 +101,7 @@ struct usb_setup_params { usb_frlength_t bufsize; usb_frlength_t bufsize_max; - uint16_t hc_max_frame_size; + uint32_t hc_max_frame_size; uint16_t hc_max_packet_size; uint8_t hc_max_packet_count; enum usb_dev_speed speed; @@ -114,6 +114,7 @@ struct usb_setup_params { uint8_t usbd_transfer_setup_sub_malloc(struct usb_setup_params *parm, struct usb_page_cache **ppc, usb_size_t size, usb_size_t align, usb_size_t count); +void usb_dma_delay_done_cb(struct usb_xfer *); void usb_command_wrapper(struct usb_xfer_queue *pq, struct usb_xfer *xfer); void usbd_pipe_enter(struct usb_xfer *xfer); @@ -124,6 +125,8 @@ void usbd_transfer_enqueue(struct usb_xfer_queue *pq, struct usb_xfer *xfer); void usbd_transfer_setup_sub(struct usb_setup_params *parm); void usbd_ctrl_transfer_setup(struct usb_device *udev); +void usbd_clear_stall_locked(struct usb_device *udev, + struct usb_endpoint *ep); void usbd_clear_data_toggle(struct usb_device *udev, struct usb_endpoint *ep); usb_callback_t usbd_do_request_callback; @@ -131,7 +134,7 @@ usb_callback_t usb_handle_request_callback; usb_callback_t usb_do_clear_stall_callback; void usbd_transfer_timeout_ms(struct usb_xfer *xfer, void (*cb) (void *arg), usb_timeout_t ms); -usb_timeout_t usbd_get_dma_delay(struct usb_bus *bus); +usb_timeout_t usbd_get_dma_delay(struct usb_device *udev); void usbd_transfer_power_ref(struct usb_xfer *xfer, int val); #endif /* _USB_TRANSFER_H_ */ diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index aaca4e5289c..be0cd7a5378 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -58,7 +58,7 @@ $FreeBSD$ vendor UNKNOWN1 0x0053 Unknown vendor vendor UNKNOWN2 0x0105 Unknown vendor vendor EGALAX2 0x0123 eGalax, Inc. -vendor UNKNOWN4 0x0204 Unknown vendor +vendor CHIPSBANK 0x0204 Chipsbank Microelectronics Co. vendor HUMAX 0x02ad HUMAX vendor LTS 0x0386 LTS vendor BWCT 0x03da Bernd Walter Computer Technology @@ -403,7 +403,7 @@ vendor ARASAN 0x07da Arasan Chip Systems vendor ALLIEDCABLE 0x07e6 Allied Cable vendor STSN 0x07ef STSN vendor CENTURY 0x07f7 Century Corp -vendor UNKNOWN5 0x07ff Unknown +vendor NEWLINK 0x07ff NEWlink vendor ZOOM 0x0803 Zoom Telephonics vendor PCS 0x0810 Personal Communication Systems vendor ALPHASMART 0x081e AlphaSmart, Inc. @@ -488,7 +488,7 @@ vendor GEOCAST 0x0a79 Geocast Network Systems vendor IDQUANTIQUE 0x0aba id Quantique vendor ZYDAS 0x0ace Zydas Technology Corporation vendor NEODIO 0x0aec Neodio -vendor OPTION 0x0af0 Option N.V: +vendor OPTION 0x0af0 Option N.V. vendor ASUS 0x0b05 ASUSTeK Computer vendor TODOS 0x0b0c Todos Data System vendor SIIG2 0x0b39 SIIG @@ -651,18 +651,21 @@ vendor METAGEEK 0x1781 MetaGeek vendor WAVESENSE 0x17f4 WaveSense vendor VAISALA 0x1843 Vaisala vendor AMIT 0x18c5 AMIT +vendor GOOGLE 0x18d1 Google vendor QCOM 0x18e8 Qcom vendor ELV 0x18ef ELV vendor LINKSYS3 0x1915 Linksys vendor QUALCOMMINC 0x19d2 Qualcomm, Incorporated vendor WCH2 0x1a86 QinHeng Electronics vendor STELERA 0x1a8d Stelera Wireless +vendor MATRIXORBITAL 0x1b3d Matrix Orbital vendor OVISLINK 0x1b75 OvisLink vendor TCTMOBILE 0x1bbb TCT Mobile vendor TELIT 0x1bc7 Telit vendor LONGCHEER 0x1c9e Longcheer Holdings, Ltd. vendor MPMAN 0x1cae MpMan vendor DRESDENELEKTRONIK 0x1cf1 dresden elektronik +vendor NEOTEL 0x1d09 Neotel vendor PEGATRON 0x1d4d Pegatron vendor QISDA 0x1da5 Qisda vendor METAGEEK2 0x1dd5 MetaGeek @@ -1292,6 +1295,10 @@ product CREATIVE3 OPTICAL_MOUSE 0x0001 Notebook Optical Mouse product CSR BT_DONGLE 0x0001 Bluetooth USB dongle product CSR CSRDFU 0xffff USB Bluetooth Device in DFU State +/* Chipsbank Microelectronics Co., Ltd */ +product CHIPSBANK USBMEMSTICK 0x6025 CBM2080 Flash drive controller +product CHIPSBANK USBMEMSTICK1 0x6026 CBM1180 Flash drive controller + /* CTX products */ product CTX EX1300 0x9999 Ex1300 hub @@ -1401,6 +1408,7 @@ product DLINK DSB650TX_PNA 0x4003 1/10/100 Ethernet product DLINK DSB650TX3 0x400b 10/100 Ethernet product DLINK DSB650TX2 0x4102 10/100 Ethernet product DLINK DSB650 0xabc1 10/100 Ethernet +product DLINK DUBH7 0xf103 DUB-H7 USB 2.0 7-Port Hub product DLINK2 DWA120 0x3a0c DWA-120 product DLINK2 DWA120_NF 0x3a0d DWA-120 (no firmware) product DLINK2 DWLG122C1 0x3c03 DWL-G122 c1 @@ -1444,7 +1452,7 @@ product EDIMAX EW7718 0x7718 EW-7718 /* eGalax Products */ product EGALAX TPANEL 0x0001 Touch Panel product EGALAX TPANEL2 0x0002 Touch Panel -product EGALAX2 TPANEL 0x0001 Touch Panel +product EGALAX2 TPANEL 0x0001 Touch Panel /* Eicon Networks */ product EICON DIVA852 0x4905 Diva 852 ISDN TA @@ -1583,7 +1591,8 @@ product FTDI UOPTBR 0xe889 USB-RS232 OptoBridge product FTDI EMCU2D 0xe88a Expert mouseCLOCK USB II product FTDI PCMSFU 0xe88b Precision Clock MSF USB product FTDI EMCU2H 0xe88c Expert mouseCLOCK USB II HBG -product FTDI MAXSTREAM 0xee18 Maxstream PKG-U +product FTDI MAXSTREAM 0xee18 Maxstream PKG-U +product FTDI USB_UIRT 0xf850 USB-UIRT product FTDI USBSERIAL 0xfa00 Matrix Orbital USB Serial product FTDI MX2_3 0xfa01 Matrix Orbital MX2 or MX3 product FTDI MX4_5 0xfa02 Matrix Orbital MX4 or MX5 @@ -1619,7 +1628,8 @@ product GENERALINSTMNTS SB5100 0x5100 SURFboard SB5100 Cable modem /* Genesys Logic products */ product GENESYS GL620USB 0x0501 GL620USB Host-Host interface -product GENESYS GL650 0x0604 GL650 Hub +product GENESYS GL650 0x0604 GL650 HUB +product GENESYS GL606 0x0606 USB 2.0 HUB product GENESYS GL641USB 0x0700 GL641USB CompactFlash Card Reader product GENESYS GL641USB2IDE_2 0x0701 GL641USB USB-IDE Bridge No 2 product GENESYS GL641USB2IDE 0x0702 GL641USB USB-IDE Bridge @@ -1666,6 +1676,9 @@ product GOHUBS GOCOM232 0x1001 GoCOM232 Serial product GOODWAY GWUSB2E 0x6200 GWUSB2E product GOODWAY RT2573 0xc019 RT2573 +/* Google products */ +product GOOGLE NEXUSONE 0x4e11 Nexus One + /* Gravis products */ product GRAVIS GAMEPADPRO 0x4001 GamePad Pro @@ -1842,6 +1855,7 @@ product HUAWEI E143D 0x143d 3G modem product HUAWEI E143E 0x143e 3G modem product HUAWEI E143F 0x143f 3G modem product HUAWEI E1752 0x1446 3G modem +product HUAWEI K3765 0x1465 3G modem product HUAWEI E14AC 0x14ac 3G modem /* HUAWEI 3com products */ @@ -1900,6 +1914,9 @@ product IODATA2 USB2SC 0x0a09 USB2.0-SCSI Bridge USB2-SC product IOMEGA ZIP100 0x0001 Zip 100 product IOMEGA ZIP250 0x0030 Zip 250 +/* Integrated System Solution Corp. products */ +product ISSC ISSCBTA 0x1001 Bluetooth USB Adapter + /* iTegno products */ product ITEGNO WM1080A 0x1080 WM1080A GSM/GPRS modem product ITEGNO WM2080A 0x2080 WM2080A CDMA modem @@ -2063,6 +2080,7 @@ product LOGITECH QUICKCAMPRO2 0xd001 QuickCam Pro /* Logitec Corp. products */ product LOGITEC LDR_H443SU2 0x0033 DVD Multi-plus unit LDR-H443SU2 product LOGITEC LDR_H443U2 0x00b3 DVD Multi-plus unit LDR-H443U2 +product LOGITEC LAN_GTJU2A 0x0160 LAN-GTJ/U2A Ethernet product LOGITEC RT2870_1 0x0162 RT2870 product LOGITEC RT2870_2 0x0163 RT2870 product LOGITEC RT2870_3 0x0164 RT2870 @@ -2081,6 +2099,9 @@ product MACALLY MOUSE1 0x0101 mouse /* Marvell Technology Group, Ltd. products */ product MARVELL SHEEVAPLUG 0x9e8f SheevaPlug serial interface + +/* Matrix Orbital products */ +product MATRIXORBITAL MOUA 0x0153 Martrix Orbital MOU-Axxxx LCD displays /* MCT Corp. */ product MCT HUB0100 0x0100 Hub @@ -2096,11 +2117,12 @@ product MELCO LUATX1 0x0001 LUA-TX Ethernet product MELCO LUATX5 0x0005 LUA-TX Ethernet product MELCO LUA2TX5 0x0009 LUA2-TX Ethernet product MELCO LUAKTX 0x0012 LUA-KTX Ethernet -product MELCO DUBPXXG 0x001c USB-IDE Bridge: DUB-PxxG +product MELCO DUBPXXG 0x001c DUB-PxxG product MELCO LUAU2KTX 0x003d LUA-U2-KTX Ethernet product MELCO KG54YB 0x005e WLI-U2-KG54-YB WLAN product MELCO KG54 0x0066 WLI-U2-KG54 WLAN product MELCO KG54AI 0x0067 WLI-U2-KG54-AI WLAN +product MELCO LUA3U2AGT 0x006e LUA3-U2-AGT product MELCO NINWIFI 0x008b Nintendo Wi-Fi product MELCO PCOPRS1 0x00b3 PC-OP-RS1 RemoteStation product MELCO SG54HP 0x00d8 WLI-U2-SG54HP @@ -2108,6 +2130,8 @@ product MELCO G54HP 0x00d9 WLI-U2-G54HP product MELCO KG54L 0x00da WLI-U2-KG54L product MELCO WLIUCG300N 0x00e8 WLI-UC-G300N product MELCO SG54HG 0x00f4 WLI-U2-SG54HG +product MELCO WLRUCG 0x0116 WLR-UC-G +product MELCO WLRUCGAOSS 0x0119 WLR-UC-G-AOSS product MELCO WLIUCAG300N 0x012e WLI-UC-AG300N product MELCO RT2870_1 0x0148 RT2870 product MELCO RT2870_2 0x0150 RT2870 @@ -2259,6 +2283,7 @@ product MSYSTEMS DISKONKEY2 0x0011 DiskOnKey /* Myson products */ product MYSON HEDEN_8813 0x8813 USB-IDE product MYSON HEDEN 0x8818 USB-IDE +product MYSON HUBREADER 0x8819 COMBO Card reader with USB HUB product MYSON STARREADER 0x9920 USB flash card adapter /* National Semiconductor */ @@ -2275,6 +2300,9 @@ product NEC HUB_B 0x55ab hub product NEODIO ND3260 0x3260 8-in-1 Multi-format Flash Controller product NEODIO ND5010 0x5010 Multi-format Flash Controller +/* Neotel products */ +product NEOTEL PRIME 0x4000 Prime USB modem + /* Netac products */ product NETAC CF_CARD 0x1060 USB-CF-Card product NETAC ONLYDISK 0x0003 OnlyDisk @@ -2305,6 +2333,9 @@ product NETGEAR3 WPN111_2 0x5f02 WPN111 /* NetIndex products */ product NETINDEX WS002IN 0x2001 Willcom WS002IN +/* NEWlink */ +product NEWLINK USB2IDEBRIDGE 0x00ff USB 2.0 Hard Drive Enclosure + /* Nikon products */ product NIKON E990 0x0102 Digital Camera E990 product NIKON LS40 0x4000 CoolScan LS40 ED @@ -2456,7 +2487,7 @@ product PANASONIC TYTP50P6S 0x3900 TY-TP50P6-S 50in Touch Panel /* PARA Industrial products */ product PARA RT3070 0x8888 RT3070 - + /* Pegatron products */ product PEGATRON RT2870 0x0002 RT2870 product PEGATRON RT3070 0x000c RT3070 @@ -2655,6 +2686,7 @@ product QUALCOMMINC E0076 0x0076 3G modem product QUALCOMMINC E0078 0x0078 3G modem product QUALCOMMINC E0082 0x0082 3G modem product QUALCOMMINC E0086 0x0086 3G modem +product QUALCOMMINC E2000 0x2000 3G modem product QUALCOMMINC E2002 0x2002 3G modem product QUALCOMMINC E2003 0x2003 3G modem @@ -2667,7 +2699,7 @@ product QUANTA Q111 0xea03 HSDPA modem product QUANTA GLX 0xea04 HSDPA modem product QUANTA GKE 0xea05 HSDPA modem product QUANTA GLE 0xea06 HSDPA modem -product QUANTA RW6815_2 0xf003 HP iPAQ rw6815 +product QUANTA RW6815R 0xf003 HP iPAQ rw6815 RNDIS /* Qtronix products */ product QTRONIX 980N 0x2011 Scorpion-980N keyboard @@ -2704,6 +2736,7 @@ product RATOC REXUSB60F 0xb020 USB serial adapter REX-USB60F /* ReakTek products */ /* Green House and CompUSA OEM this part */ +product REALTEK USB20CRW 0x0158 USB20CRW Card Reader product REALTEK USBKR100 0x8150 USBKR100 USB Ethernet product REALTEK RTL8187 0x8187 RTL8187 Wireless Adapter product REALTEK RTL8187B_0 0x8189 RTL8187B Wireless Adapter @@ -2742,7 +2775,7 @@ product SAGEM XG76NA 0x0062 XG-76NA product SAMSUNG ML6060 0x3008 ML-6060 laser printer product SAMSUNG YP_U2 0x5050 YP-U2 MP3 Player product SAMSUNG YP_U4 0x5092 YP-U4 MP3 Player -product SAMSUNG I500 0x6601 I500 Palm USB Phone +product SAMSUNG I500 0x6601 I500 Palm USB Phone product SAMSUNG I330 0x8001 I330 phone cradle product SAMSUNG2 RT2870_1 0x2018 RT2870 @@ -3146,6 +3179,7 @@ product TAUGA CAMERAMATE 0x0005 CameraMate (DPCM_USB) /* TCTMobile products */ product TCTMOBILE X060S 0x0000 X060S 3G modem +product TCTMOBILE X080S 0xf000 X080S 3G modem /* TDK products */ product TDK UPA9664 0x0115 USB-PDC Adapter UPA9664 @@ -3236,9 +3270,6 @@ product UMEDIA AR5523_2_NF 0x3206 AR5523 (no firmware) /* Universal Access products */ product UNIACCESS PANACHE 0x0101 Panache Surf USB ISDN Adapter -/* Unknown vendors */ -product UNKNOWN4 USBMEMSTICK 0x6025 Flash Disk CBM - /* Unknown vendors */ product UNKNOWN5 USB2IDEBRIDGE 0x00ff USB 2.0 ATA/SATA Bridge @@ -3371,7 +3402,7 @@ product ZOOM 2986L 0x9700 2986L Fax modem product ZORAN EX20DSC 0x4343 Digital Camera EX-20 DSC /* Zydas Technology Corporation products */ -product ZYDAS ZD1211 0x1211 ZD1211 WLAN abg +product ZYDAS ZD1211 0x1211 ZD1211 WLAN abg product ZYDAS ZD1211B 0x1215 ZD1211B /* ZyXEL Communication Co. products */ diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 9adf39adc77..1c2d412b9f5 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -135,6 +135,7 @@ struct usb_endpoint { struct usb_xfer_queue endpoint_q; /* queue of USB transfers */ struct usb_endpoint_descriptor *edesc; + struct usb_endpoint_ss_comp_descriptor *ecomp; struct usb_pipe_methods *methods; /* set by HC driver */ uint16_t isoc_next; @@ -479,6 +480,7 @@ void usbd_set_parent_iface(struct usb_device *udev, uint8_t iface_index, uint8_t usbd_get_bus_index(struct usb_device *udev); uint8_t usbd_get_device_index(struct usb_device *udev); void usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode); +uint8_t usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode); uint8_t usbd_device_attached(struct usb_device *udev); void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, diff --git a/sys/dev/usb/usbdi_util.h b/sys/dev/usb/usbdi_util.h index bb6e324ab97..1e450f8f4ff 100644 --- a/sys/dev/usb/usbdi_util.h +++ b/sys/dev/usb/usbdi_util.h @@ -51,6 +51,9 @@ struct usb_interface_descriptor *usb_idesc_foreach( struct usb_endpoint_descriptor *usb_edesc_foreach( struct usb_config_descriptor *cd, struct usb_endpoint_descriptor *ped); +struct usb_endpoint_ss_comp_descriptor *usb_ed_comp_foreach( + struct usb_config_descriptor *cd, + struct usb_endpoint_ss_comp_descriptor *ped); uint8_t usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type); uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd, @@ -78,4 +81,11 @@ usb_error_t usbd_req_set_protocol(struct usb_device *udev, struct mtx *mtx, usb_error_t usbd_req_set_report(struct usb_device *udev, struct mtx *mtx, void *data, uint16_t len, uint8_t iface_index, uint8_t type, uint8_t id); + +/* The following functions will not return NULL strings. */ + +const char *usb_get_manufacturer(struct usb_device *); +const char *usb_get_product(struct usb_device *); +const char *usb_get_serial(struct usb_device *); + #endif /* _USB_USBDI_UTIL_H_ */ diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index d8378f846f4..21961ce0d3c 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -118,6 +118,8 @@ static const struct usb_device_id rum_devs[] = { RUM_DEV(HUAWEI3COM, WUB320G), RUM_DEV(MELCO, G54HP), RUM_DEV(MELCO, SG54HP), + RUM_DEV(MELCO, WLRUCG), + RUM_DEV(MELCO, WLRUCGAOSS), RUM_DEV(MSI, RT2573_1), RUM_DEV(MSI, RT2573_2), RUM_DEV(MSI, RT2573_3), @@ -139,9 +141,6 @@ static const struct usb_device_id rum_devs[] = { #undef RUM_DEV }; -MODULE_DEPEND(rum, wlan, 1, 1, 1); -MODULE_DEPEND(rum, usb, 1, 1, 1); - static device_probe_t rum_match; static device_attach_t rum_attach; static device_detach_t rum_detach; @@ -722,7 +721,7 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; case IEEE80211_S_RUN: - ni = vap->iv_bss; + ni = ieee80211_ref_node(vap->iv_bss); if (vap->iv_opmode != IEEE80211_M_MONITOR) { rum_update_slot(ic->ic_ifp); @@ -746,6 +745,7 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) rum_ratectl_start(sc, ni); + ieee80211_free_node(ni); break; default: break; @@ -1821,8 +1821,12 @@ rum_update_promisc(struct ifnet *ifp) static void rum_update_mcast(struct ifnet *ifp) { + static int warning_printed; - /* XXX do nothing? */ + if (warning_printed == 0) { + if_printf(ifp, "need to implement %s\n", __func__); + warning_printed = 1; + } } static const char * @@ -2226,7 +2230,7 @@ rum_ratectl_task(void *arg, int pending) struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = ic->ic_ifp; struct rum_softc *sc = ifp->if_softc; - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; int ok, fail; int sum, retrycnt; @@ -2240,8 +2244,10 @@ rum_ratectl_task(void *arg, int pending) sum = ok+fail; retrycnt = (le32toh(sc->sta[5]) & 0xffff) + fail; + ni = ieee80211_ref_node(vap->iv_bss); ieee80211_ratectl_tx_update(vap, ni, &sum, &ok, &retrycnt); (void) ieee80211_ratectl_rate(ni, NULL, 0); + ieee80211_free_node(ni); ifp->if_oerrors += fail; /* count TX retry-fail as Tx errors */ @@ -2360,3 +2366,6 @@ static driver_t rum_driver = { static devclass_t rum_devclass; DRIVER_MODULE(rum, uhub, rum_driver, rum_devclass, NULL, 0); +MODULE_DEPEND(rum, wlan, 1, 1, 1); +MODULE_DEPEND(rum, usb, 1, 1, 1); +MODULE_VERSION(rum, 1); diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index c594f2148fd..d6cbf3ac609 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -294,10 +294,6 @@ static const struct usb_device_id run_devs[] = { #undef RUN_DEV }; -MODULE_DEPEND(run, wlan, 1, 1, 1); -MODULE_DEPEND(run, usb, 1, 1, 1); -MODULE_DEPEND(run, firmware, 1, 1, 1); - static device_probe_t run_match; static device_attach_t run_attach; static device_detach_t run_detach; @@ -1697,7 +1693,6 @@ run_media_change(struct ifnet *ifp) struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_txparam *tp; struct run_softc *sc = ic->ic_ifp->if_softc; - struct run_node *rn = (void *)vap->iv_bss; uint8_t rate, ridx; int error; @@ -1711,13 +1706,19 @@ run_media_change(struct ifnet *ifp) tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { + struct ieee80211_node *ni; + struct run_node *rn; + rate = ic->ic_sup_rates[ic->ic_curmode]. rs_rates[tp->ucastrate] & IEEE80211_RATE_VAL; for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) if (rt2860_rates[ridx].rate == rate) break; + ni = ieee80211_ref_node(vap->iv_bss); + rn = (struct run_node *)ni; rn->fix_ridx = ridx; DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); + ieee80211_free_node(ni); } #if 0 @@ -1740,7 +1741,6 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct run_softc *sc = ic->ic_ifp->if_softc; struct run_vap *rvp = RUN_VAP(vap); enum ieee80211_state ostate; - struct ieee80211_node *ni; uint32_t sta[3]; uint32_t tmp; uint8_t ratectl; @@ -1785,7 +1785,6 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) case IEEE80211_S_RUN: - ni = vap->iv_bss; if (!(sc->runbmap & bid)) { if(sc->running++) restart_ratectl = 1; @@ -1821,12 +1820,16 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } if (vap->iv_opmode != IEEE80211_M_MONITOR) { + struct ieee80211_node *ni; + run_updateslot(ic->ic_ifp); run_enable_mrr(sc); run_set_txpreamble(sc); run_set_basicrates(sc); + ni = ieee80211_ref_node(vap->iv_bss); IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); run_set_bssid(sc, ni->ni_bssid); + ieee80211_free_node(ni); run_enable_tsf_sync(sc); /* enable automatic rate adaptation */ @@ -4871,3 +4874,7 @@ static driver_t run_driver = { static devclass_t run_devclass; DRIVER_MODULE(run, uhub, run_driver, run_devclass, NULL, 0); +MODULE_DEPEND(run, wlan, 1, 1, 1); +MODULE_DEPEND(run, usb, 1, 1, 1); +MODULE_DEPEND(run, firmware, 1, 1, 1); +MODULE_VERSION(run, 1); diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 40b7c83da10..35202a9b50f 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -1968,9 +1968,10 @@ uath_create_connection(struct uath_softc *sc, uint32_t connid) const struct ieee80211_rateset *rs; struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; struct uath_cmd_create_connection create; + ni = ieee80211_ref_node(vap->iv_bss); bzero(&create, sizeof create); create.connid = htobe32(connid); create.bssid = htobe32(0); @@ -1989,6 +1990,7 @@ uath_create_connection(struct uath_softc *sc, uint32_t connid) create.connattr.wlanmode = htobe32(WLAN_MODE_11g); else create.connattr.wlanmode = htobe32(WLAN_MODE_11b); + ieee80211_free_node(ni); return uath_cmd_write(sc, WDCMSG_CREATE_CONNECTION, &create, sizeof create, 0); @@ -2017,14 +2019,16 @@ uath_write_associd(struct uath_softc *sc) { struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; struct uath_cmd_set_associd associd; + ni = ieee80211_ref_node(vap->iv_bss); bzero(&associd, sizeof associd); associd.defaultrateix = htobe32(1); /* XXX */ associd.associd = htobe32(ni->ni_associd); associd.timoffset = htobe32(0x3b); /* XXX */ IEEE80211_ADDR_COPY(associd.bssid, ni->ni_bssid); + ieee80211_free_node(ni); return uath_cmd_write(sc, WDCMSG_WRITE_ASSOCID, &associd, sizeof associd, 0); } @@ -2065,7 +2069,7 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { enum ieee80211_state ostate = vap->iv_state; int error; - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; struct ieee80211com *ic = vap->iv_ic; struct uath_softc *sc = ic->ic_ifp->if_softc; struct uath_vap *uvp = UATH_VAP(vap); @@ -2078,6 +2082,7 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) UATH_LOCK(sc); callout_stop(&sc->stat_ch); callout_stop(&sc->watchdog_ch); + ni = ieee80211_ref_node(vap->iv_bss); switch (nstate) { case IEEE80211_S_INIT: @@ -2150,6 +2155,7 @@ uath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) default: break; } + ieee80211_free_node(ni); UATH_UNLOCK(sc); IEEE80211_LOCK(ic); return (uvp->newstate(vap, nstate, arg)); @@ -2892,3 +2898,4 @@ static devclass_t uath_devclass; DRIVER_MODULE(uath, uhub, uath_driver, uath_devclass, NULL, 0); MODULE_DEPEND(uath, wlan, 1, 1, 1); MODULE_DEPEND(uath, usb, 1, 1, 1); +MODULE_VERSION(uath, 1); diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c index 58d716201fc..d704cec1aa9 100644 --- a/sys/dev/usb/wlan/if_upgt.c +++ b/sys/dev/usb/wlan/if_upgt.c @@ -182,6 +182,7 @@ static const struct usb_device_id upgt_devs_2[] = { UPGT_DEV(FSC, E5400), UPGT_DEV(GLOBESPAN, PRISM_GT_1), UPGT_DEV(GLOBESPAN, PRISM_GT_2), + UPGT_DEV(NETGEAR, WG111V2_2), UPGT_DEV(INTERSIL, PRISM_GT), UPGT_DEV(SMC, 2862WG), UPGT_DEV(USR, USR5422), @@ -652,7 +653,7 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; struct upgt_data *data_cmd; struct upgt_lmac_mem *mem; struct upgt_lmac_filter *filter; @@ -707,6 +708,7 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) filter->unknown3 = htole16(UPGT_FILTER_UNKNOWN3); break; case IEEE80211_S_RUN: + ni = ieee80211_ref_node(vap->iv_bss); /* XXX monitor mode isn't tested yet. */ if (vap->iv_opmode == IEEE80211_M_MONITOR) { filter->type = htole16(UPGT_FILTER_TYPE_MONITOR); @@ -730,6 +732,7 @@ upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) filter->rxhw = htole32(sc->sc_eeprom_hwrx); filter->unknown3 = htole16(UPGT_FILTER_UNKNOWN3); } + ieee80211_free_node(ni); break; default: device_printf(sc->sc_dev, diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index c3e60cd59fb..aa2dcbd5769 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -400,6 +400,7 @@ static devclass_t ural_devclass; DRIVER_MODULE(ural, uhub, ural_driver, ural_devclass, NULL, 0); MODULE_DEPEND(ural, usb, 1, 1, 1); MODULE_DEPEND(ural, wlan, 1, 1, 1); +MODULE_VERSION(ural, 1); static int ural_match(device_t self) @@ -710,7 +711,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; case IEEE80211_S_RUN: - ni = vap->iv_bss; + ni = ieee80211_ref_node(vap->iv_bss); if (vap->iv_opmode != IEEE80211_M_MONITOR) { ural_update_slot(ic->ic_ifp); @@ -728,6 +729,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) "could not allocate beacon\n"); RAL_UNLOCK(sc); IEEE80211_LOCK(ic); + ieee80211_free_node(ni); return (-1); } ieee80211_ref_node(ni); @@ -736,6 +738,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) "could not send beacon\n"); RAL_UNLOCK(sc); IEEE80211_LOCK(ic); + ieee80211_free_node(ni); return (-1); } } @@ -753,7 +756,7 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) ural_ratectl_start(sc, ni); - + ieee80211_free_node(ni); break; default: @@ -2236,10 +2239,11 @@ ural_ratectl_task(void *arg, int pending) struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = ic->ic_ifp; struct ural_softc *sc = ifp->if_softc; - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_node *ni; int ok, fail; int sum, retrycnt; + ni = ieee80211_ref_node(vap->iv_bss); RAL_LOCK(sc); /* read and clear statistic registers (STA_CSR0 to STA_CSR10) */ ural_read_multi(sc, RAL_STA_CSR0, sc->sta, sizeof(sc->sta)); @@ -2257,6 +2261,7 @@ ural_ratectl_task(void *arg, int pending) usb_callout_reset(&uvp->ratectl_ch, hz, ural_ratectl_timeout, uvp); RAL_UNLOCK(sc); + ieee80211_free_node(ni); } static int diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c index 9ff16f3b137..3de2273bcb6 100644 --- a/sys/dev/usb/wlan/if_urtw.c +++ b/sys/dev/usb/wlan/if_urtw.c @@ -1830,10 +1830,10 @@ urtw_tx_start(struct urtw_softc *sc, struct ieee80211_node *ni, struct mbuf *m0, static int urtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct ieee80211_node *ni = vap->iv_bss; struct ieee80211com *ic = vap->iv_ic; struct urtw_softc *sc = ic->ic_ifp->if_softc; struct urtw_vap *uvp = URTW_VAP(vap); + struct ieee80211_node *ni; usb_error_t error = 0; DPRINTF(sc, URTW_DEBUG_STATE, "%s: %s -> %s\n", __func__, @@ -1854,6 +1854,7 @@ urtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) case IEEE80211_S_ASSOC: break; case IEEE80211_S_RUN: + ni = ieee80211_ref_node(vap->iv_bss); /* setting bssid. */ urtw_write32_m(sc, URTW_BSSID, ((uint32_t *)ni->ni_bssid)[0]); urtw_write16_m(sc, URTW_BSSID + 4, @@ -1868,6 +1869,7 @@ urtw_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (error != 0) device_printf(sc->sc_dev, "could not control LED (%d)\n", error); + ieee80211_free_node(ni); break; default: break; @@ -4441,3 +4443,4 @@ static devclass_t urtw_devclass; DRIVER_MODULE(urtw, uhub, urtw_driver, urtw_devclass, NULL, 0); MODULE_DEPEND(urtw, wlan, 1, 1, 1); MODULE_DEPEND(urtw, usb, 1, 1, 1); +MODULE_VERSION(urtw, 1); diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index 94ad559a50d..e8d7b7e06ea 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -572,7 +572,6 @@ zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct zyd_vap *zvp = ZYD_VAP(vap); struct ieee80211com *ic = vap->iv_ic; struct zyd_softc *sc = ic->ic_ifp->if_softc; - struct ieee80211_node *ni; int error; DPRINTF(sc, ZYD_DEBUG_STATE, "%s: %s -> %s\n", __func__, @@ -586,7 +585,6 @@ zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) zyd_set_chan(sc, ic->ic_curchan); break; case IEEE80211_S_RUN: - ni = vap->iv_bss; if (vap->iv_opmode == IEEE80211_M_MONITOR) break; @@ -598,7 +596,7 @@ zyd_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) /* make data LED blink upon Tx */ zyd_write32_m(sc, sc->sc_fwbase + ZYD_FW_LINK_STATUS, 1); - IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); + IEEE80211_ADDR_COPY(sc->sc_bssid, vap->iv_bss->ni_bssid); zyd_set_bssid(sc, sc->sc_bssid); break; default: @@ -2948,3 +2946,4 @@ static devclass_t zyd_devclass; DRIVER_MODULE(zyd, uhub, zyd_driver, zyd_devclass, NULL, 0); MODULE_DEPEND(zyd, usb, 1, 1, 1); MODULE_DEPEND(zyd, wlan, 1, 1, 1); +MODULE_VERSION(zyd, 1); diff --git a/sys/dev/vge/if_vge.c b/sys/dev/vge/if_vge.c index 127a123cc63..20a0df4b242 100644 --- a/sys/dev/vge/if_vge.c +++ b/sys/dev/vge/if_vge.c @@ -368,9 +368,6 @@ vge_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - if (phy != sc->vge_phyaddr) - return (0); - vge_miipoll_stop(sc); /* Specify the register we want to read. */ @@ -404,9 +401,6 @@ vge_miibus_writereg(device_t dev, int phy, int reg, int data) sc = device_get_softc(dev); - if (phy != sc->vge_phyaddr) - return (0); - vge_miipoll_stop(sc); /* Specify the register we want to write. */ @@ -1091,10 +1085,11 @@ vge_attach(device_t dev) } /* Do MII setup */ - if (mii_phy_probe(dev, &sc->vge_miibus, - vge_ifmedia_upd, vge_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->vge_miibus, ifp, vge_ifmedia_upd, + vge_ifmedia_sts, BMSR_DEFCAPMASK, sc->vge_phyaddr, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/vr/if_vr.c b/sys/dev/vr/if_vr.c index 954024d7f92..49555757b77 100644 --- a/sys/dev/vr/if_vr.c +++ b/sys/dev/vr/if_vr.c @@ -249,8 +249,6 @@ vr_miibus_readreg(device_t dev, int phy, int reg) int i; sc = device_get_softc(dev); - if (sc->vr_phyaddr != phy) - return (0); /* Set the register address. */ CSR_WRITE_1(sc, VR_MIIADDR, reg); @@ -274,8 +272,6 @@ vr_miibus_writereg(device_t dev, int phy, int reg, int data) int i; sc = device_get_softc(dev); - if (sc->vr_phyaddr != phy) - return (0); /* Set the register address and data to write. */ CSR_WRITE_1(sc, VR_MIIADDR, reg); @@ -613,7 +609,7 @@ vr_attach(device_t dev) struct vr_type *t; uint8_t eaddr[ETHER_ADDR_LEN]; int error, rid; - int i, pmc; + int i, phy, pmc; sc = device_get_softc(dev); sc->vr_dev = dev; @@ -780,17 +776,15 @@ vr_attach(device_t dev) goto fail; } - /* Save PHY address. */ - if (sc->vr_revid >= REV_ID_VT6105_A0) - sc->vr_phyaddr = 1; - else - sc->vr_phyaddr = CSR_READ_1(sc, VR_PHYADDR) & VR_PHYADDR_MASK; - /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->vr_miibus, - vr_ifmedia_upd, vr_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + if (sc->vr_revid >= REV_ID_VT6105_A0) + phy = 1; + else + phy = CSR_READ_1(sc, VR_PHYADDR) & VR_PHYADDR_MASK; + error = mii_attach(dev, &sc->vr_miibus, ifp, vr_ifmedia_upd, + vr_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1558,8 +1552,7 @@ vr_tick(void *xsc) if ((sc->vr_flags & VR_F_RESTART) != 0) { device_printf(sc->vr_dev, "restarting\n"); sc->vr_stat.num_restart++; - vr_stop(sc); - vr_reset(sc); + sc->vr_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; vr_init_locked(sc); sc->vr_flags &= ~VR_F_RESTART; } @@ -2016,6 +2009,9 @@ vr_init_locked(struct vr_softc *sc) ifp = sc->vr_ifp; mii = device_get_softc(sc->vr_miibus); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + /* Cancel pending I/O and free all RX/TX buffers. */ vr_stop(sc); vr_reset(sc); @@ -2287,6 +2283,7 @@ vr_watchdog(struct vr_softc *sc) if_printf(sc->vr_ifp, "watchdog timeout " "(missed link)\n"); ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; vr_init_locked(sc); return; } @@ -2294,8 +2291,7 @@ vr_watchdog(struct vr_softc *sc) ifp->if_oerrors++; if_printf(ifp, "watchdog timeout\n"); - vr_stop(sc); - vr_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; vr_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) diff --git a/sys/dev/vr/if_vrreg.h b/sys/dev/vr/if_vrreg.h index 9c85962916c..d686bddb240 100644 --- a/sys/dev/vr/if_vrreg.h +++ b/sys/dev/vr/if_vrreg.h @@ -722,7 +722,6 @@ struct vr_softc { uint8_t vr_revid; /* Rhine chip revision */ uint8_t vr_flags; /* See VR_F_* below */ #define VR_F_RESTART 0x01 /* Restart unit on next tick */ - int vr_phyaddr; int vr_if_flags; struct task vr_link_task; struct vr_chain_data vr_cdata; diff --git a/sys/dev/wb/if_wb.c b/sys/dev/wb/if_wb.c index cb4f3bb817f..1169cb79aa6 100644 --- a/sys/dev/wb/if_wb.c +++ b/sys/dev/wb/if_wb.c @@ -855,9 +855,10 @@ wb_attach(dev) /* * Do MII setup. */ - if (mii_phy_probe(dev, &sc->wb_miibus, - wb_ifmedia_upd, wb_ifmedia_sts)) { - error = ENXIO; + error = mii_attach(dev, &sc->wb_miibus, ifp, wb_ifmedia_upd, + wb_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/dev/xen/balloon/balloon.c b/sys/dev/xen/balloon/balloon.c index 6948173765a..eb55dfc7b4c 100644 --- a/sys/dev/xen/balloon/balloon.c +++ b/sys/dev/xen/balloon/balloon.c @@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include @@ -406,20 +406,20 @@ set_new_target(unsigned long target) wakeup(balloon_process); } -static struct xenbus_watch target_watch = +static struct xs_watch target_watch = { .node = "memory/target" }; /* React to a change in the target key */ static void -watch_target(struct xenbus_watch *watch, +watch_target(struct xs_watch *watch, const char **vec, unsigned int len) { unsigned long long new_target; int err; - err = xenbus_scanf(XBT_NIL, "memory", "target", NULL, + err = xs_scanf(XST_NIL, "memory", "target", NULL, "%llu", &new_target); if (err) { /* This is ok (for domain0 at least) - so just return */ @@ -438,7 +438,7 @@ balloon_init_watcher(void *arg) { int err; - err = register_xenbus_watch(&target_watch); + err = xs_register_watch(&target_watch); if (err) printf("Failed to set balloon watcher\n"); diff --git a/sys/dev/xen/blkback/blkback.c b/sys/dev/xen/blkback/blkback.c index 259f2f6c041..72087f5994c 100644 --- a/sys/dev/xen/blkback/blkback.c +++ b/sys/dev/xen/blkback/blkback.c @@ -1,1055 +1,1919 @@ -/* - * Copyright (c) 2006, Cisco Systems, Inc. +/*- + * Copyright (c) 2009-2010 Spectra Logic Corporation * All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * 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 + * substantially 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. * - * 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 Cisco Systems, Inc. nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 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. * - * 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + * Authors: Justin T. Gibbs (Spectra Logic Corporation) + * Ken Merry (Spectra Logic Corporation) */ - #include __FBSDID("$FreeBSD$"); +/** + * \file blkback.c + * + * \brief Device driver supporting the vending of block storage from + * a FreeBSD domain to other domains. + */ + #include #include -#include -#include #include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include #include -#include -#include -#include - -#include -#include -#include +#include #include +#include +#include + +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#if XEN_BLKBACK_DEBUG +#include + +/*--------------------------- Compile-time Tunables --------------------------*/ +/** + * The maximum number of outstanding request blocks (request headers plus + * additional segment blocks) we will allow in a negotiated block-front/back + * communication channel. + */ +#define XBB_MAX_REQUESTS 256 + +/** + * \brief Define to force all I/O to be performed on memory owned by the + * backend device, with a copy-in/out to the remote domain's memory. + * + * \note This option is currently required when this driver's domain is + * operating in HVM mode on a system using an IOMMU. + * + * This driver uses Xen's grant table API to gain access to the memory of + * the remote domains it serves. When our domain is operating in PV mode, + * the grant table mechanism directly updates our domain's page table entries + * to point to the physical pages of the remote domain. This scheme guarantees + * that blkback and the backing devices it uses can safely perform DMA + * operations to satisfy requests. In HVM mode, Xen may use a HW IOMMU to + * insure that our domain cannot DMA to pages owned by another domain. As + * of Xen 4.0, IOMMU mappings for HVM guests are not updated via the grant + * table API. For this reason, in HVM mode, we must bounce all requests into + * memory that is mapped into our domain at domain startup and thus has + * valid IOMMU mappings. + */ +#define XBB_USE_BOUNCE_BUFFERS + +/** + * \brief Define to enable rudimentary request logging to the console. + */ +#undef XBB_DEBUG + +/*---------------------------------- Macros ----------------------------------*/ +/** + * Custom malloc type for all driver allocations. + */ +MALLOC_DEFINE(M_XENBLOCKBACK, "xbbd", "Xen Block Back Driver Data"); + +#ifdef XBB_DEBUG #define DPRINTF(fmt, args...) \ - printf("blkback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) + printf("xbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) #else -#define DPRINTF(fmt, args...) ((void)0) +#define DPRINTF(fmt, args...) do {} while(0) #endif -#define WPRINTF(fmt, args...) \ - printf("blkback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) +/** + * The maximum mapped region size per request we will allow in a negotiated + * block-front/back communication channel. + */ +#define XBB_MAX_REQUEST_SIZE \ + MIN(MAXPHYS, BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) -#define BLKBACK_INVALID_HANDLE (~0) +/** + * The maximum number of segments (within a request header and accompanying + * segment blocks) per request we will allow in a negotiated block-front/back + * communication channel. + */ +#define XBB_MAX_SEGMENTS_PER_REQUEST \ + (MIN(UIO_MAXIOV, \ + MIN(BLKIF_MAX_SEGMENTS_PER_REQUEST, \ + (XBB_MAX_REQUEST_SIZE / PAGE_SIZE) + 1))) -struct ring_ref { - vm_offset_t va; - grant_handle_t handle; - uint64_t bus_addr; +/** + * The maximum number of shared memory ring pages we will allow in a + * negotiated block-front/back communication channel. Allow enough + * ring space for all requests to be XBB_MAX_REQUEST_SIZE'd. + */ +#define XBB_MAX_RING_PAGES \ + BLKIF_RING_PAGES(BLKIF_SEGS_TO_BLOCKS(XBB_MAX_SEGMENTS_PER_REQUEST) \ + * XBB_MAX_REQUESTS) + +/*--------------------------- Forward Declarations ---------------------------*/ +struct xbb_softc; + +static void xbb_attach_failed(struct xbb_softc *xbb, int err, const char *fmt, + ...) __attribute__((format(printf, 3, 4))); +static int xbb_shutdown(struct xbb_softc *xbb); +static int xbb_detach(device_t dev); + +/*------------------------------ Data Structures -----------------------------*/ +/** + * \brief Object tracking an in-flight I/O from a Xen VBD consumer. + */ +struct xbb_xen_req { + /** + * Linked list links used to aggregate idle request in the + * request free pool (xbb->request_free_slist). + */ + SLIST_ENTRY(xbb_xen_req) links; + + /** + * Back reference to the parent block back instance for this + * request. Used during bio_done handling. + */ + struct xbb_softc *xbb; + + /** + * The remote domain's identifier for this I/O request. + */ + uint64_t id; + + /** + * Kernel virtual address space reserved for this request + * structure and used to map the remote domain's pages for + * this I/O, into our domain's address space. + */ + uint8_t *kva; + +#ifdef XBB_USE_BOUNCE_BUFFERS + /** + * Pre-allocated domain local memory used to proxy remote + * domain memory during I/O operations. + */ + uint8_t *bounce; +#endif + + /** + * Base, psuedo-physical address, corresponding to the start + * of this request's kva region. + */ + uint64_t gnt_base; + + /** + * The number of pages currently mapped for this request. + */ + int nr_pages; + + /** + * The number of 512 byte sectors comprising this requests. + */ + int nr_512b_sectors; + + /** + * The number of struct bio requests still outstanding for this + * request on the backend device. This field is only used for + * device (rather than file) backed I/O. + */ + int pendcnt; + + /** + * BLKIF_OP code for this request. + */ + int operation; + + /** + * BLKIF_RSP status code for this request. + * + * This field allows an error status to be recorded even if the + * delivery of this status must be deferred. Deferred reporting + * is necessary, for example, when an error is detected during + * completion processing of one bio when other bios for this + * request are still outstanding. + */ + int status; + + /** + * Device statistics request ordering type (ordered or simple). + */ + devstat_tag_type ds_tag_type; + + /** + * Device statistics request type (read, write, no_data). + */ + devstat_trans_flags ds_trans_type; + + /** + * The start time for this request. + */ + struct bintime ds_t0; + + /** + * Array of grant handles (one per page) used to map this request. + */ + grant_handle_t *gnt_handles; +}; +SLIST_HEAD(xbb_xen_req_slist, xbb_xen_req); + +/** + * \brief Configuration data for the shared memory request ring + * used to communicate with the front-end client of this + * this driver. + */ +struct xbb_ring_config { + /** KVA address where ring memory is mapped. */ + vm_offset_t va; + + /** The pseudo-physical address where ring memory is mapped.*/ + uint64_t gnt_addr; + + /** + * Grant table handles, one per-ring page, returned by the + * hyperpervisor upon mapping of the ring and required to + * unmap it when a connection is torn down. + */ + grant_handle_t handle[XBB_MAX_RING_PAGES]; + + /** + * The device bus address returned by the hypervisor when + * mapping the ring and required to unmap it when a connection + * is torn down. + */ + uint64_t bus_addr[XBB_MAX_RING_PAGES]; + + /** The number of ring pages mapped for the current connection. */ + u_int ring_pages; + + /** + * The grant references, one per-ring page, supplied by the + * front-end, allowing us to reference the ring pages in the + * front-end's domain and to map these pages into our own domain. + */ + grant_ref_t ring_ref[XBB_MAX_RING_PAGES]; + + /** The interrupt driven even channel used to signal ring events. */ + evtchn_port_t evtchn; }; -typedef struct blkback_info { +/** + * Per-instance connection state flags. + */ +typedef enum +{ + /** + * The front-end requested a read-only mount of the + * back-end device/file. + */ + XBBF_READ_ONLY = 0x01, - /* Schedule lists */ - STAILQ_ENTRY(blkback_info) next_req; - int on_req_sched_list; + /** Communication with the front-end has been established. */ + XBBF_RING_CONNECTED = 0x02, - struct xenbus_device *xdev; - XenbusState frontend_state; + /** + * Front-end requests exist in the ring and are waiting for + * xbb_xen_req objects to free up. + */ + XBBF_RESOURCE_SHORTAGE = 0x04, - domid_t domid; + /** Connection teardown in progress. */ + XBBF_SHUTDOWN = 0x08 +} xbb_flag_t; - int state; - int ring_connected; - struct ring_ref rr; - blkif_back_ring_t ring; - evtchn_port_t evtchn; - int irq; - void *irq_cookie; +/** Backend device type. */ +typedef enum { + /** Backend type unknown. */ + XBB_TYPE_NONE = 0x00, - int ref_cnt; + /** + * Backend type disk (access via cdev switch + * strategy routine). + */ + XBB_TYPE_DISK = 0x01, - int handle; - char *mode; - char *type; - char *dev_name; + /** Backend type file (access vnode operations.). */ + XBB_TYPE_FILE = 0x02 +} xbb_type; - struct vnode *vn; - struct cdev *cdev; +/** + * \brief Structure used to memoize information about a per-request + * scatter-gather list. + * + * The chief benefit of using this data structure is it avoids having + * to reparse the possibly discontiguous S/G list in the original + * request. Due to the way that the mapping of the memory backing an + * I/O transaction is handled by Xen, a second pass is unavoidable. + * At least this way the second walk is a simple array traversal. + * + * \note A single Scatter/Gather element in the block interface covers + * at most 1 machine page. In this context a sector (blkif + * nomenclature, not what I'd choose) is a 512b aligned unit + * of mapping within the machine page referenced by an S/G + * element. + */ +struct xbb_sg { + /** The number of 512b data chunks mapped in this S/G element. */ + int16_t nsect; + + /** + * The index (0 based) of the first 512b data chunk mapped + * in this S/G element. + */ + uint8_t first_sect; + + /** + * The index (0 based) of the last 512b data chunk mapped + * in this S/G element. + */ + uint8_t last_sect; +}; + +/** + * Character device backend specific configuration data. + */ +struct xbb_dev_data { + /** Cdev used for device backend access. */ + struct cdev *cdev; + + /** Cdev switch used for device backend access. */ struct cdevsw *csw; - u_int sector_size; - int sector_size_shift; - off_t media_size; - u_int media_num_sectors; - int major; - int minor; - int read_only; - struct mtx blk_ring_lock; + /** Used to hold a reference on opened cdev backend devices. */ + int dev_ref; +}; - device_t ndev; - - /* Stats */ - int st_rd_req; - int st_wr_req; - int st_oo_req; - int st_err_req; -} blkif_t; - -/* - * These are rather arbitrary. They are fairly large because adjacent requests - * pulled from a communication ring are quite likely to end up being part of - * the same scatter/gather request at the disc. - * - * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW ** - * - * This will increase the chances of being able to write whole tracks. - * 64 should be enough to keep us competitive with Linux. +/** + * File backend specific configuration data. */ -static int blkif_reqs = 64; -TUNABLE_INT("xen.vbd.blkif_reqs", &blkif_reqs); +struct xbb_file_data { + /** Credentials to use for vnode backed (file based) I/O. */ + struct ucred *cred; -static int mmap_pages; + /** + * \brief Array of io vectors used to process file based I/O. + * + * Only a single file based request is outstanding per-xbb instance, + * so we only need one of these. + */ + struct iovec xiovecs[XBB_MAX_SEGMENTS_PER_REQUEST]; +#ifdef XBB_USE_BOUNCE_BUFFERS -/* - * Each outstanding request that we've passed to the lower device layers has a - * 'pending_req' allocated to it. Each buffer_head that completes decrements - * the pendcnt towards zero. When it hits zero, the specified domain has a - * response queued for it, with the saved 'id' passed back. + /** + * \brief Array of io vectors used to handle bouncing of file reads. + * + * Vnode operations are free to modify uio data during their + * exectuion. In the case of a read with bounce buffering active, + * we need some of the data from the original uio in order to + * bounce-out the read data. This array serves as the temporary + * storage for this saved data. + */ + struct iovec saved_xiovecs[XBB_MAX_SEGMENTS_PER_REQUEST]; + + /** + * \brief Array of memoized bounce buffer kva offsets used + * in the file based backend. + * + * Due to the way that the mapping of the memory backing an + * I/O transaction is handled by Xen, a second pass through + * the request sg elements is unavoidable. We memoize the computed + * bounce address here to reduce the cost of the second walk. + */ + void *xiovecs_vaddr[XBB_MAX_SEGMENTS_PER_REQUEST]; +#endif /* XBB_USE_BOUNCE_BUFFERS */ +}; + +/** + * Collection of backend type specific data. */ -typedef struct pending_req { - blkif_t *blkif; - uint64_t id; - int nr_pages; - int pendcnt; - unsigned short operation; - int status; - STAILQ_ENTRY(pending_req) free_list; -} pending_req_t; +union xbb_backend_data { + struct xbb_dev_data dev; + struct xbb_file_data file; +}; -static pending_req_t *pending_reqs; -static STAILQ_HEAD(pending_reqs_list, pending_req) pending_free = - STAILQ_HEAD_INITIALIZER(pending_free); -static struct mtx pending_free_lock; +/** + * Function signature of backend specific I/O handlers. + */ +typedef int (*xbb_dispatch_t)(struct xbb_softc *xbb, blkif_request_t *ring_req, + struct xbb_xen_req *req, int nseg, + int operation, int flags); -static STAILQ_HEAD(blkback_req_sched_list, blkback_info) req_sched_list = - STAILQ_HEAD_INITIALIZER(req_sched_list); -static struct mtx req_sched_list_lock; +/** + * Per-instance configuration data. + */ +struct xbb_softc { -static unsigned long mmap_vstart; -static unsigned long *pending_vaddrs; -static grant_handle_t *pending_grant_handles; + /** + * Task-queue used to process I/O requests. + */ + struct taskqueue *io_taskqueue; -static struct task blk_req_task; + /** + * Single "run the request queue" task enqueued + * on io_taskqueue. + */ + struct task io_task; -/* Protos */ -static void disconnect_ring(blkif_t *blkif); -static int vbd_add_dev(struct xenbus_device *xdev); + /** Device type for this instance. */ + xbb_type device_type; -static inline int vaddr_pagenr(pending_req_t *req, int seg) + /** NewBus device corresponding to this instance. */ + device_t dev; + + /** Backend specific dispatch routine for this instance. */ + xbb_dispatch_t dispatch_io; + + /** The number of requests outstanding on the backend device/file. */ + u_int active_request_count; + + /** Free pool of request tracking structures. */ + struct xbb_xen_req_slist request_free_slist; + + /** Array, sized at connection time, of request tracking structures. */ + struct xbb_xen_req *requests; + + /** + * Global pool of kva used for mapping remote domain ring + * and I/O transaction data. + */ + vm_offset_t kva; + + /** Psuedo-physical address corresponding to kva. */ + uint64_t gnt_base_addr; + + /** The size of the global kva pool. */ + int kva_size; + + /** + * \brief Cached value of the front-end's domain id. + * + * This value is used at once for each mapped page in + * a transaction. We cache it to avoid incuring the + * cost of an ivar access every time this is needed. + */ + domid_t otherend_id; + + /** + * \brief The blkif protocol abi in effect. + * + * There are situations where the back and front ends can + * have a different, native abi (e.g. intel x86_64 and + * 32bit x86 domains on the same machine). The back-end + * always accomodates the front-end's native abi. That + * value is pulled from the XenStore and recorded here. + */ + int abi; + + /** + * \brief The maximum number of requests allowed to be in + * flight at a time. + * + * This value is negotiated via the XenStore. + */ + uint32_t max_requests; + + /** + * \brief The maximum number of segments (1 page per segment) + * that can be mapped by a request. + * + * This value is negotiated via the XenStore. + */ + uint32_t max_request_segments; + + /** + * The maximum size of any request to this back-end + * device. + * + * This value is negotiated via the XenStore. + */ + uint32_t max_request_size; + + /** Various configuration and state bit flags. */ + xbb_flag_t flags; + + /** Ring mapping and interrupt configuration data. */ + struct xbb_ring_config ring_config; + + /** Runtime, cross-abi safe, structures for ring access. */ + blkif_back_rings_t rings; + + /** IRQ mapping for the communication ring event channel. */ + int irq; + + /** + * \brief Backend access mode flags (e.g. write, or read-only). + * + * This value is passed to us by the front-end via the XenStore. + */ + char *dev_mode; + + /** + * \brief Backend device type (e.g. "disk", "cdrom", "floppy"). + * + * This value is passed to us by the front-end via the XenStore. + * Currently unused. + */ + char *dev_type; + + /** + * \brief Backend device/file identifier. + * + * This value is passed to us by the front-end via the XenStore. + * We expect this to be a POSIX path indicating the file or + * device to open. + */ + char *dev_name; + + /** + * Vnode corresponding to the backend device node or file + * we are acessing. + */ + struct vnode *vn; + + union xbb_backend_data backend; + /** The native sector size of the backend. */ + u_int sector_size; + + /** log2 of sector_size. */ + u_int sector_size_shift; + + /** Size in bytes of the backend device or file. */ + off_t media_size; + + /** + * \brief media_size expressed in terms of the backend native + * sector size. + * + * (e.g. xbb->media_size >> xbb->sector_size_shift). + */ + uint64_t media_num_sectors; + + /** + * \brief Array of memoized scatter gather data computed during the + * conversion of blkif ring requests to internal xbb_xen_req + * structures. + * + * Ring processing is serialized so we only need one of these. + */ + struct xbb_sg xbb_sgs[XBB_MAX_SEGMENTS_PER_REQUEST]; + + /** Mutex protecting per-instance data. */ + struct mtx lock; + +#ifdef XENHVM + /** + * Resource representing allocated physical address space + * associated with our per-instance kva region. + */ + struct resource *pseudo_phys_res; + + /** Resource id for allocated physical address space. */ + int pseudo_phys_res_id; +#endif + + /** I/O statistics. */ + struct devstat *xbb_stats; +}; + +/*---------------------------- Request Processing ----------------------------*/ +/** + * Allocate an internal transaction tracking structure from the free pool. + * + * \param xbb Per-instance xbb configuration structure. + * + * \return On success, a pointer to the allocated xbb_xen_req structure. + * Otherwise NULL. + */ +static inline struct xbb_xen_req * +xbb_get_req(struct xbb_softc *xbb) { - return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg; -} + struct xbb_xen_req *req; -static inline unsigned long vaddr(pending_req_t *req, int seg) -{ - return pending_vaddrs[vaddr_pagenr(req, seg)]; -} + req = NULL; + mtx_lock(&xbb->lock); -#define pending_handle(_req, _seg) \ - (pending_grant_handles[vaddr_pagenr(_req, _seg)]) - -static unsigned long -alloc_empty_page_range(unsigned long nr_pages) -{ - void *pages; - int i = 0, j = 0; - multicall_entry_t mcl[17]; - unsigned long mfn_list[16]; - struct xen_memory_reservation reservation = { - .extent_start = mfn_list, - .nr_extents = 0, - .address_bits = 0, - .extent_order = 0, - .domid = DOMID_SELF - }; - - pages = malloc(nr_pages*PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (pages == NULL) - return 0; - - memset(mcl, 0, sizeof(mcl)); - - while (i < nr_pages) { - unsigned long va = (unsigned long)pages + (i++ * PAGE_SIZE); - - mcl[j].op = __HYPERVISOR_update_va_mapping; - mcl[j].args[0] = va; - - mfn_list[j++] = vtomach(va) >> PAGE_SHIFT; - - xen_phys_machine[(vtophys(va) >> PAGE_SHIFT)] = INVALID_P2M_ENTRY; - - if (j == 16 || i == nr_pages) { - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_LOCAL; - - reservation.nr_extents = j; - - mcl[j].op = __HYPERVISOR_memory_op; - mcl[j].args[0] = XENMEM_decrease_reservation; - mcl[j].args[1] = (unsigned long)&reservation; - - (void)HYPERVISOR_multicall(mcl, j+1); - - mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = 0; - j = 0; + /* + * Do not allow new requests to be allocated while we + * are shutting down. + */ + if ((xbb->flags & XBBF_SHUTDOWN) == 0) { + if ((req = SLIST_FIRST(&xbb->request_free_slist)) != NULL) { + SLIST_REMOVE_HEAD(&xbb->request_free_slist, links); + xbb->active_request_count++; + } else { + xbb->flags |= XBBF_RESOURCE_SHORTAGE; } } - - return (unsigned long)pages; + mtx_unlock(&xbb->lock); + return (req); } -static pending_req_t * -alloc_req(void) +/** + * Return an allocated transaction tracking structure to the free pool. + * + * \param xbb Per-instance xbb configuration structure. + * \param req The request structure to free. + */ +static inline void +xbb_release_req(struct xbb_softc *xbb, struct xbb_xen_req *req) { - pending_req_t *req; - mtx_lock(&pending_free_lock); - if ((req = STAILQ_FIRST(&pending_free))) { - STAILQ_REMOVE(&pending_free, req, pending_req, free_list); - STAILQ_NEXT(req, free_list) = NULL; + int wake_thread; + + mtx_lock(&xbb->lock); + wake_thread = xbb->flags & XBBF_RESOURCE_SHORTAGE; + xbb->flags &= ~XBBF_RESOURCE_SHORTAGE; + SLIST_INSERT_HEAD(&xbb->request_free_slist, req, links); + xbb->active_request_count--; + + if ((xbb->flags & XBBF_SHUTDOWN) != 0) { + /* + * Shutdown is in progress. See if we can + * progress further now that one more request + * has completed and been returned to the + * free pool. + */ + xbb_shutdown(xbb); } - mtx_unlock(&pending_free_lock); - return req; + mtx_unlock(&xbb->lock); + + if (wake_thread != 0) + taskqueue_enqueue(xbb->io_taskqueue, &xbb->io_task); } -static void -free_req(pending_req_t *req) +/** + * Given a page index and 512b sector offset within that page, + * calculate an offset into a request's kva region. + * + * \param req The request structure whose kva region will be accessed. + * \param pagenr The page index used to compute the kva offset. + * \param sector The 512b sector index used to compute the page relative + * kva offset. + * + * \return The computed global KVA offset. + */ +static inline uint8_t * +xbb_req_vaddr(struct xbb_xen_req *req, int pagenr, int sector) { - int was_empty; - - mtx_lock(&pending_free_lock); - was_empty = STAILQ_EMPTY(&pending_free); - STAILQ_INSERT_TAIL(&pending_free, req, free_list); - mtx_unlock(&pending_free_lock); - if (was_empty) - taskqueue_enqueue(taskqueue_swi, &blk_req_task); + return (req->kva + (PAGE_SIZE * pagenr) + (sector << 9)); } -static void -fast_flush_area(pending_req_t *req) +#ifdef XBB_USE_BOUNCE_BUFFERS +/** + * Given a page index and 512b sector offset within that page, + * calculate an offset into a request's local bounce memory region. + * + * \param req The request structure whose bounce region will be accessed. + * \param pagenr The page index used to compute the bounce offset. + * \param sector The 512b sector index used to compute the page relative + * bounce offset. + * + * \return The computed global bounce buffer address. + */ +static inline uint8_t * +xbb_req_bounce_addr(struct xbb_xen_req *req, int pagenr, int sector) { - struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - unsigned int i, invcount = 0; - grant_handle_t handle; - int ret; + return (req->bounce + (PAGE_SIZE * pagenr) + (sector << 9)); +} +#endif +/** + * Given a page number and 512b sector offset within that page, + * calculate an offset into the request's memory region that the + * underlying backend device/file should use for I/O. + * + * \param req The request structure whose I/O region will be accessed. + * \param pagenr The page index used to compute the I/O offset. + * \param sector The 512b sector index used to compute the page relative + * I/O offset. + * + * \return The computed global I/O address. + * + * Depending on configuration, this will either be a local bounce buffer + * or a pointer to the memory mapped in from the front-end domain for + * this request. + */ +static inline uint8_t * +xbb_req_ioaddr(struct xbb_xen_req *req, int pagenr, int sector) +{ +#ifdef XBB_USE_BOUNCE_BUFFERS + return (xbb_req_bounce_addr(req, pagenr, sector)); +#else + return (xbb_req_vaddr(req, pagenr, sector)); +#endif +} + +/** + * Given a page index and 512b sector offset within that page, calculate + * an offset into the local psuedo-physical address space used to map a + * front-end's request data into a request. + * + * \param req The request structure whose pseudo-physical region + * will be accessed. + * \param pagenr The page index used to compute the pseudo-physical offset. + * \param sector The 512b sector index used to compute the page relative + * pseudo-physical offset. + * + * \return The computed global pseudo-phsyical address. + * + * Depending on configuration, this will either be a local bounce buffer + * or a pointer to the memory mapped in from the front-end domain for + * this request. + */ +static inline uintptr_t +xbb_req_gntaddr(struct xbb_xen_req *req, int pagenr, int sector) +{ + return ((uintptr_t)(req->gnt_base + + (PAGE_SIZE * pagenr) + (sector << 9))); +} + +/** + * Unmap the front-end pages associated with this I/O request. + * + * \param req The request structure to unmap. + */ +static void +xbb_unmap_req(struct xbb_xen_req *req) +{ + struct gnttab_unmap_grant_ref unmap[XBB_MAX_SEGMENTS_PER_REQUEST]; + u_int i; + u_int invcount; + int error; + + invcount = 0; for (i = 0; i < req->nr_pages; i++) { - handle = pending_handle(req, i); - if (handle == BLKBACK_INVALID_HANDLE) + + if (req->gnt_handles[i] == GRANT_REF_INVALID) continue; - unmap[invcount].host_addr = vaddr(req, i); + + unmap[invcount].host_addr = xbb_req_gntaddr(req, i, 0); unmap[invcount].dev_bus_addr = 0; - unmap[invcount].handle = handle; - pending_handle(req, i) = BLKBACK_INVALID_HANDLE; + unmap[invcount].handle = req->gnt_handles[i]; + req->gnt_handles[i] = GRANT_REF_INVALID; invcount++; } - ret = HYPERVISOR_grant_table_op( - GNTTABOP_unmap_grant_ref, unmap, invcount); - PANIC_IF(ret); + error = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + unmap, invcount); + KASSERT(error == 0, ("Grant table operation failed")); } +/** + * Create and transmit a response to a blkif request. + * + * \param xbb Per-instance xbb configuration structure. + * \param req The request structure to which to respond. + * \param status The status code to report. See BLKIF_RSP_* + * in sys/xen/interface/io/blkif.h. + */ static void -blkif_get(blkif_t *blkif) -{ - atomic_add_int(&blkif->ref_cnt, 1); -} - -static void -blkif_put(blkif_t *blkif) -{ - if (atomic_fetchadd_int(&blkif->ref_cnt, -1) == 1) { - DPRINTF("Removing %x\n", (unsigned int)blkif); - disconnect_ring(blkif); - if (blkif->mode) - free(blkif->mode, M_DEVBUF); - if (blkif->type) - free(blkif->type, M_DEVBUF); - if (blkif->dev_name) - free(blkif->dev_name, M_DEVBUF); - free(blkif, M_DEVBUF); - } -} - -static int -blkif_create(struct xenbus_device *xdev, long handle, char *mode, char *type, char *params) -{ - blkif_t *blkif; - - blkif = (blkif_t *)malloc(sizeof(*blkif), M_DEVBUF, M_NOWAIT | M_ZERO); - if (!blkif) - return ENOMEM; - - DPRINTF("Created %x\n", (unsigned int)blkif); - - blkif->ref_cnt = 1; - blkif->domid = xdev->otherend_id; - blkif->handle = handle; - blkif->mode = mode; - blkif->type = type; - blkif->dev_name = params; - blkif->xdev = xdev; - xdev->data = blkif; - - mtx_init(&blkif->blk_ring_lock, "blk_ring_ock", "blkback ring lock", MTX_DEF); - - if (strcmp(mode, "w")) - blkif->read_only = 1; - - return 0; -} - -static void -add_to_req_schedule_list_tail(blkif_t *blkif) -{ - if (!blkif->on_req_sched_list) { - mtx_lock(&req_sched_list_lock); - if (!blkif->on_req_sched_list && (blkif->state == XenbusStateConnected)) { - blkif_get(blkif); - STAILQ_INSERT_TAIL(&req_sched_list, blkif, next_req); - blkif->on_req_sched_list = 1; - taskqueue_enqueue(taskqueue_swi, &blk_req_task); - } - mtx_unlock(&req_sched_list_lock); - } -} - -/* This routine does not call blkif_get(), does not schedule the blk_req_task to run, - and assumes that the state is connected */ -static void -add_to_req_schedule_list_tail2(blkif_t *blkif) -{ - mtx_lock(&req_sched_list_lock); - if (!blkif->on_req_sched_list) { - STAILQ_INSERT_TAIL(&req_sched_list, blkif, next_req); - blkif->on_req_sched_list = 1; - } - mtx_unlock(&req_sched_list_lock); -} - -/* Removes blkif from front of list and does not call blkif_put() (caller must) */ -static blkif_t * -remove_from_req_schedule_list(void) -{ - blkif_t *blkif; - - mtx_lock(&req_sched_list_lock); - - if ((blkif = STAILQ_FIRST(&req_sched_list))) { - STAILQ_REMOVE(&req_sched_list, blkif, blkback_info, next_req); - STAILQ_NEXT(blkif, next_req) = NULL; - blkif->on_req_sched_list = 0; - } - - mtx_unlock(&req_sched_list_lock); - - return blkif; -} - -static void -make_response(blkif_t *blkif, uint64_t id, - unsigned short op, int st) +xbb_send_response(struct xbb_softc *xbb, struct xbb_xen_req *req, int status) { blkif_response_t *resp; - blkif_back_ring_t *blk_ring = &blkif->ring; - int more_to_do = 0; - int notify; + int more_to_do; + int notify; - mtx_lock(&blkif->blk_ring_lock); + more_to_do = 0; + /* + * Place on the response ring for the relevant domain. + * For now, only the spacing between entries is different + * in the different ABIs, not the response entry layout. + */ + mtx_lock(&xbb->lock); + switch (xbb->abi) { + case BLKIF_PROTOCOL_NATIVE: + resp = RING_GET_RESPONSE(&xbb->rings.native, + xbb->rings.native.rsp_prod_pvt); + break; + case BLKIF_PROTOCOL_X86_32: + resp = (blkif_response_t *) + RING_GET_RESPONSE(&xbb->rings.x86_32, + xbb->rings.x86_32.rsp_prod_pvt); + break; + case BLKIF_PROTOCOL_X86_64: + resp = (blkif_response_t *) + RING_GET_RESPONSE(&xbb->rings.x86_64, + xbb->rings.x86_64.rsp_prod_pvt); + break; + default: + panic("Unexpected blkif protocol ABI."); + } - /* Place on the response ring for the relevant domain. */ - resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt); - resp->id = id; - resp->operation = op; - resp->status = st; - blk_ring->rsp_prod_pvt++; - RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify); + resp->id = req->id; + resp->operation = req->operation; + resp->status = status; + + xbb->rings.common.rsp_prod_pvt += BLKIF_SEGS_TO_BLOCKS(req->nr_pages); + RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&xbb->rings.common, notify); + + if (xbb->rings.common.rsp_prod_pvt == xbb->rings.common.req_cons) { - if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) { /* * Tail check for pending requests. Allows frontend to avoid * notifications if requests are already in flight (lower * overheads and promotes batching). */ - RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do); + RING_FINAL_CHECK_FOR_REQUESTS(&xbb->rings.common, more_to_do); + } else if (RING_HAS_UNCONSUMED_REQUESTS(&xbb->rings.common)) { - } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) more_to_do = 1; - - mtx_unlock(&blkif->blk_ring_lock); - - if (more_to_do) - add_to_req_schedule_list_tail(blkif); - - if (notify) - notify_remote_via_irq(blkif->irq); -} - -static void -end_block_io_op(struct bio *bio) -{ - pending_req_t *pending_req = bio->bio_caller2; - - if (bio->bio_error) { - DPRINTF("BIO returned error %d for operation on device %s\n", - bio->bio_error, pending_req->blkif->dev_name); - pending_req->status = BLKIF_RSP_ERROR; - pending_req->blkif->st_err_req++; } -#if 0 - printf("done: bio=%x error=%x completed=%llu resid=%lu flags=%x\n", - (unsigned int)bio, bio->bio_error, bio->bio_completed, bio->bio_resid, bio->bio_flags); -#endif + mtx_unlock(&xbb->lock); - if (atomic_fetchadd_int(&pending_req->pendcnt, -1) == 1) { - fast_flush_area(pending_req); - make_response(pending_req->blkif, pending_req->id, - pending_req->operation, pending_req->status); - blkif_put(pending_req->blkif); - free_req(pending_req); + if (more_to_do) + taskqueue_enqueue(xbb->io_taskqueue, &xbb->io_task); + + if (notify) + notify_remote_via_irq(xbb->irq); +} + +/** + * Completion handler for buffer I/O requests issued by the device + * backend driver. + * + * \param bio The buffer I/O request on which to perform completion + * processing. + */ +static void +xbb_bio_done(struct bio *bio) +{ + struct xbb_softc *xbb; + struct xbb_xen_req *req; + + req = bio->bio_caller1; + xbb = req->xbb; + + /* Only include transferred I/O in stats. */ + req->nr_512b_sectors -= bio->bio_resid >> 9; + if (bio->bio_error) { + DPRINTF("BIO returned error %d for operation on device %s\n", + bio->bio_error, xbb->dev_name); + req->status = BLKIF_RSP_ERROR; + + if (bio->bio_error == ENXIO + && xenbus_get_state(xbb->dev) == XenbusStateConnected) { + + /* + * Backend device has disappeared. Signal the + * front-end that we (the device proxy) want to + * go away. + */ + xenbus_set_state(xbb->dev, XenbusStateClosing); + } + } + +#ifdef XBB_USE_BOUNCE_BUFFERS + if (bio->bio_cmd == BIO_READ) { + vm_offset_t kva_offset; + + kva_offset = (vm_offset_t)bio->bio_data + - (vm_offset_t)req->bounce; + memcpy((uint8_t *)req->kva + kva_offset, + bio->bio_data, bio->bio_bcount); + } +#endif /* XBB_USE_BOUNCE_BUFFERS */ + + if (atomic_fetchadd_int(&req->pendcnt, -1) == 1) { + xbb_unmap_req(req); + xbb_send_response(xbb, req, req->status); + devstat_end_transaction(xbb->xbb_stats, + /*bytes*/req->nr_512b_sectors << 9, + req->ds_tag_type, + req->ds_trans_type, + /*now*/NULL, + /*then*/&req->ds_t0); + xbb_release_req(xbb, req); } g_destroy_bio(bio); } +/** + * Parse a blkif request into an internal request structure and send + * it to the backend for processing. + * + * \param xbb Per-instance xbb configuration structure. + * \param ring_req Front-end's I/O request as pulled from the shared + * communication ring. + * \param req Allocated internal request structure. + * \param req_ring_idx The location of ring_req within the shared + * communication ring. + * + * This routine performs the backend common aspects of request parsing + * including compiling an internal request structure, parsing the S/G + * list and any secondary ring requests in which they may reside, and + * the mapping of front-end I/O pages into our domain. + */ static void -dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req, pending_req_t *pending_req) +xbb_dispatch_io(struct xbb_softc *xbb, blkif_request_t *ring_req, + struct xbb_xen_req *req, RING_IDX req_ring_idx) { - struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - struct { - unsigned long buf; unsigned int nsec; - } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - unsigned int nseg = req->nr_segments, nr_sects = 0; - struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST]; - int operation, ret, i, nbio = 0; + struct gnttab_map_grant_ref maps[XBB_MAX_SEGMENTS_PER_REQUEST]; + struct xbb_sg *xbb_sg; + struct gnttab_map_grant_ref *map; + struct blkif_request_segment *sg; + struct blkif_request_segment *last_block_sg; + u_int nseg; + u_int seg_idx; + u_int block_segs; + int nr_sects; + int operation; + uint8_t bio_flags; + int error; - /* Check that number of segments is sane. */ - if (unlikely(nseg == 0) || - unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) { - DPRINTF("Bad number of segments in request (%d)\n", nseg); - goto fail_response; + nseg = ring_req->nr_segments; + nr_sects = 0; + req->xbb = xbb; + req->id = ring_req->id; + req->operation = ring_req->operation; + req->status = BLKIF_RSP_OKAY; + req->ds_tag_type = DEVSTAT_TAG_SIMPLE; + req->nr_pages = nseg; + req->nr_512b_sectors = 0; + bio_flags = 0; + sg = NULL; + + binuptime(&req->ds_t0); + devstat_start_transaction(xbb->xbb_stats, &req->ds_t0); + + switch (req->operation) { + case BLKIF_OP_WRITE_BARRIER: + bio_flags |= BIO_ORDERED; + req->ds_tag_type = DEVSTAT_TAG_ORDERED; + /* FALLTHROUGH */ + case BLKIF_OP_WRITE: + operation = BIO_WRITE; + req->ds_trans_type = DEVSTAT_WRITE; + if ((xbb->flags & XBBF_READ_ONLY) != 0) { + DPRINTF("Attempt to write to read only device %s\n", + xbb->dev_name); + goto fail_send_response; + } + break; + case BLKIF_OP_READ: + operation = BIO_READ; + req->ds_trans_type = DEVSTAT_READ; + break; + case BLKIF_OP_FLUSH_DISKCACHE: + operation = BIO_FLUSH; + req->ds_tag_type = DEVSTAT_TAG_ORDERED; + req->ds_trans_type = DEVSTAT_NO_DATA; + goto do_dispatch; + /*NOTREACHED*/ + default: + DPRINTF("error: unknown block io operation [%d]\n", + req->operation); + goto fail_send_response; } - if (req->operation == BLKIF_OP_WRITE) { - if (blkif->read_only) { - DPRINTF("Attempt to write to read only device %s\n", blkif->dev_name); - goto fail_response; + /* Check that number of segments is sane. */ + if (unlikely(nseg == 0) + || unlikely(nseg > xbb->max_request_segments)) { + DPRINTF("Bad number of segments in request (%d)\n", nseg); + goto fail_send_response; + } + + map = maps; + xbb_sg = xbb->xbb_sgs; + block_segs = MIN(req->nr_pages, BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK); + sg = ring_req->seg; + last_block_sg = sg + block_segs; + seg_idx = 0; + while (1) { + + while (sg < last_block_sg) { + + xbb_sg->first_sect = sg->first_sect; + xbb_sg->last_sect = sg->last_sect; + xbb_sg->nsect = + (int8_t)(sg->last_sect - sg->first_sect + 1); + + if ((sg->last_sect >= (PAGE_SIZE >> 9)) + || (xbb_sg->nsect <= 0)) + goto fail_send_response; + + nr_sects += xbb_sg->nsect; + map->host_addr = xbb_req_gntaddr(req, seg_idx, + /*sector*/0); + map->flags = GNTMAP_host_map; + map->ref = sg->gref; + map->dom = xbb->otherend_id; + if (operation == BIO_WRITE) + map->flags |= GNTMAP_readonly; + sg++; + map++; + xbb_sg++; + seg_idx++; } - operation = BIO_WRITE; - } else - operation = BIO_READ; - pending_req->blkif = blkif; - pending_req->id = req->id; - pending_req->operation = req->operation; - pending_req->status = BLKIF_RSP_OKAY; - pending_req->nr_pages = nseg; + block_segs = MIN(nseg - seg_idx, + BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK); + if (block_segs == 0) + break; - for (i = 0; i < nseg; i++) { - seg[i].nsec = req->seg[i].last_sect - - req->seg[i].first_sect + 1; - - if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) || - (seg[i].nsec <= 0)) - goto fail_response; - nr_sects += seg[i].nsec; - - map[i].host_addr = vaddr(pending_req, i); - map[i].dom = blkif->domid; - map[i].ref = req->seg[i].gref; - map[i].flags = GNTMAP_host_map; - if (operation == BIO_WRITE) - map[i].flags |= GNTMAP_readonly; + /* + * Fetch the next request block full of SG elements. + * For now, only the spacing between entries is different + * in the different ABIs, not the sg entry layout. + */ + req_ring_idx++; + switch (xbb->abi) { + case BLKIF_PROTOCOL_NATIVE: + sg = BLKRING_GET_SG_REQUEST(&xbb->rings.native, + req_ring_idx); + break; + case BLKIF_PROTOCOL_X86_32: + { + sg = BLKRING_GET_SG_REQUEST(&xbb->rings.x86_32, + req_ring_idx); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + sg = BLKRING_GET_SG_REQUEST(&xbb->rings.x86_64, + req_ring_idx); + break; + } + default: + panic("Unexpected blkif protocol ABI."); + /* NOTREACHED */ + } + last_block_sg = sg + block_segs; } /* Convert to the disk's sector size */ - nr_sects = (nr_sects << 9) >> blkif->sector_size_shift; + req->nr_512b_sectors = nr_sects; + nr_sects = (nr_sects << 9) >> xbb->sector_size_shift; - ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg); - PANIC_IF(ret); - - for (i = 0; i < nseg; i++) { - if (unlikely(map[i].status != 0)) { - DPRINTF("invalid buffer -- could not remap it\n"); - goto fail_flush; - } - - pending_handle(pending_req, i) = map[i].handle; -#if 0 - /* Can't do this in FreeBSD since vtophys() returns the pfn */ - /* of the remote domain who loaned us the machine page - DPT */ - xen_phys_machine[(vtophys(vaddr(pending_req, i)) >> PAGE_SHIFT)] = - map[i]dev_bus_addr >> PAGE_SHIFT; -#endif - seg[i].buf = map[i].dev_bus_addr | - (req->seg[i].first_sect << 9); + if ((req->nr_512b_sectors & ((xbb->sector_size >> 9) - 1)) != 0) { + device_printf(xbb->dev, "%s: I/O size (%d) is not a multiple " + "of the backing store sector size (%d)\n", + __func__, req->nr_512b_sectors << 9, + xbb->sector_size); + goto fail_send_response; } - if (req->sector_number + nr_sects > blkif->media_num_sectors) { - DPRINTF("%s of [%llu,%llu] extends past end of device %s\n", + error = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, + maps, req->nr_pages); + if (error != 0) + panic("Grant table operation failed (%d)", error); + + for (seg_idx = 0, map = maps; seg_idx < nseg; seg_idx++, map++) { + + if (unlikely(map->status != 0)) { + DPRINTF("invalid buffer -- could not remap it (%d)\n", + map->status); + DPRINTF("Mapping(%d): Host Addr 0x%lx, flags 0x%x " + "ref 0x%x, dom %d\n", seg_idx, + map->host_addr, map->flags, map->ref, + map->dom); + goto fail_unmap_req; + } + + req->gnt_handles[seg_idx] = map->handle; + } + if (ring_req->sector_number + nr_sects > xbb->media_num_sectors) { + + DPRINTF("%s of [%" PRIu64 ",%" PRIu64 "] " + "extends past end of device %s\n", operation == BIO_READ ? "read" : "write", - req->sector_number, - req->sector_number + nr_sects, blkif->dev_name); - goto fail_flush; + ring_req->sector_number, + ring_req->sector_number + nr_sects, xbb->dev_name); + goto fail_unmap_req; } - for (i = 0; i < nseg; i++) { - struct bio *bio; +do_dispatch: - if ((int)seg[i].nsec & ((blkif->sector_size >> 9) - 1)) { - DPRINTF("Misaligned I/O request from domain %d", blkif->domid); - goto fail_put_bio; - } + error = xbb->dispatch_io(xbb, + ring_req, + req, + nseg, + operation, + bio_flags); - bio = biolist[nbio++] = g_new_bio(); - if (unlikely(bio == NULL)) - goto fail_put_bio; - - bio->bio_cmd = operation; - bio->bio_offset = req->sector_number << blkif->sector_size_shift; - bio->bio_length = seg[i].nsec << 9; - bio->bio_bcount = bio->bio_length; - bio->bio_data = (caddr_t)(vaddr(pending_req, i) | (seg[i].buf & PAGE_MASK)); - bio->bio_done = end_block_io_op; - bio->bio_caller2 = pending_req; - bio->bio_dev = blkif->cdev; - - req->sector_number += (seg[i].nsec << 9) >> blkif->sector_size_shift; -#if 0 - printf("new: bio=%x cmd=%d sect=%llu nsect=%u iosize_max=%u @ %08lx\n", - (unsigned int)bio, req->operation, req->sector_number, seg[i].nsec, - blkif->cdev->si_iosize_max, seg[i].buf); -#endif + if (error != 0) { + if (operation == BIO_FLUSH) + goto fail_send_response; + else + goto fail_unmap_req; } - pending_req->pendcnt = nbio; - blkif_get(blkif); - - for (i = 0; i < nbio; i++) - (*blkif->csw->d_strategy)(biolist[i]); - return; - fail_put_bio: - for (i = 0; i < (nbio-1); i++) - g_destroy_bio(biolist[i]); - fail_flush: - fast_flush_area(pending_req); - fail_response: - make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); - free_req(pending_req); + +fail_unmap_req: + xbb_unmap_req(req); + /* FALLTHROUGH */ + +fail_send_response: + xbb_send_response(xbb, req, BLKIF_RSP_ERROR); + xbb_release_req(xbb, req); + devstat_end_transaction(xbb->xbb_stats, + /*bytes*/0, + req->ds_tag_type, + req->ds_trans_type, + /*now*/NULL, + /*then*/&req->ds_t0); } +/** + * Process incoming requests from the shared communication ring in response + * to a signal on the ring's event channel. + * + * \param context Callback argument registerd during task initialization - + * the xbb_softc for this instance. + * \param pending The number of taskqueue_enqueue events that have + * occurred since this handler was last run. + */ static void -blk_req_action(void *context, int pending) +xbb_run_queue(void *context, int pending) { - blkif_t *blkif; + struct xbb_softc *xbb; + blkif_back_rings_t *rings; + RING_IDX rp; - DPRINTF("\n"); - while (!STAILQ_EMPTY(&req_sched_list)) { - blkif_back_ring_t *blk_ring; - RING_IDX rc, rp; + xbb = (struct xbb_softc *)context; + rings = &xbb->rings; - blkif = remove_from_req_schedule_list(); + /* + * Cache req_prod to avoid accessing a cache line shared + * with the frontend. + */ + rp = rings->common.sring->req_prod; - blk_ring = &blkif->ring; - rc = blk_ring->req_cons; - rp = blk_ring->sring->req_prod; - rmb(); /* Ensure we see queued requests up to 'rp'. */ + /* Ensure we see queued requests up to 'rp'. */ + rmb(); - while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) { - blkif_request_t *req; - pending_req_t *pending_req; + /** + * Run so long as there is work to consume and the generation + * of a response will not overflow the ring. + * + * @note There's a 1 to 1 relationship between requests and responses, + * so an overflow should never occur. This test is to protect + * our domain from digesting bogus data. Shouldn't we log this? + */ + while (rings->common.req_cons != rp + && RING_REQUEST_CONS_OVERFLOW(&rings->common, + rings->common.req_cons) == 0) { + blkif_request_t ring_req_storage; + blkif_request_t *ring_req; + struct xbb_xen_req *req; + RING_IDX req_ring_idx; - pending_req = alloc_req(); - if (pending_req == NULL) - goto out_of_preqs; + req = xbb_get_req(xbb); + if (req == NULL) { + /* + * Resource shortage has been recorded. + * We'll be scheduled to run once a request + * object frees up due to a completion. + */ + break; + } - req = RING_GET_REQUEST(blk_ring, rc); - blk_ring->req_cons = ++rc; /* before make_response() */ + switch (xbb->abi) { + case BLKIF_PROTOCOL_NATIVE: + ring_req = RING_GET_REQUEST(&xbb->rings.native, + rings->common.req_cons); + break; + case BLKIF_PROTOCOL_X86_32: + { + struct blkif_x86_32_request *ring_req32; - switch (req->operation) { - case BLKIF_OP_READ: - blkif->st_rd_req++; - dispatch_rw_block_io(blkif, req, pending_req); - break; - case BLKIF_OP_WRITE: - blkif->st_wr_req++; - dispatch_rw_block_io(blkif, req, pending_req); - break; - default: - blkif->st_err_req++; - DPRINTF("error: unknown block io operation [%d]\n", - req->operation); - make_response(blkif, req->id, req->operation, - BLKIF_RSP_ERROR); - free_req(pending_req); - break; + ring_req32 = RING_GET_REQUEST(&xbb->rings.x86_32, + rings->common.req_cons); + blkif_get_x86_32_req(&ring_req_storage, ring_req32); + ring_req = &ring_req_storage; + break; + } + case BLKIF_PROTOCOL_X86_64: + { + struct blkif_x86_64_request *ring_req64; + + ring_req64 = RING_GET_REQUEST(&xbb->rings.x86_64, + rings->common.req_cons); + blkif_get_x86_64_req(&ring_req_storage, ring_req64); + ring_req = &ring_req_storage; + break; + } + default: + panic("Unexpected blkif protocol ABI."); + /* NOTREACHED */ + } + + /* + * Signify that we can overwrite this request with a + * response by incrementing our consumer index. The + * response won't be generated until after we've already + * consumed all necessary data out of the version of the + * request in the ring buffer (for native mode). We + * must update the consumer index before issueing back-end + * I/O so there is no possibility that it will complete + * and a response be generated before we make room in + * the queue for that response. + */ + req_ring_idx = xbb->rings.common.req_cons; + xbb->rings.common.req_cons += + BLKIF_SEGS_TO_BLOCKS(ring_req->nr_segments); + + xbb_dispatch_io(xbb, ring_req, req, req_ring_idx); + } +} + +/** + * Interrupt handler bound to the shared ring's event channel. + * + * \param arg Callback argument registerd during event channel + * binding - the xbb_softc for this instance. + */ +static void +xbb_intr(void *arg) +{ + struct xbb_softc *xbb; + + /* Defer to kernel thread. */ + xbb = (struct xbb_softc *)arg; + taskqueue_enqueue(xbb->io_taskqueue, &xbb->io_task); +} + +/*----------------------------- Backend Handlers -----------------------------*/ +/** + * Backend handler for character device access. + * + * \param xbb Per-instance xbb configuration structure. + * \param ring_req Front-end's I/O request as pulled from the shared + * communication ring. + * \param req Allocated internal request structure. + * \param nseg The number of valid segments for this request in + * xbb->xbb_sgs. + * \param operation BIO_* I/O operation code. + * \param bio_flags Additional bio_flag data to pass to any generated + * bios (e.g. BIO_ORDERED).. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_dispatch_dev(struct xbb_softc *xbb, blkif_request_t *ring_req, + struct xbb_xen_req *req, int nseg, int operation, + int bio_flags) +{ + struct xbb_dev_data *dev_data; + struct bio *bios[XBB_MAX_SEGMENTS_PER_REQUEST]; + off_t bio_offset; + struct bio *bio; + struct xbb_sg *xbb_sg; + u_int nbio; + u_int bio_idx; + u_int seg_idx; + int error; + + dev_data = &xbb->backend.dev; + bio_offset = (off_t)ring_req->sector_number + << xbb->sector_size_shift; + error = 0; + nbio = 0; + bio_idx = 0; + + if (operation == BIO_FLUSH) { + bio = g_new_bio(); + if (unlikely(bio == NULL)) { + DPRINTF("Unable to allocate bio for BIO_FLUSH\n"); + error = ENOMEM; + return (error); + } + + bio->bio_cmd = BIO_FLUSH; + bio->bio_flags |= BIO_ORDERED; + bio->bio_dev = dev_data->cdev; + bio->bio_offset = 0; + bio->bio_data = 0; + bio->bio_done = xbb_bio_done; + bio->bio_caller1 = req; + bio->bio_pblkno = 0; + + req->pendcnt = 1; + + (*dev_data->csw->d_strategy)(bios[bio_idx]); + + return (0); + } + + for (seg_idx = 0, bio = NULL, xbb_sg = xbb->xbb_sgs; + seg_idx < nseg; + seg_idx++, xbb_sg++) { + + /* + * KVA will not be contiguous, so any additional + * I/O will need to be represented in a new bio. + */ + if ((bio != NULL) + && (xbb_sg->first_sect != 0)) { + if ((bio->bio_length & (xbb->sector_size - 1)) != 0) { + printf("%s: Discontiguous I/O request from " + "domain %d ends on non-sector " + "boundary\n", __func__, + xbb->otherend_id); + error = EINVAL; + goto fail_free_bios; } + bio = NULL; } - blkif_put(blkif); + if (bio == NULL) { + /* + * Make sure that the start of this bio is aligned + * to a device sector. + */ + if ((bio_offset & (xbb->sector_size - 1)) != 0) { + printf("%s: Misaligned I/O request from " + "domain %d\n", __func__, + xbb->otherend_id); + error = EINVAL; + goto fail_free_bios; + } + + bio = bios[nbio++] = g_new_bio(); + if (unlikely(bio == NULL)) { + error = ENOMEM; + goto fail_free_bios; + } + bio->bio_cmd = operation; + bio->bio_flags |= bio_flags; + bio->bio_dev = dev_data->cdev; + bio->bio_offset = bio_offset; + bio->bio_data = xbb_req_ioaddr(req, seg_idx, + xbb_sg->first_sect); + bio->bio_done = xbb_bio_done; + bio->bio_caller1 = req; + bio->bio_pblkno = bio_offset + >> xbb->sector_size_shift; + } + + bio->bio_length += xbb_sg->nsect << 9; + bio->bio_bcount = bio->bio_length; + bio_offset += xbb_sg->nsect << 9; + + if (xbb_sg->last_sect != (PAGE_SIZE - 512) >> 9) { + + if ((bio->bio_length & (xbb->sector_size - 1)) != 0) { + printf("%s: Discontiguous I/O request from " + "domain %d ends on non-sector " + "boundary\n", __func__, + xbb->otherend_id); + error = EINVAL; + goto fail_free_bios; + } + /* + * KVA will not be contiguous, so any additional + * I/O will need to be represented in a new bio. + */ + bio = NULL; + } } - return; + req->pendcnt = nbio; - out_of_preqs: - /* We ran out of pending req structs */ - /* Just requeue interface and wait to be rescheduled to run when one is freed */ - add_to_req_schedule_list_tail2(blkif); - blkif->st_oo_req++; + for (bio_idx = 0; bio_idx < nbio; bio_idx++) + { +#ifdef XBB_USE_BOUNCE_BUFFERS + vm_offset_t kva_offset; + + kva_offset = (vm_offset_t)bios[bio_idx]->bio_data + - (vm_offset_t)req->bounce; + if (operation == BIO_WRITE) { + memcpy(bios[bio_idx]->bio_data, + (uint8_t *)req->kva + kva_offset, + bios[bio_idx]->bio_bcount); + } +#endif + (*dev_data->csw->d_strategy)(bios[bio_idx]); + } + + return (error); + +fail_free_bios: + for (bio_idx = 0; bio_idx < (nbio-1); bio_idx++) + g_destroy_bio(bios[bio_idx]); + + return (error); } -/* Handle interrupt from a frontend */ -static void -blkback_intr(void *arg) -{ - blkif_t *blkif = arg; - DPRINTF("%x\n", (unsigned int)blkif); - add_to_req_schedule_list_tail(blkif); -} - -/* Map grant ref for ring */ +/** + * Backend handler for file access. + * + * \param xbb Per-instance xbb configuration structure. + * \param ring_req Front-end's I/O request as pulled from the shared + * communication ring. + * \param req Allocated internal request structure. + * \param nseg The number of valid segments for this request in + * xbb->xbb_sgs. + * \param operation BIO_* I/O operation code. + * \param bio_flags Additional bio_flag data to pass to any generated bios + * (e.g. BIO_ORDERED).. + * + * \return 0 for success, errno codes for failure. + */ static int -map_ring(grant_ref_t ref, domid_t dom, struct ring_ref *ring) +xbb_dispatch_file(struct xbb_softc *xbb, blkif_request_t *ring_req, + struct xbb_xen_req *req, int nseg, int operation, + int flags) { - struct gnttab_map_grant_ref op; + struct xbb_file_data *file_data; + u_int seg_idx; + struct uio xuio; + struct xbb_sg *xbb_sg; + struct iovec *xiovec; +#ifdef XBB_USE_BOUNCE_BUFFERS + void **p_vaddr; + int saved_uio_iovcnt; +#endif /* XBB_USE_BOUNCE_BUFFERS */ + int vfs_is_locked; + int error; - ring->va = kmem_alloc_nofault(kernel_map, PAGE_SIZE); - if (ring->va == 0) - return ENOMEM; + file_data = &xbb->backend.file; + error = 0; + bzero(&xuio, sizeof(xuio)); - op.host_addr = ring->va; - op.flags = GNTMAP_host_map; - op.ref = ref; - op.dom = dom; - HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1); - if (op.status) { - WPRINTF("grant table op err=%d\n", op.status); - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; - return EACCES; - } + req->pendcnt = 0; - ring->handle = op.handle; - ring->bus_addr = op.dev_bus_addr; - - return 0; -} - -/* Unmap grant ref for ring */ -static void -unmap_ring(struct ring_ref *ring) -{ - struct gnttab_unmap_grant_ref op; - - op.host_addr = ring->va; - op.dev_bus_addr = ring->bus_addr; - op.handle = ring->handle; - HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1); - if (op.status) - WPRINTF("grant table op err=%d\n", op.status); - - kmem_free(kernel_map, ring->va, PAGE_SIZE); - ring->va = 0; -} - -static int -connect_ring(blkif_t *blkif) -{ - struct xenbus_device *xdev = blkif->xdev; - blkif_sring_t *ring; - unsigned long ring_ref; - evtchn_port_t evtchn; - evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain }; - int err; - - if (blkif->ring_connected) - return 0; - - // Grab FE data and map his memory - err = xenbus_gather(NULL, xdev->otherend, - "ring-ref", "%lu", &ring_ref, - "event-channel", "%u", &evtchn, NULL); - if (err) { - xenbus_dev_fatal(xdev, err, - "reading %s/ring-ref and event-channel", - xdev->otherend); - return err; - } - - err = map_ring(ring_ref, blkif->domid, &blkif->rr); - if (err) { - xenbus_dev_fatal(xdev, err, "mapping ring"); - return err; - } - ring = (blkif_sring_t *)blkif->rr.va; - BACK_RING_INIT(&blkif->ring, ring, PAGE_SIZE); - - op.u.bind_interdomain.remote_dom = blkif->domid; - op.u.bind_interdomain.remote_port = evtchn; - err = HYPERVISOR_event_channel_op(&op); - if (err) { - unmap_ring(&blkif->rr); - xenbus_dev_fatal(xdev, err, "binding event channel"); - return err; - } - blkif->evtchn = op.u.bind_interdomain.local_port; - - /* bind evtchn to irq handler */ - blkif->irq = - bind_evtchn_to_irqhandler(blkif->evtchn, "blkback", - blkback_intr, blkif, INTR_TYPE_NET|INTR_MPSAFE, &blkif->irq_cookie); - - blkif->ring_connected = 1; - - DPRINTF("%x rings connected! evtchn=%d irq=%d\n", - (unsigned int)blkif, blkif->evtchn, blkif->irq); - - return 0; -} - -static void -disconnect_ring(blkif_t *blkif) -{ - DPRINTF("\n"); - - if (blkif->ring_connected) { - unbind_from_irqhandler(blkif->irq, blkif->irq_cookie); - blkif->irq = 0; - unmap_ring(&blkif->rr); - blkif->ring_connected = 0; - } -} - -static void -connect(blkif_t *blkif) -{ - struct xenbus_transaction *xbt; - struct xenbus_device *xdev = blkif->xdev; - int err; - - if (!blkif->ring_connected || - blkif->vn == NULL || - blkif->state == XenbusStateConnected) - return; - - DPRINTF("%s\n", xdev->otherend); - - /* Supply the information about the device the frontend needs */ -again: - xbt = xenbus_transaction_start(); - if (IS_ERR(xbt)) { - xenbus_dev_fatal(xdev, PTR_ERR(xbt), - "Error writing configuration for backend " - "(start transaction)"); - return; - } - - err = xenbus_printf(xbt, xdev->nodename, "sectors", "%u", - blkif->media_num_sectors); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/sectors", - xdev->nodename); - goto abort; - } - - err = xenbus_printf(xbt, xdev->nodename, "info", "%u", - blkif->read_only ? VDISK_READONLY : 0); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/info", - xdev->nodename); - goto abort; - } - err = xenbus_printf(xbt, xdev->nodename, "sector-size", "%u", - blkif->sector_size); - if (err) { - xenbus_dev_fatal(xdev, err, "writing %s/sector-size", - xdev->nodename); - goto abort; - } - - err = xenbus_transaction_end(xbt, 0); - if (err == -EAGAIN) - goto again; - if (err) - xenbus_dev_fatal(xdev, err, "ending transaction"); - - err = xenbus_switch_state(xdev, NULL, XenbusStateConnected); - if (err) - xenbus_dev_fatal(xdev, err, "switching to Connected state", - xdev->nodename); - - blkif->state = XenbusStateConnected; - - return; - - abort: - xenbus_transaction_end(xbt, 1); -} - -static int -blkback_probe(struct xenbus_device *xdev, const struct xenbus_device_id *id) -{ - int err; - char *p, *mode = NULL, *type = NULL, *params = NULL; - long handle; - - DPRINTF("node=%s\n", xdev->nodename); - - p = strrchr(xdev->otherend, '/') + 1; - handle = strtoul(p, NULL, 0); - - mode = xenbus_read(NULL, xdev->nodename, "mode", NULL); - if (IS_ERR(mode)) { - xenbus_dev_fatal(xdev, PTR_ERR(mode), "reading mode"); - err = PTR_ERR(mode); - goto error; - } - - type = xenbus_read(NULL, xdev->nodename, "type", NULL); - if (IS_ERR(type)) { - xenbus_dev_fatal(xdev, PTR_ERR(type), "reading type"); - err = PTR_ERR(type); - goto error; - } - - params = xenbus_read(NULL, xdev->nodename, "params", NULL); - if (IS_ERR(type)) { - xenbus_dev_fatal(xdev, PTR_ERR(params), "reading params"); - err = PTR_ERR(params); - goto error; - } - - err = blkif_create(xdev, handle, mode, type, params); - if (err) { - xenbus_dev_fatal(xdev, err, "creating blkif"); - goto error; - } - - err = vbd_add_dev(xdev); - if (err) { - blkif_put((blkif_t *)xdev->data); - xenbus_dev_fatal(xdev, err, "adding vbd device"); - } - - return err; - - error: - if (mode) - free(mode, M_DEVBUF); - if (type) - free(type, M_DEVBUF); - if (params) - free(params, M_DEVBUF); - return err; -} - -static int -blkback_remove(struct xenbus_device *xdev) -{ - blkif_t *blkif = xdev->data; - device_t ndev; - - DPRINTF("node=%s\n", xdev->nodename); - - blkif->state = XenbusStateClosing; - - if ((ndev = blkif->ndev)) { - blkif->ndev = NULL; - mtx_lock(&Giant); - device_detach(ndev); - mtx_unlock(&Giant); - } - - xdev->data = NULL; - blkif->xdev = NULL; - blkif_put(blkif); - - return 0; -} - -static int -blkback_resume(struct xenbus_device *xdev) -{ - DPRINTF("node=%s\n", xdev->nodename); - return 0; -} - -static void -frontend_changed(struct xenbus_device *xdev, - XenbusState frontend_state) -{ - blkif_t *blkif = xdev->data; - - DPRINTF("state=%d\n", frontend_state); - - blkif->frontend_state = frontend_state; - - switch (frontend_state) { - case XenbusStateInitialising: + switch (operation) { + case BIO_READ: + xuio.uio_rw = UIO_READ; break; - case XenbusStateInitialised: - case XenbusStateConnected: - connect_ring(blkif); - connect(blkif); + case BIO_WRITE: + xuio.uio_rw = UIO_WRITE; break; - case XenbusStateClosing: - xenbus_switch_state(xdev, NULL, XenbusStateClosing); + case BIO_FLUSH: { + struct mount *mountpoint; + + vfs_is_locked = VFS_LOCK_GIANT(xbb->vn->v_mount); + + (void) vn_start_write(xbb->vn, &mountpoint, V_WAIT); + + vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY); + error = VOP_FSYNC(xbb->vn, MNT_WAIT, curthread); + VOP_UNLOCK(xbb->vn, 0); + + vn_finished_write(mountpoint); + + VFS_UNLOCK_GIANT(vfs_is_locked); + + goto bailout_send_response; + /* NOTREACHED */ + } + default: + panic("invalid operation %d", operation); + /* NOTREACHED */ + } + xuio.uio_offset = (vm_offset_t)ring_req->sector_number + << xbb->sector_size_shift; + + xuio.uio_segflg = UIO_SYSSPACE; + xuio.uio_iov = file_data->xiovecs; + xuio.uio_iovcnt = 0; + + for (seg_idx = 0, xiovec = NULL, xbb_sg = xbb->xbb_sgs; + seg_idx < nseg; seg_idx++, xbb_sg++) { + + /* + * If the first sector is not 0, the KVA will not be + * contiguous and we'll need to go on to another segment. + */ + if (xbb_sg->first_sect != 0) + xiovec = NULL; + + if (xiovec == NULL) { + xiovec = &file_data->xiovecs[xuio.uio_iovcnt]; + xiovec->iov_base = xbb_req_ioaddr(req, seg_idx, + xbb_sg->first_sect); +#ifdef XBB_USE_BOUNCE_BUFFERS + /* + * Store the address of the incoming buffer at this + * particular offset as well, so we can do the copy + * later without having to do more work to + * recalculate this address. + */ + p_vaddr = &file_data->xiovecs_vaddr[xuio.uio_iovcnt]; + *p_vaddr = xbb_req_vaddr(req, seg_idx, + xbb_sg->first_sect); +#endif /* XBB_USE_BOUNCE_BUFFERS */ + xiovec->iov_len = 0; + xuio.uio_iovcnt++; + } + + xiovec->iov_len += xbb_sg->nsect << 9; + + xuio.uio_resid += xbb_sg->nsect << 9; + + /* + * If the last sector is not the full page size count, + * the next segment will not be contiguous in KVA and we + * need a new iovec. + */ + if (xbb_sg->last_sect != (PAGE_SIZE - 512) >> 9) + xiovec = NULL; + } + + xuio.uio_td = curthread; + +#ifdef XBB_USE_BOUNCE_BUFFERS + saved_uio_iovcnt = xuio.uio_iovcnt; + + if (operation == BIO_WRITE) { + /* Copy the write data to the local buffer. */ + for (seg_idx = 0, p_vaddr = file_data->xiovecs_vaddr, + xiovec = xuio.uio_iov; seg_idx < xuio.uio_iovcnt; + seg_idx++, xiovec++, p_vaddr++) { + + memcpy(xiovec->iov_base, *p_vaddr, xiovec->iov_len); + } + } else { + /* + * We only need to save off the iovecs in the case of a + * read, because the copy for the read happens after the + * VOP_READ(). (The uio will get modified in that call + * sequence.) + */ + memcpy(file_data->saved_xiovecs, xuio.uio_iov, + xuio.uio_iovcnt * sizeof(xuio.uio_iov[0])); + } +#endif /* XBB_USE_BOUNCE_BUFFERS */ + + vfs_is_locked = VFS_LOCK_GIANT(xbb->vn->v_mount); + switch (operation) { + case BIO_READ: + + vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY); + + /* + * UFS pays attention to IO_DIRECT for reads. If the + * DIRECTIO option is configured into the kernel, it calls + * ffs_rawread(). But that only works for single-segment + * uios with user space addresses. In our case, with a + * kernel uio, it still reads into the buffer cache, but it + * will just try to release the buffer from the cache later + * on in ffs_read(). + * + * ZFS does not pay attention to IO_DIRECT for reads. + * + * UFS does not pay attention to IO_SYNC for reads. + * + * ZFS pays attention to IO_SYNC (which translates into the + * Solaris define FRSYNC for zfs_read()) for reads. It + * attempts to sync the file before reading. + * + * So, to attempt to provide some barrier semantics in the + * BIO_ORDERED case, set both IO_DIRECT and IO_SYNC. + */ + error = VOP_READ(xbb->vn, &xuio, (flags & BIO_ORDERED) ? + (IO_DIRECT|IO_SYNC) : 0, file_data->cred); + + VOP_UNLOCK(xbb->vn, 0); break; - case XenbusStateClosed: - xenbus_remove_device(xdev); - break; - case XenbusStateUnknown: - case XenbusStateInitWait: - xenbus_dev_fatal(xdev, EINVAL, "saw state %d at frontend", - frontend_state); + case BIO_WRITE: { + struct mount *mountpoint; + + (void)vn_start_write(xbb->vn, &mountpoint, V_WAIT); + + vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY); + + /* + * UFS pays attention to IO_DIRECT for writes. The write + * is done asynchronously. (Normally the write would just + * get put into cache. + * + * UFS pays attention to IO_SYNC for writes. It will + * attempt to write the buffer out synchronously if that + * flag is set. + * + * ZFS does not pay attention to IO_DIRECT for writes. + * + * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) + * for writes. It will flush the transaction from the + * cache before returning. + * + * So if we've got the BIO_ORDERED flag set, we want + * IO_SYNC in either the UFS or ZFS case. + */ + error = VOP_WRITE(xbb->vn, &xuio, (flags & BIO_ORDERED) ? + IO_SYNC : 0, file_data->cred); + VOP_UNLOCK(xbb->vn, 0); + + vn_finished_write(mountpoint); + break; } + default: + panic("invalid operation %d", operation); + /* NOTREACHED */ + } + VFS_UNLOCK_GIANT(vfs_is_locked); + +#ifdef XBB_USE_BOUNCE_BUFFERS + /* We only need to copy here for read operations */ + if (operation == BIO_READ) { + + for (seg_idx = 0, p_vaddr = file_data->xiovecs_vaddr, + xiovec = file_data->saved_xiovecs; + seg_idx < saved_uio_iovcnt; seg_idx++, + xiovec++, p_vaddr++) { + + /* + * Note that we have to use the copy of the + * io vector we made above. uiomove() modifies + * the uio and its referenced vector as uiomove + * performs the copy, so we can't rely on any + * state from the original uio. + */ + memcpy(*p_vaddr, xiovec->iov_base, xiovec->iov_len); + } + } +#endif /* XBB_USE_BOUNCE_BUFFERS */ + +bailout_send_response: + + /* + * All I/O is already done, send the response. A lock is not + * necessary here because we're single threaded, and therefore the + * only context accessing this request right now. If that changes, + * we may need some locking here. + */ + xbb_unmap_req(req); + xbb_send_response(xbb, req, (error == 0) ? BLKIF_RSP_OKAY : + BLKIF_RSP_ERROR); + devstat_end_transaction(xbb->xbb_stats, + /*bytes*/error == 0 ? req->nr_512b_sectors << 9 + : 0, + req->ds_tag_type, + req->ds_trans_type, + /*now*/NULL, + /*then*/&req->ds_t0); + xbb_release_req(xbb, req); + + return (0); } -/* ** Driver registration ** */ - -static struct xenbus_device_id blkback_ids[] = { - { "vbd" }, - { "" } -}; - -static struct xenbus_driver blkback = { - .name = "blkback", - .ids = blkback_ids, - .probe = blkback_probe, - .remove = blkback_remove, - .resume = blkback_resume, - .otherend_changed = frontend_changed, -}; - +/*--------------------------- Backend Configuration --------------------------*/ +/** + * Close and cleanup any backend device/file specific state for this + * block back instance. + * + * \param xbb Per-instance xbb configuration structure. + */ static void -blkback_init(void *unused) +xbb_close_backend(struct xbb_softc *xbb) { - int i; - - TASK_INIT(&blk_req_task, 0, blk_req_action, NULL); - mtx_init(&req_sched_list_lock, "blk_req_sched_lock", "blkback req sched lock", MTX_DEF); - - mtx_init(&pending_free_lock, "blk_pending_req_ock", "blkback pending request lock", MTX_DEF); - - mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST; - pending_reqs = malloc(sizeof(pending_reqs[0]) * - blkif_reqs, M_DEVBUF, M_ZERO|M_NOWAIT); - pending_grant_handles = malloc(sizeof(pending_grant_handles[0]) * - mmap_pages, M_DEVBUF, M_NOWAIT); - pending_vaddrs = malloc(sizeof(pending_vaddrs[0]) * - mmap_pages, M_DEVBUF, M_NOWAIT); - mmap_vstart = alloc_empty_page_range(mmap_pages); - if (!pending_reqs || !pending_grant_handles || !pending_vaddrs || !mmap_vstart) { - if (pending_reqs) - free(pending_reqs, M_DEVBUF); - if (pending_grant_handles) - free(pending_grant_handles, M_DEVBUF); - if (pending_vaddrs) - free(pending_vaddrs, M_DEVBUF); - WPRINTF("out of memory\n"); - return; - } - - for (i = 0; i < mmap_pages; i++) { - pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT); - pending_grant_handles[i] = BLKBACK_INVALID_HANDLE; - } - - for (i = 0; i < blkif_reqs; i++) { - STAILQ_INSERT_TAIL(&pending_free, &pending_reqs[i], free_list); - } - - DPRINTF("registering %s\n", blkback.name); - xenbus_register_backend(&blkback); -} - -SYSINIT(xbbedev, SI_SUB_PSEUDO, SI_ORDER_ANY, blkback_init, NULL) - -static void -close_device(blkif_t *blkif) -{ - DPRINTF("closing dev=%s\n", blkif->dev_name); - if (blkif->vn) { + DROP_GIANT(); + DPRINTF("closing dev=%s\n", xbb->dev_name); + if (xbb->vn) { int flags = FREAD; + int vfs_is_locked = 0; - if (!blkif->read_only) + if ((xbb->flags & XBBF_READ_ONLY) == 0) flags |= FWRITE; - if (blkif->csw) { - dev_relthread(blkif->cdev); - blkif->csw = NULL; + switch (xbb->device_type) { + case XBB_TYPE_DISK: + if (xbb->backend.dev.csw) { + dev_relthread(xbb->backend.dev.cdev, + xbb->backend.dev.dev_ref); + xbb->backend.dev.csw = NULL; + xbb->backend.dev.cdev = NULL; + } + break; + case XBB_TYPE_FILE: + vfs_is_locked = VFS_LOCK_GIANT(xbb->vn->v_mount); + break; + case XBB_TYPE_NONE: + default: + panic("Unexpected backend type."); + break; } - (void)vn_close(blkif->vn, flags, NOCRED, curthread); - blkif->vn = NULL; + (void)vn_close(xbb->vn, flags, NOCRED, curthread); + xbb->vn = NULL; + + switch (xbb->device_type) { + case XBB_TYPE_DISK: + break; + case XBB_TYPE_FILE: + VFS_UNLOCK_GIANT(vfs_is_locked); + if (xbb->backend.file.cred != NULL) { + crfree(xbb->backend.file.cred); + xbb->backend.file.cred = NULL; + } + break; + case XBB_TYPE_NONE: + default: + panic("Unexpected backend type."); + break; + } } + PICKUP_GIANT(); } +/** + * Open a character device to be used for backend I/O. + * + * \param xbb Per-instance xbb configuration structure. + * + * \return 0 for success, errno codes for failure. + */ static int -open_device(blkif_t *blkif) +xbb_open_dev(struct xbb_softc *xbb) +{ + struct vattr vattr; + struct cdev *dev; + struct cdevsw *devsw; + int error; + + xbb->device_type = XBB_TYPE_DISK; + xbb->dispatch_io = xbb_dispatch_dev; + xbb->backend.dev.cdev = xbb->vn->v_rdev; + xbb->backend.dev.csw = dev_refthread(xbb->backend.dev.cdev, + &xbb->backend.dev.dev_ref); + if (xbb->backend.dev.csw == NULL) + panic("Unable to retrieve device switch"); + + error = VOP_GETATTR(xbb->vn, &vattr, NOCRED); + if (error) { + xenbus_dev_fatal(xbb->dev, error, "error getting " + "vnode attributes for device %s", + xbb->dev_name); + return (error); + } + + + dev = xbb->vn->v_rdev; + devsw = dev->si_devsw; + if (!devsw->d_ioctl) { + xenbus_dev_fatal(xbb->dev, ENODEV, "no d_ioctl for " + "device %s!", xbb->dev_name); + return (ENODEV); + } + + error = devsw->d_ioctl(dev, DIOCGSECTORSIZE, + (caddr_t)&xbb->sector_size, FREAD, + curthread); + if (error) { + xenbus_dev_fatal(xbb->dev, error, + "error calling ioctl DIOCGSECTORSIZE " + "for device %s", xbb->dev_name); + return (error); + } + + error = devsw->d_ioctl(dev, DIOCGMEDIASIZE, + (caddr_t)&xbb->media_size, FREAD, + curthread); + if (error) { + xenbus_dev_fatal(xbb->dev, error, + "error calling ioctl DIOCGMEDIASIZE " + "for device %s", xbb->dev_name); + return (error); + } + + return (0); +} + +/** + * Open a file to be used for backend I/O. + * + * \param xbb Per-instance xbb configuration structure. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_open_file(struct xbb_softc *xbb) +{ + struct xbb_file_data *file_data; + struct vattr vattr; + int error; + + file_data = &xbb->backend.file; + xbb->device_type = XBB_TYPE_FILE; + xbb->dispatch_io = xbb_dispatch_file; + error = VOP_GETATTR(xbb->vn, &vattr, curthread->td_ucred); + if (error != 0) { + xenbus_dev_fatal(xbb->dev, error, + "error calling VOP_GETATTR()" + "for file %s", xbb->dev_name); + return (error); + } + + /* + * Verify that we have the ability to upgrade to exclusive + * access on this file so we can trap errors at open instead + * of reporting them during first access. + */ + if (VOP_ISLOCKED(xbb->vn) != LK_EXCLUSIVE) { + vn_lock(xbb->vn, LK_UPGRADE | LK_RETRY); + if (xbb->vn->v_iflag & VI_DOOMED) { + error = EBADF; + xenbus_dev_fatal(xbb->dev, error, + "error locking file %s", + xbb->dev_name); + + return (error); + } + } + + file_data->cred = crhold(curthread->td_ucred); + xbb->media_size = vattr.va_size; + + /* + * XXX KDM vattr.va_blocksize may be larger than 512 bytes here. + * With ZFS, it is 131072 bytes. Block sizes that large don't work + * with disklabel and UFS on FreeBSD at least. Large block sizes + * may not work with other OSes as well. So just export a sector + * size of 512 bytes, which should work with any OS or + * application. Since our backing is a file, any block size will + * work fine for the backing store. + */ +#if 0 + xbb->sector_size = vattr.va_blocksize; +#endif + xbb->sector_size = 512; + + /* + * Sanity check. The media size has to be at least one + * sector long. + */ + if (xbb->media_size < xbb->sector_size) { + error = EINVAL; + xenbus_dev_fatal(xbb->dev, error, + "file %s size %ju < block size %u", + xbb->dev_name, + (uintmax_t)xbb->media_size, + xbb->sector_size); + } + return (error); +} + +/** + * Open the backend provider for this connection. + * + * \param xbb Per-instance xbb configuration structure. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_open_backend(struct xbb_softc *xbb) { struct nameidata nd; - struct vattr vattr; - struct cdev *dev; - struct cdevsw *devsw; - int flags = FREAD, err = 0; + int flags; + int error; + int vfs_is_locked; - DPRINTF("opening dev=%s\n", blkif->dev_name); + flags = FREAD; + error = 0; - if (!blkif->read_only) + DPRINTF("opening dev=%s\n", xbb->dev_name); + + if ((xbb->flags & XBBF_READ_ONLY) == 0) flags |= FWRITE; if (!curthread->td_proc->p_fd->fd_cdir) { @@ -1066,284 +1930,1045 @@ open_device(blkif_t *blkif) } again: - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, blkif->dev_name, curthread); - err = vn_open(&nd, &flags, 0, -1); - if (err) { - if (blkif->dev_name[0] != '/') { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, xbb->dev_name, curthread); + error = vn_open(&nd, &flags, 0, NULL); + if (error) { + /* + * This is the only reasonable guess we can make as far as + * path if the user doesn't give us a fully qualified path. + * If they want to specify a file, they need to specify the + * full path. + */ + if (xbb->dev_name[0] != '/') { char *dev_path = "/dev/"; char *dev_name; /* Try adding device path at beginning of name */ - dev_name = malloc(strlen(blkif->dev_name) + strlen(dev_path) + 1, M_DEVBUF, M_NOWAIT); + dev_name = malloc(strlen(xbb->dev_name) + + strlen(dev_path) + 1, + M_XENBLOCKBACK, M_NOWAIT); if (dev_name) { - sprintf(dev_name, "%s%s", dev_path, blkif->dev_name); - free(blkif->dev_name, M_DEVBUF); - blkif->dev_name = dev_name; + sprintf(dev_name, "%s%s", dev_path, + xbb->dev_name); + free(xbb->dev_name, M_XENBLOCKBACK); + xbb->dev_name = dev_name; goto again; } } - xenbus_dev_fatal(blkif->xdev, err, "error opening device %s", blkif->dev_name); - return err; + xenbus_dev_fatal(xbb->dev, error, "error opening device %s", + xbb->dev_name); + return (error); } + + vfs_is_locked = NDHASGIANT(&nd); + NDFREE(&nd, NDF_ONLY_PNBUF); - blkif->vn = nd.ni_vp; + xbb->vn = nd.ni_vp; - /* We only support disks for now */ - if (!vn_isdisk(blkif->vn, &err)) { - xenbus_dev_fatal(blkif->xdev, err, "device %s is not a disk", blkif->dev_name); - VOP_UNLOCK(blkif->vn, 0, curthread); - goto error; + /* We only support disks and files. */ + if (vn_isdisk(xbb->vn, &error)) { + error = xbb_open_dev(xbb); + } else if (xbb->vn->v_type == VREG) { + error = xbb_open_file(xbb); + } else { + error = EINVAL; + xenbus_dev_fatal(xbb->dev, error, "%s is not a disk " + "or file", xbb->dev_name); + } + VOP_UNLOCK(xbb->vn, 0); + VFS_UNLOCK_GIANT(vfs_is_locked); + + if (error != 0) { + xbb_close_backend(xbb); + return (error); } - blkif->cdev = blkif->vn->v_rdev; - blkif->csw = dev_refthread(blkif->cdev); - PANIC_IF(blkif->csw == NULL); + xbb->sector_size_shift = fls(xbb->sector_size) - 1; + xbb->media_num_sectors = xbb->media_size >> xbb->sector_size_shift; - err = VOP_GETATTR(blkif->vn, &vattr, NOCRED); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error getting vnode attributes for device %s", blkif->dev_name); - VOP_UNLOCK(blkif->vn, 0, curthread); - goto error; + DPRINTF("opened %s=%s sector_size=%u media_size=%" PRId64 "\n", + (xbb->device_type == XBB_TYPE_DISK) ? "dev" : "file", + xbb->dev_name, xbb->sector_size, xbb->media_size); + + return (0); +} + +/*------------------------ Inter-Domain Communication ------------------------*/ +/** + * Cleanup all inter-domain communication mechanisms. + * + * \param xbb Per-instance xbb configuration structure. + */ +static void +xbb_disconnect(struct xbb_softc *xbb) +{ + struct gnttab_unmap_grant_ref ops[XBB_MAX_RING_PAGES]; + struct gnttab_unmap_grant_ref *op; + u_int ring_idx; + int error; + + DPRINTF("\n"); + + if ((xbb->flags & XBBF_RING_CONNECTED) == 0) + return; + + if (xbb->irq != 0) { + unbind_from_irqhandler(xbb->irq); + xbb->irq = 0; } - VOP_UNLOCK(blkif->vn, 0, curthread); + for (ring_idx = 0, op = ops; + ring_idx < xbb->ring_config.ring_pages; + ring_idx++, op++) { - dev = blkif->vn->v_rdev; - devsw = dev->si_devsw; - if (!devsw->d_ioctl) { - err = ENODEV; - xenbus_dev_fatal(blkif->xdev, err, - "no d_ioctl for device %s!", blkif->dev_name); - goto error; + op->host_addr = xbb->ring_config.gnt_addr + + (ring_idx * PAGE_SIZE); + op->dev_bus_addr = xbb->ring_config.bus_addr[ring_idx]; + op->handle = xbb->ring_config.handle[ring_idx]; } - err = (*devsw->d_ioctl)(dev, DIOCGSECTORSIZE, (caddr_t)&blkif->sector_size, FREAD, curthread); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error calling ioctl DIOCGSECTORSIZE for device %s", blkif->dev_name); - goto error; + error = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, ops, + xbb->ring_config.ring_pages); + if (error != 0) + panic("Grant table op failed (%d)", error); + + xbb->flags &= ~XBBF_RING_CONNECTED; +} + +/** + * Map shared memory ring into domain local address space, initialize + * ring control structures, and bind an interrupt to the event channel + * used to notify us of ring changes. + * + * \param xbb Per-instance xbb configuration structure. + */ +static int +xbb_connect_ring(struct xbb_softc *xbb) +{ + struct gnttab_map_grant_ref gnts[XBB_MAX_RING_PAGES]; + struct gnttab_map_grant_ref *gnt; + u_int ring_idx; + int error; + + if ((xbb->flags & XBBF_RING_CONNECTED) != 0) + return (0); + + /* + * Kva for our ring is at the tail of the region of kva allocated + * by xbb_alloc_communication_mem(). + */ + xbb->ring_config.va = xbb->kva + + (xbb->kva_size + - (xbb->ring_config.ring_pages * PAGE_SIZE)); + xbb->ring_config.gnt_addr = xbb->gnt_base_addr + + (xbb->kva_size + - (xbb->ring_config.ring_pages * PAGE_SIZE)); + + for (ring_idx = 0, gnt = gnts; + ring_idx < xbb->ring_config.ring_pages; + ring_idx++, gnt++) { + + gnt->host_addr = xbb->ring_config.gnt_addr + + (ring_idx * PAGE_SIZE); + gnt->flags = GNTMAP_host_map; + gnt->ref = xbb->ring_config.ring_ref[ring_idx]; + gnt->dom = xbb->otherend_id; } - blkif->sector_size_shift = fls(blkif->sector_size) - 1; - err = (*devsw->d_ioctl)(dev, DIOCGMEDIASIZE, (caddr_t)&blkif->media_size, FREAD, curthread); - if (err) { - xenbus_dev_fatal(blkif->xdev, err, - "error calling ioctl DIOCGMEDIASIZE for device %s", blkif->dev_name); - goto error; + error = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, gnts, + xbb->ring_config.ring_pages); + if (error) + panic("blkback: Ring page grant table op failed (%d)", error); + + for (ring_idx = 0, gnt = gnts; + ring_idx < xbb->ring_config.ring_pages; + ring_idx++, gnt++) { + if (gnt->status != 0) { + xbb->ring_config.va = 0; + xenbus_dev_fatal(xbb->dev, EACCES, + "Ring shared page mapping failed. " + "Status %d.", gnt->status); + return (EACCES); + } + xbb->ring_config.handle[ring_idx] = gnt->handle; + xbb->ring_config.bus_addr[ring_idx] = gnt->dev_bus_addr; } - blkif->media_num_sectors = blkif->media_size >> blkif->sector_size_shift; - blkif->major = major(vattr.va_rdev); - blkif->minor = minor(vattr.va_rdev); + /* Initialize the ring based on ABI. */ + switch (xbb->abi) { + case BLKIF_PROTOCOL_NATIVE: + { + blkif_sring_t *sring; + sring = (blkif_sring_t *)xbb->ring_config.va; + BACK_RING_INIT(&xbb->rings.native, sring, + xbb->ring_config.ring_pages * PAGE_SIZE); + break; + } + case BLKIF_PROTOCOL_X86_32: + { + blkif_x86_32_sring_t *sring_x86_32; + sring_x86_32 = (blkif_x86_32_sring_t *)xbb->ring_config.va; + BACK_RING_INIT(&xbb->rings.x86_32, sring_x86_32, + xbb->ring_config.ring_pages * PAGE_SIZE); + break; + } + case BLKIF_PROTOCOL_X86_64: + { + blkif_x86_64_sring_t *sring_x86_64; + sring_x86_64 = (blkif_x86_64_sring_t *)xbb->ring_config.va; + BACK_RING_INIT(&xbb->rings.x86_64, sring_x86_64, + xbb->ring_config.ring_pages * PAGE_SIZE); + break; + } + default: + panic("Unexpected blkif protocol ABI."); + } - DPRINTF("opened dev=%s major=%d minor=%d sector_size=%u media_size=%lld\n", - blkif->dev_name, blkif->major, blkif->minor, blkif->sector_size, blkif->media_size); + xbb->flags |= XBBF_RING_CONNECTED; + + error = + bind_interdomain_evtchn_to_irqhandler(xbb->otherend_id, + xbb->ring_config.evtchn, + device_get_nameunit(xbb->dev), + xbb_intr, /*arg*/xbb, + INTR_TYPE_BIO | INTR_MPSAFE, + &xbb->irq); + if (error) { + xbb_disconnect(xbb); + xenbus_dev_fatal(xbb->dev, error, "binding event channel"); + return (error); + } + + DPRINTF("rings connected!\n"); return 0; - - error: - close_device(blkif); - return err; } +/** + * Size KVA and pseudo-physical address allocations based on negotiated + * values for the size and number of I/O requests, and the size of our + * communication ring. + * + * \param xbb Per-instance xbb configuration structure. + * + * These address spaces are used to dynamically map pages in the + * front-end's domain into our own. + */ static int -vbd_add_dev(struct xenbus_device *xdev) +xbb_alloc_communication_mem(struct xbb_softc *xbb) { - blkif_t *blkif = xdev->data; - device_t nexus, ndev; - devclass_t dc; - int err = 0; - - mtx_lock(&Giant); - - /* We will add a vbd device as a child of nexus0 (for now) */ - if (!(dc = devclass_find("nexus")) || - !(nexus = devclass_get_device(dc, 0))) { - WPRINTF("could not find nexus0!\n"); - err = ENOENT; - goto done; + xbb->kva_size = (xbb->ring_config.ring_pages + + (xbb->max_requests * xbb->max_request_segments)) + * PAGE_SIZE; +#ifndef XENHVM + xbb->kva = kmem_alloc_nofault(kernel_map, xbb->kva_size); + if (xbb->kva == 0) + return (ENOMEM); + xbb->gnt_base_addr = xbb->kva; +#else /* XENHVM */ + /* + * Reserve a range of pseudo physical memory that we can map + * into kva. These pages will only be backed by machine + * pages ("real memory") during the lifetime of front-end requests + * via grant table operations. + */ + xbb->pseudo_phys_res_id = 0; + xbb->pseudo_phys_res = bus_alloc_resource(xbb->dev, SYS_RES_MEMORY, + &xbb->pseudo_phys_res_id, + 0, ~0, xbb->kva_size, + RF_ACTIVE); + if (xbb->pseudo_phys_res == NULL) { + xbb->kva = 0; + return (ENOMEM); } - - - /* Create a newbus device representing the vbd */ - ndev = BUS_ADD_CHILD(nexus, 0, "vbd", blkif->handle); - if (!ndev) { - WPRINTF("could not create newbus device vbd%d!\n", blkif->handle); - err = EFAULT; - goto done; - } - - blkif_get(blkif); - device_set_ivars(ndev, blkif); - blkif->ndev = ndev; - - device_probe_and_attach(ndev); - - done: - - mtx_unlock(&Giant); - - return err; + xbb->kva = (vm_offset_t)rman_get_virtual(xbb->pseudo_phys_res); + xbb->gnt_base_addr = rman_get_start(xbb->pseudo_phys_res); +#endif /* XENHVM */ + return (0); } -enum { - VBD_SYSCTL_DOMID, - VBD_SYSCTL_ST_RD_REQ, - VBD_SYSCTL_ST_WR_REQ, - VBD_SYSCTL_ST_OO_REQ, - VBD_SYSCTL_ST_ERR_REQ, - VBD_SYSCTL_RING, -}; - -static char * -vbd_sysctl_ring_info(blkif_t *blkif, int cmd) +/** + * Free dynamically allocated KVA or pseudo-physical address allocations. + * + * \param xbb Per-instance xbb configuration structure. + */ +static void +xbb_free_communication_mem(struct xbb_softc *xbb) { - char *buf = malloc(256, M_DEVBUF, M_WAITOK); - if (buf) { - if (!blkif->ring_connected) - sprintf(buf, "ring not connected\n"); - else { - blkif_back_ring_t *ring = &blkif->ring; - sprintf(buf, "nr_ents=%x req_cons=%x" - " req_prod=%x req_event=%x" - " rsp_prod=%x rsp_event=%x", - ring->nr_ents, ring->req_cons, - ring->sring->req_prod, ring->sring->req_event, - ring->sring->rsp_prod, ring->sring->rsp_event); + if (xbb->kva != 0) { +#ifndef XENHVM + kmem_free(kernel_map, xbb->kva, xbb->kva_size); +#else + if (xbb->pseudo_phys_res != NULL) { + bus_release_resource(xbb->dev, SYS_RES_MEMORY, + xbb->pseudo_phys_res_id, + xbb->pseudo_phys_res); + xbb->pseudo_phys_res = NULL; } +#endif } - return buf; + xbb->kva = 0; + xbb->gnt_base_addr = 0; } +/** + * Collect front-end information from the XenStore. + * + * \param xbb Per-instance xbb configuration structure. + */ static int -vbd_sysctl_handler(SYSCTL_HANDLER_ARGS) +xbb_collect_frontend_info(struct xbb_softc *xbb) { - device_t dev = (device_t)arg1; - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); - const char *value; - char *buf = NULL; - int err; + char protocol_abi[64]; + const char *otherend_path; + int error; + u_int ring_idx; - switch (arg2) { - case VBD_SYSCTL_DOMID: - return sysctl_handle_int(oidp, NULL, blkif->domid, req); - case VBD_SYSCTL_ST_RD_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_rd_req, req); - case VBD_SYSCTL_ST_WR_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_wr_req, req); - case VBD_SYSCTL_ST_OO_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_oo_req, req); - case VBD_SYSCTL_ST_ERR_REQ: - return sysctl_handle_int(oidp, NULL, blkif->st_err_req, req); - case VBD_SYSCTL_RING: - value = buf = vbd_sysctl_ring_info(blkif, arg2); - break; - default: + otherend_path = xenbus_get_otherend_path(xbb->dev); + + /* + * Mandatory data (used in all versions of the protocol) first. + */ + error = xs_gather(XST_NIL, otherend_path, + "ring-ref", "%" PRIu32, + &xbb->ring_config.ring_ref[0], + "event-channel", "%" PRIu32, + &xbb->ring_config.evtchn, + NULL); + if (error != 0) { + xenbus_dev_fatal(xbb->dev, error, + "Unable to retrieve ring information from " + "frontend %s. Unable to connect.", + xenbus_get_otherend_path(xbb->dev)); + return (error); + } + + /* + * These fields are initialized to legacy protocol defaults + * so we only need to fail if reading the updated value succeeds + * and the new value is outside of its allowed range. + * + * \note xs_gather() returns on the first encountered error, so + * we must use independant calls in order to guarantee + * we don't miss information in a sparsly populated front-end + * tree. + */ + (void)xs_scanf(XST_NIL, otherend_path, + "ring-pages", NULL, "%" PRIu32, + &xbb->ring_config.ring_pages); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-requests", NULL, "%" PRIu32, + &xbb->max_requests); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-request-segments", NULL, "%" PRIu32, + &xbb->max_request_segments); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-request-size", NULL, "%" PRIu32, + &xbb->max_request_size); + + if (xbb->ring_config.ring_pages > XBB_MAX_RING_PAGES) { + xenbus_dev_fatal(xbb->dev, EINVAL, + "Front-end specificed ring-pages of %u " + "exceeds backend limit of %zu. " + "Unable to connect.", + xbb->ring_config.ring_pages, + XBB_MAX_RING_PAGES); + return (EINVAL); + } else if (xbb->max_requests > XBB_MAX_REQUESTS) { + xenbus_dev_fatal(xbb->dev, EINVAL, + "Front-end specificed max_requests of %u " + "exceeds backend limit of %u. " + "Unable to connect.", + xbb->max_requests, + XBB_MAX_REQUESTS); + return (EINVAL); + } else if (xbb->max_request_segments > XBB_MAX_SEGMENTS_PER_REQUEST) { + xenbus_dev_fatal(xbb->dev, EINVAL, + "Front-end specificed max_requests_segments " + "of %u exceeds backend limit of %u. " + "Unable to connect.", + xbb->max_request_segments, + XBB_MAX_SEGMENTS_PER_REQUEST); + return (EINVAL); + } else if (xbb->max_request_size > XBB_MAX_REQUEST_SIZE) { + xenbus_dev_fatal(xbb->dev, EINVAL, + "Front-end specificed max_request_size " + "of %u exceeds backend limit of %u. " + "Unable to connect.", + xbb->max_request_size, + XBB_MAX_REQUEST_SIZE); return (EINVAL); } - err = SYSCTL_OUT(req, value, strlen(value)); - if (buf != NULL) - free(buf, M_DEVBUF); + /* If using a multi-page ring, pull in the remaining references. */ + for (ring_idx = 1; ring_idx < xbb->ring_config.ring_pages; ring_idx++) { + char ring_ref_name[]= "ring_refXX"; - return err; + snprintf(ring_ref_name, sizeof(ring_ref_name), + "ring-ref%u", ring_idx); + error = xs_scanf(XST_NIL, otherend_path, + ring_ref_name, NULL, "%" PRIu32, + &xbb->ring_config.ring_ref[ring_idx]); + if (error != 0) { + xenbus_dev_fatal(xbb->dev, error, + "Failed to retriev grant reference " + "for page %u of shared ring. Unable " + "to connect.", ring_idx); + return (error); + } + } + + error = xs_gather(XST_NIL, otherend_path, + "protocol", "%63s", protocol_abi, + NULL); + if (error != 0 + || !strcmp(protocol_abi, XEN_IO_PROTO_ABI_NATIVE)) { + /* + * Assume native if the frontend has not + * published ABI data or it has published and + * matches our own ABI. + */ + xbb->abi = BLKIF_PROTOCOL_NATIVE; + } else if (!strcmp(protocol_abi, XEN_IO_PROTO_ABI_X86_32)) { + + xbb->abi = BLKIF_PROTOCOL_X86_32; + } else if (!strcmp(protocol_abi, XEN_IO_PROTO_ABI_X86_64)) { + + xbb->abi = BLKIF_PROTOCOL_X86_64; + } else { + + xenbus_dev_fatal(xbb->dev, EINVAL, + "Unknown protocol ABI (%s) published by " + "frontend. Unable to connect.", protocol_abi); + return (EINVAL); + } + return (0); } -/* Newbus vbd device driver probe */ +/** + * Allocate per-request data structures given request size and number + * information negotiated with the front-end. + * + * \param xbb Per-instance xbb configuration structure. + */ static int -vbd_probe(device_t dev) +xbb_alloc_requests(struct xbb_softc *xbb) { - DPRINTF("vbd%d\n", device_get_unit(dev)); - return 0; + struct xbb_xen_req *req; + struct xbb_xen_req *last_req; + uint8_t *req_kva; + u_long gnt_base; + + /* + * Allocate request book keeping datastructures. + */ + xbb->requests = malloc(xbb->max_requests * sizeof(*xbb->requests), + M_XENBLOCKBACK, M_NOWAIT|M_ZERO); + if (xbb->requests == NULL) { + xenbus_dev_fatal(xbb->dev, ENOMEM, + "Unable to allocate request structures"); + return (ENOMEM); + } + + req_kva = (uint8_t *)xbb->kva; + gnt_base = xbb->gnt_base_addr; + req = xbb->requests; + last_req = &xbb->requests[xbb->max_requests - 1]; + while (req <= last_req) { + int seg; + + req->xbb = xbb; + req->kva = req_kva; + req->gnt_handles = malloc(xbb->max_request_segments + * sizeof(*req->gnt_handles), + M_XENBLOCKBACK, M_NOWAIT|M_ZERO); + if (req->gnt_handles == NULL) { + xenbus_dev_fatal(xbb->dev, ENOMEM, + "Unable to allocate request " + "grant references"); + return (ENOMEM); + } +#ifdef XBB_USE_BOUNCE_BUFFERS + req->bounce = malloc(xbb->max_request_size, + M_XENBLOCKBACK, M_NOWAIT); + if (req->bounce == NULL) { + xenbus_dev_fatal(xbb->dev, ENOMEM, + "Unable to allocate request " + "bounce buffers"); + return (ENOMEM); + } +#endif /* XBB_USE_BOUNCE_BUFFERS */ + req->gnt_base = gnt_base; + req_kva += xbb->max_request_segments * PAGE_SIZE; + gnt_base += xbb->max_request_segments * PAGE_SIZE; + SLIST_INSERT_HEAD(&xbb->request_free_slist, req, links); + + for (seg = 0; seg < xbb->max_request_segments; seg++) + req->gnt_handles[seg] = GRANT_REF_INVALID; + + req++; + } + return (0); } -/* Newbus vbd device driver attach */ +/** + * Supply information about the physical device to the frontend + * via XenBus. + * + * \param xbb Per-instance xbb configuration structure. + */ static int -vbd_attach(device_t dev) +xbb_publish_backend_info(struct xbb_softc *xbb) { - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); + struct xs_transaction xst; + const char *our_path; + const char *leaf; + int error; - DPRINTF("%s\n", blkif->dev_name); + our_path = xenbus_get_node(xbb->dev); + while (1) { + error = xs_transaction_start(&xst); + if (error != 0) { + xenbus_dev_fatal(xbb->dev, error, + "Error publishing backend info " + "(start transaction)"); + return (error); + } - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "domid", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_DOMID, vbd_sysctl_handler, "I", - "domid of frontend"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "rd_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_RD_REQ, vbd_sysctl_handler, "I", - "number of read reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "wr_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_WR_REQ, vbd_sysctl_handler, "I", - "number of write reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "oo_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_OO_REQ, vbd_sysctl_handler, "I", - "number of deferred reqs"); - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "err_reqs", CTLTYPE_INT|CTLFLAG_RD, - dev, VBD_SYSCTL_ST_ERR_REQ, vbd_sysctl_handler, "I", - "number of reqs that returned error"); -#if XEN_BLKBACK_DEBUG - SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "ring", CTLFLAG_RD, - dev, VBD_SYSCTL_RING, vbd_sysctl_handler, "A", - "req ring info"); + leaf = "sectors"; + error = xs_printf(xst, our_path, leaf, + "%"PRIu64, xbb->media_num_sectors); + if (error != 0) + break; + + /* XXX Support all VBD attributes here. */ + leaf = "info"; + error = xs_printf(xst, our_path, leaf, "%u", + xbb->flags & XBBF_READ_ONLY + ? VDISK_READONLY : 0); + if (error != 0) + break; + + leaf = "sector-size"; + error = xs_printf(xst, our_path, leaf, "%u", + xbb->sector_size); + if (error != 0) + break; + + error = xs_transaction_end(xst, 0); + if (error == 0) { + return (0); + } else if (error != EAGAIN) { + xenbus_dev_fatal(xbb->dev, error, "ending transaction"); + return (error); + } + } + + xenbus_dev_fatal(xbb->dev, error, "writing %s/%s", + our_path, leaf); + xs_transaction_end(xst, 1); + return (error); +} + +/** + * Connect to our blkfront peer now that it has completed publishing + * its configuration into the XenStore. + * + * \param xbb Per-instance xbb configuration structure. + */ +static void +xbb_connect(struct xbb_softc *xbb) +{ + int error; + + if (xenbus_get_state(xbb->dev) == XenbusStateConnected) + return; + + if (xbb_collect_frontend_info(xbb) != 0) + return; + + /* Allocate resources whose size depends on front-end configuration. */ + error = xbb_alloc_communication_mem(xbb); + if (error != 0) { + xenbus_dev_fatal(xbb->dev, error, + "Unable to allocate communication memory"); + return; + } + + error = xbb_alloc_requests(xbb); + if (error != 0) { + /* Specific errors are reported by xbb_alloc_requests(). */ + return; + } + + /* + * Connect communication channel. + */ + error = xbb_connect_ring(xbb); + if (error != 0) { + /* Specific errors are reported by xbb_connect_ring(). */ + return; + } + + if (xbb_publish_backend_info(xbb) != 0) { + /* + * If we can't publish our data, we cannot participate + * in this connection, and waiting for a front-end state + * change will not help the situation. + */ + xbb_disconnect(xbb); + return; + } + + /* Ready for I/O. */ + xenbus_set_state(xbb->dev, XenbusStateConnected); +} + +/*-------------------------- Device Teardown Support -------------------------*/ +/** + * Perform device shutdown functions. + * + * \param xbb Per-instance xbb configuration structure. + * + * Mark this instance as shutting down, wait for any active I/O on the + * backend device/file to drain, disconnect from the front-end, and notify + * any waiters (e.g. a thread invoking our detach method) that detach can + * now proceed. + */ +static int +xbb_shutdown(struct xbb_softc *xbb) +{ + static int in_shutdown; + + DPRINTF("\n"); + + /* + * Due to the need to drop our mutex during some + * xenbus operations, it is possible for two threads + * to attempt to close out shutdown processing at + * the same time. Tell the caller that hits this + * race to try back later. + */ + if (in_shutdown != 0) + return (EAGAIN); + + DPRINTF("\n"); + + /* Indicate shutdown is in progress. */ + xbb->flags |= XBBF_SHUTDOWN; + + /* Wait for requests to complete. */ + if (xbb->active_request_count != 0) + return (EAGAIN); + + DPRINTF("\n"); + + /* Disconnect from the front-end. */ + xbb_disconnect(xbb); + + in_shutdown = 1; + mtx_unlock(&xbb->lock); + xenbus_set_state(xbb->dev, XenbusStateClosed); + mtx_lock(&xbb->lock); + in_shutdown = 0; + + /* Indicate to xbb_detach() that is it safe to proceed. */ + wakeup(xbb); + + return (0); +} + +/** + * Report an attach time error to the console and Xen, and cleanup + * this instance by forcing immediate detach processing. + * + * \param xbb Per-instance xbb configuration structure. + * \param err Errno describing the error. + * \param fmt Printf style format and arguments + */ +static void +xbb_attach_failed(struct xbb_softc *xbb, int err, const char *fmt, ...) +{ + va_list ap; + va_list ap_hotplug; + + va_start(ap, fmt); + va_copy(ap_hotplug, ap); + xs_vprintf(XST_NIL, xenbus_get_node(xbb->dev), + "hotplug-error", fmt, ap_hotplug); + va_end(ap_hotplug); + xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "hotplug-status", "error"); + + xenbus_dev_vfatal(xbb->dev, err, fmt, ap); + va_end(ap); + + xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "online", "0"); + xbb_detach(xbb->dev); +} + +/*---------------------------- NewBus Entrypoints ----------------------------*/ +/** + * Inspect a XenBus device and claim it if is of the appropriate type. + * + * \param dev NewBus device object representing a candidate XenBus device. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_probe(device_t dev) +{ + + if (!strcmp(xenbus_get_type(dev), "vbd")) { + device_set_desc(dev, "Backend Virtual Block Device"); + device_quiet(dev); + return (0); + } + + return (ENXIO); +} + +/** + * Attach to a XenBus device that has been claimed by our probe routine. + * + * \param dev NewBus device object representing this Xen Block Back instance. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_attach(device_t dev) +{ + struct xbb_softc *xbb; + int error; + + DPRINTF("Attaching to %s\n", xenbus_get_node(dev)); + + /* + * Basic initialization. + * After this block it is safe to call xbb_detach() + * to clean up any allocated data for this instance. + */ + xbb = device_get_softc(dev); + xbb->dev = dev; + xbb->otherend_id = xenbus_get_otherend_id(dev); + TASK_INIT(&xbb->io_task, /*priority*/0, xbb_run_queue, xbb); + mtx_init(&xbb->lock, device_get_nameunit(dev), NULL, MTX_DEF); + SLIST_INIT(&xbb->request_free_slist); + + /* + * Protocol defaults valid even if all negotiation fails. + */ + xbb->ring_config.ring_pages = 1; + xbb->max_requests = BLKIF_MAX_RING_REQUESTS(PAGE_SIZE); + xbb->max_request_segments = BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK; + xbb->max_request_size = xbb->max_request_segments * PAGE_SIZE; + + /* + * Publish protocol capabilities for consumption by the + * front-end. + */ + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "feature-barrier", "1"); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/feature-barrier", + xenbus_get_node(xbb->dev)); + return (error); + } + + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "feature-flush-cache", "1"); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/feature-flush-cache", + xenbus_get_node(xbb->dev)); + return (error); + } + + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "max-ring-pages", "%zu", XBB_MAX_RING_PAGES); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/max-ring-pages", + xenbus_get_node(xbb->dev)); + return (error); + } + + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "max-requests", "%u", XBB_MAX_REQUESTS); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/max-requests", + xenbus_get_node(xbb->dev)); + return (error); + } + + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "max-request-segments", "%u", + XBB_MAX_SEGMENTS_PER_REQUEST); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/max-request-segments", + xenbus_get_node(xbb->dev)); + return (error); + } + + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "max-request-size", "%u", + XBB_MAX_REQUEST_SIZE); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/max-request-size", + xenbus_get_node(xbb->dev)); + return (error); + } + + /* Collect physical device information. */ + error = xs_gather(XST_NIL, xenbus_get_otherend_path(xbb->dev), + "device-type", NULL, &xbb->dev_type, + NULL); + if (error != 0) + xbb->dev_type = NULL; + + error = xs_gather(XST_NIL, xenbus_get_node(dev), + "mode", NULL, &xbb->dev_mode, + "params", NULL, &xbb->dev_name, + NULL); + if (error != 0) { + xbb_attach_failed(xbb, error, "reading backend fields at %s", + xenbus_get_node(dev)); + return (ENXIO); + } + + /* Parse fopen style mode flags. */ + if (strchr(xbb->dev_mode, 'w') == NULL) + xbb->flags |= XBBF_READ_ONLY; + + /* + * Verify the physical device is present and can support + * the desired I/O mode. + */ + DROP_GIANT(); + error = xbb_open_backend(xbb); + PICKUP_GIANT(); + if (error != 0) { + xbb_attach_failed(xbb, error, "Unable to open %s", + xbb->dev_name); + return (ENXIO); + } + + /* Use devstat(9) for recording statistics. */ + xbb->xbb_stats = devstat_new_entry("xbb", device_get_unit(xbb->dev), + xbb->sector_size, + DEVSTAT_ALL_SUPPORTED, + DEVSTAT_TYPE_DIRECT + | DEVSTAT_TYPE_IF_OTHER, + DEVSTAT_PRIORITY_OTHER); + /* + * Create a taskqueue for doing work that must occur from a + * thread context. + */ + xbb->io_taskqueue = taskqueue_create(device_get_nameunit(dev), M_NOWAIT, + taskqueue_thread_enqueue, + /*context*/&xbb->io_taskqueue); + if (xbb->io_taskqueue == NULL) { + xbb_attach_failed(xbb, error, "Unable to create taskqueue"); + return (ENOMEM); + } + + taskqueue_start_threads(&xbb->io_taskqueue, + /*num threads*/1, + /*priority*/PWAIT, + /*thread name*/ + "%s taskq", device_get_nameunit(dev)); + + /* Update hot-plug status to satisfy xend. */ + error = xs_printf(XST_NIL, xenbus_get_node(xbb->dev), + "hotplug-status", "connected"); + if (error) { + xbb_attach_failed(xbb, error, "writing %s/hotplug-status", + xenbus_get_node(xbb->dev)); + return (error); + } + + /* Tell the front end that we are ready to connect. */ + xenbus_set_state(dev, XenbusStateInitWait); + + return (0); +} + +/** + * Detach from a block back device instanced. + * + * \param dev NewBus device object representing this Xen Block Back instance. + * + * \return 0 for success, errno codes for failure. + * + * \note A block back device may be detached at any time in its life-cycle, + * including part way through the attach process. For this reason, + * initialization order and the intialization state checks in this + * routine must be carefully coupled so that attach time failures + * are gracefully handled. + */ +static int +xbb_detach(device_t dev) +{ + struct xbb_softc *xbb; + + DPRINTF("\n"); + + xbb = device_get_softc(dev); + mtx_lock(&xbb->lock); + while (xbb_shutdown(xbb) == EAGAIN) { + msleep(xbb, &xbb->lock, /*wakeup prio unchanged*/0, + "xbb_shutdown", 0); + } + mtx_unlock(&xbb->lock); + mtx_destroy(&xbb->lock); + + DPRINTF("\n"); + + taskqueue_free(xbb->io_taskqueue); + devstat_remove_entry(xbb->xbb_stats); + + xbb_close_backend(xbb); + xbb_free_communication_mem(xbb); + + if (xbb->dev_mode != NULL) { + free(xbb->dev_mode, M_XENBUS); + xbb->dev_mode = NULL; + } + + if (xbb->dev_type != NULL) { + free(xbb->dev_type, M_XENBUS); + xbb->dev_type = NULL; + } + + if (xbb->dev_name != NULL) { + free(xbb->dev_name, M_XENBUS); + xbb->dev_name = NULL; + } + + if (xbb->requests != NULL) { + struct xbb_xen_req *req; + struct xbb_xen_req *last_req; + + req = xbb->requests; + last_req = &xbb->requests[xbb->max_requests - 1]; + while (req <= last_req) { +#ifdef XBB_USE_BOUNCE_BUFFERS + if (req->bounce != NULL) { + free(req->bounce, M_XENBLOCKBACK); + req->bounce = NULL; + } +#endif + if (req->gnt_handles != NULL) { + free (req->gnt_handles, M_XENBLOCKBACK); + req->gnt_handles = NULL; + } + req++; + } + free(xbb->requests, M_XENBLOCKBACK); + xbb->requests = NULL; + } + + return (0); +} + +/** + * Prepare this block back device for suspension of this VM. + * + * \param dev NewBus device object representing this Xen Block Back instance. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_suspend(device_t dev) +{ +#ifdef NOT_YET + struct xbb_softc *sc = device_get_softc(dev); + + /* Prevent new requests being issued until we fix things up. */ + mtx_lock(&sc->xb_io_lock); + sc->connected = BLKIF_STATE_SUSPENDED; + mtx_unlock(&sc->xb_io_lock); #endif - if (!open_device(blkif)) - connect(blkif); - - return bus_generic_attach(dev); + return (0); } -/* Newbus vbd device driver detach */ -static int -vbd_detach(device_t dev) -{ - blkif_t *blkif = (blkif_t *)device_get_ivars(dev); - - DPRINTF("%s\n", blkif->dev_name); - - close_device(blkif); - - bus_generic_detach(dev); - - blkif_put(blkif); - - return 0; -} - -static device_method_t vbd_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, vbd_probe), - DEVMETHOD(device_attach, vbd_attach), - DEVMETHOD(device_detach, vbd_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - {0, 0} -}; - -static devclass_t vbd_devclass; - -static driver_t vbd_driver = { - "vbd", - vbd_methods, - 0, -}; - -DRIVER_MODULE(vbd, nexus, vbd_driver, vbd_devclass, 0, 0); - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: t - * End: +/** + * Perform any processing required to recover from a suspended state. + * + * \param dev NewBus device object representing this Xen Block Back instance. + * + * \return 0 for success, errno codes for failure. */ +static int +xbb_resume(device_t dev) +{ + return (0); +} + +/** + * Handle state changes expressed via the XenStore by our front-end peer. + * + * \param dev NewBus device object representing this Xen + * Block Back instance. + * \param frontend_state The new state of the front-end. + * + * \return 0 for success, errno codes for failure. + */ +static int +xbb_frontend_changed(device_t dev, XenbusState frontend_state) +{ + struct xbb_softc *xbb = device_get_softc(dev); + + DPRINTF("state=%s\n", xenbus_strstate(frontend_state)); + + switch (frontend_state) { + case XenbusStateInitialising: + case XenbusStateClosing: + break; + case XenbusStateInitialised: + case XenbusStateConnected: + xbb_connect(xbb); + break; + case XenbusStateClosed: + case XenbusStateInitWait: + + mtx_lock(&xbb->lock); + xbb_shutdown(xbb); + mtx_unlock(&xbb->lock); + break; + default: + xenbus_dev_fatal(xbb->dev, EINVAL, "saw state %d at frontend", + frontend_state); + break; + } + return (0); +} + +/*---------------------------- NewBus Registration ---------------------------*/ +static device_method_t xbb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xbb_probe), + DEVMETHOD(device_attach, xbb_attach), + DEVMETHOD(device_detach, xbb_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, xbb_suspend), + DEVMETHOD(device_resume, xbb_resume), + + /* Xenbus interface */ + DEVMETHOD(xenbus_otherend_changed, xbb_frontend_changed), + + { 0, 0 } +}; + +static driver_t xbb_driver = { + "xbbd", + xbb_methods, + sizeof(struct xbb_softc), +}; +devclass_t xbb_devclass; + +DRIVER_MODULE(xbbd, xenbusb_back, xbb_driver, xbb_devclass, 0, 0); diff --git a/sys/dev/xen/blkfront/blkfront.c b/sys/dev/xen/blkfront/blkfront.c index 6c222ea6ecf..8ff87574bd5 100644 --- a/sys/dev/xen/blkfront/blkfront.c +++ b/sys/dev/xen/blkfront/blkfront.c @@ -49,8 +49,10 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include + #include #include #include @@ -68,17 +70,21 @@ __FBSDID("$FreeBSD$"); /* prototypes */ static void xb_free_command(struct xb_command *cm); static void xb_startio(struct xb_softc *sc); -static void connect(struct xb_softc *); +static void blkfront_connect(struct xb_softc *); static void blkfront_closing(device_t); static int blkfront_detach(device_t); -static int talk_to_backend(struct xb_softc *); static int setup_blkring(struct xb_softc *); static void blkif_int(void *); +static void blkfront_initialize(struct xb_softc *); +#if 0 static void blkif_recover(struct xb_softc *); -static void blkif_completion(struct xb_command *); +#endif +static int blkif_completion(struct xb_command *); static void blkif_free(struct xb_softc *, int); static void blkif_queue_cb(void *, bus_dma_segment_t *, int, int); +MALLOC_DEFINE(M_XENBLOCKFRONT, "xbd", "Xen Block Front driver data"); + #define GRANT_INVALID_REF 0 /* Control whether runtime update of vbds is enabled. */ @@ -113,11 +119,6 @@ static char * blkif_status_name[] = { #define DPRINTK(fmt, args...) #endif -#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ - (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) - -#define BLKIF_MAXIO (32 * 1024) - static int blkif_open(struct disk *dp); static int blkif_close(struct disk *dp); static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); @@ -202,8 +203,8 @@ blkfront_vdevice_to_unit(int vdevice, int *unit, const char **name) } int -xlvbd_add(struct xb_softc *sc, blkif_sector_t capacity, - int vdevice, uint16_t vdisk_info, uint16_t sector_size) +xlvbd_add(struct xb_softc *sc, blkif_sector_t sectors, + int vdevice, uint16_t vdisk_info, unsigned long sector_size) { int unit, error = 0; const char *name; @@ -215,7 +216,6 @@ xlvbd_add(struct xb_softc *sc, blkif_sector_t capacity, if (strcmp(name, "xbd")) device_printf(sc->xb_dev, "attaching as %s%d\n", name, unit); - memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); sc->xb_disk = disk_alloc(); sc->xb_disk->d_unit = sc->xb_unit; sc->xb_disk->d_open = blkif_open; @@ -227,20 +227,14 @@ xlvbd_add(struct xb_softc *sc, blkif_sector_t capacity, sc->xb_disk->d_drv1 = sc; sc->xb_disk->d_sectorsize = sector_size; - sc->xb_disk->d_mediasize = capacity << XBD_SECTOR_SHFT; - sc->xb_disk->d_maxsize = BLKIF_MAXIO; + sc->xb_disk->d_mediasize = sectors * sector_size; + sc->xb_disk->d_maxsize = sc->max_request_size; sc->xb_disk->d_flags = 0; disk_create(sc->xb_disk, DISK_VERSION_00); return error; } -void -xlvbd_del(struct xb_softc *sc) -{ - - disk_destroy(sc->xb_disk); -} /************************ end VBD support *****************/ /* @@ -357,15 +351,16 @@ xb_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, return (EBUSY); } - if (gnttab_alloc_grant_references( - BLKIF_MAX_SEGMENTS_PER_REQUEST, &cm->gref_head) < 0) { + if (gnttab_alloc_grant_references(sc->max_request_segments, + &cm->gref_head) != 0) { xb_free_command(cm); mtx_unlock(&sc->xb_io_lock); device_printf(sc->xb_dev, "no more grant allocs?\n"); return (EBUSY); } - chunk = length > BLKIF_MAXIO ? BLKIF_MAXIO : length; + chunk = length > sc->max_request_size + ? sc->max_request_size : length; cm->data = virtual; cm->datalen = chunk; cm->operation = BLKIF_OP_WRITE; @@ -423,16 +418,18 @@ static int blkfront_attach(device_t dev) { struct xb_softc *sc; - struct xb_command *cm; const char *name; - int error, vdevice, i, unit; + int error; + int vdevice; + int i; + int unit; /* FIXME: Use dynamic device id if this is not set. */ - error = xenbus_scanf(XBT_NIL, xenbus_get_node(dev), + error = xs_scanf(XST_NIL, xenbus_get_node(dev), "virtual-device", NULL, "%i", &vdevice); if (error) { xenbus_dev_fatal(dev, error, "reading virtual-device"); - printf("couldn't find virtual device"); + device_printf(dev, "Couldn't determine virtual device.\n"); return (error); } @@ -447,51 +444,18 @@ blkfront_attach(device_t dev) xb_initq_ready(sc); xb_initq_complete(sc); xb_initq_bio(sc); - - /* Allocate parent DMA tag */ - if (bus_dma_tag_create( NULL, /* parent */ - 512, 4096, /* algnmnt, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - BLKIF_MAXIO, /* maxsize */ - BLKIF_MAX_SEGMENTS_PER_REQUEST, /* nsegments */ - PAGE_SIZE, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &sc->xb_io_lock, /* lockarg */ - &sc->xb_io_dmat)) { - device_printf(dev, "Cannot allocate parent DMA tag\n"); - return (ENOMEM); - } -#ifdef notyet - if (bus_dma_tag_set(sc->xb_io_dmat, BUS_DMA_SET_MINSEGSZ, - XBD_SECTOR_SIZE)) { - device_printf(dev, "Cannot set sector size\n"); - return (EINVAL); - } -#endif + for (i = 0; i < XBF_MAX_RING_PAGES; i++) + sc->ring_ref[i] = GRANT_INVALID_REF; sc->xb_dev = dev; sc->vdevice = vdevice; sc->connected = BLKIF_STATE_DISCONNECTED; - /* work queue needed ? */ - for (i = 0; i < BLK_RING_SIZE; i++) { - cm = &sc->shadow[i]; - cm->req.id = i; - cm->cm_sc = sc; - if (bus_dmamap_create(sc->xb_io_dmat, 0, &cm->map) != 0) - break; - xb_free_command(cm); - } - /* Front end dir is a number, which is used as the id. */ sc->handle = strtoul(strrchr(xenbus_get_node(dev),'/')+1, NULL, 0); - error = talk_to_backend(sc); - if (error) - return (error); + /* Wait for backend device to publish its protocol capabilities. */ + xenbus_set_state(dev, XenbusStateInitialising); return (0); } @@ -512,121 +476,265 @@ blkfront_suspend(device_t dev) static int blkfront_resume(device_t dev) { +#if 0 struct xb_softc *sc = device_get_softc(dev); - int err; DPRINTK("blkfront_resume: %s\n", xenbus_get_node(dev)); +/* XXX This can't work!!! */ blkif_free(sc, 1); - err = talk_to_backend(sc); - if (sc->connected == BLKIF_STATE_SUSPENDED && !err) + blkfront_initialize(sc); + if (sc->connected == BLKIF_STATE_SUSPENDED) blkif_recover(sc); - - return (err); +#endif + return (0); } -/* Common code used when first setting up, and when resuming. */ -static int -talk_to_backend(struct xb_softc *sc) +static void +blkfront_initialize(struct xb_softc *sc) { - device_t dev; - struct xenbus_transaction xbt; - const char *message = NULL; - int err; + const char *otherend_path; + const char *node_path; + int error; + int i; - /* Create shared ring, alloc event channel. */ - dev = sc->xb_dev; - err = setup_blkring(sc); - if (err) - goto out; + if (xenbus_get_state(sc->xb_dev) != XenbusStateInitialising) + return; - again: - err = xenbus_transaction_start(&xbt); - if (err) { - xenbus_dev_fatal(dev, err, "starting transaction"); - goto destroy_blkring; + /* + * Protocol defaults valid even if negotiation for a + * setting fails. + */ + sc->ring_pages = 1; + sc->max_requests = BLKIF_MAX_RING_REQUESTS(PAGE_SIZE); + sc->max_request_segments = BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK; + sc->max_request_size = sc->max_request_segments * PAGE_SIZE; + sc->max_request_blocks = BLKIF_SEGS_TO_BLOCKS(sc->max_request_segments); + + /* + * Protocol negotiation. + * + * \note xs_gather() returns on the first encountered error, so + * we must use independant calls in order to guarantee + * we don't miss information in a sparsly populated back-end + * tree. + */ + otherend_path = xenbus_get_otherend_path(sc->xb_dev); + node_path = xenbus_get_node(sc->xb_dev); + (void)xs_scanf(XST_NIL, otherend_path, + "max-ring-pages", NULL, "%" PRIu32, + &sc->ring_pages); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-requests", NULL, "%" PRIu32, + &sc->max_requests); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-request-segments", NULL, "%" PRIu32, + &sc->max_request_segments); + + (void)xs_scanf(XST_NIL, otherend_path, + "max-request-size", NULL, "%" PRIu32, + &sc->max_request_size); + + if (sc->ring_pages > XBF_MAX_RING_PAGES) { + device_printf(sc->xb_dev, "Back-end specified ring-pages of " + "%u limited to front-end limit of %zu.\n", + sc->ring_pages, XBF_MAX_RING_PAGES); + sc->ring_pages = XBF_MAX_RING_PAGES; } - err = xenbus_printf(xbt, xenbus_get_node(dev), - "ring-ref","%u", sc->ring_ref); - if (err) { - message = "writing ring-ref"; - goto abort_transaction; - } - err = xenbus_printf(xbt, xenbus_get_node(dev), - "event-channel", "%u", irq_to_evtchn_port(sc->irq)); - if (err) { - message = "writing event-channel"; - goto abort_transaction; - } - err = xenbus_printf(xbt, xenbus_get_node(dev), - "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); - if (err) { - message = "writing protocol"; - goto abort_transaction; + if (sc->max_requests > XBF_MAX_REQUESTS) { + device_printf(sc->xb_dev, "Back-end specified max_requests of " + "%u limited to front-end limit of %u.\n", + sc->max_requests, XBF_MAX_REQUESTS); + sc->max_requests = XBF_MAX_REQUESTS; } - err = xenbus_transaction_end(xbt, 0); - if (err) { - if (err == EAGAIN) - goto again; - xenbus_dev_fatal(dev, err, "completing transaction"); - goto destroy_blkring; + if (sc->max_request_segments > XBF_MAX_SEGMENTS_PER_REQUEST) { + device_printf(sc->xb_dev, "Back-end specificed " + "max_requests_segments of %u limited to " + "front-end limit of %u.\n", + sc->max_request_segments, + XBF_MAX_SEGMENTS_PER_REQUEST); + sc->max_request_segments = XBF_MAX_SEGMENTS_PER_REQUEST; } - xenbus_set_state(dev, XenbusStateInitialised); - - return 0; - abort_transaction: - xenbus_transaction_end(xbt, 1); - if (message) - xenbus_dev_fatal(dev, err, "%s", message); - destroy_blkring: - blkif_free(sc, 0); - out: - return err; + if (sc->max_request_size > XBF_MAX_REQUEST_SIZE) { + device_printf(sc->xb_dev, "Back-end specificed " + "max_request_size of %u limited to front-end " + "limit of %u.\n", sc->max_request_size, + XBF_MAX_REQUEST_SIZE); + sc->max_request_size = XBF_MAX_REQUEST_SIZE; + } + sc->max_request_blocks = BLKIF_SEGS_TO_BLOCKS(sc->max_request_segments); + + /* Allocate datastructures based on negotiated values. */ + error = bus_dma_tag_create(NULL, /* parent */ + 512, PAGE_SIZE, /* algnmnt, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->max_request_size, + sc->max_request_segments, + PAGE_SIZE, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + busdma_lock_mutex, /* lockfunc */ + &sc->xb_io_lock, /* lockarg */ + &sc->xb_io_dmat); + if (error != 0) { + xenbus_dev_fatal(sc->xb_dev, error, + "Cannot allocate parent DMA tag\n"); + return; + } + + /* Per-transaction data allocation. */ + sc->shadow = malloc(sizeof(*sc->shadow) * sc->max_requests, + M_XENBLOCKFRONT, M_NOWAIT|M_ZERO); + if (sc->shadow == NULL) { + xenbus_dev_fatal(sc->xb_dev, error, + "Cannot allocate request structures\n"); + } + + for (i = 0; i < sc->max_requests; i++) { + struct xb_command *cm; + + cm = &sc->shadow[i]; + cm->sg_refs = malloc(sizeof(grant_ref_t) + * sc->max_request_segments, + M_XENBLOCKFRONT, M_NOWAIT); + if (cm->sg_refs == NULL) + break; + cm->id = i; + cm->cm_sc = sc; + if (bus_dmamap_create(sc->xb_io_dmat, 0, &cm->map) != 0) + break; + xb_free_command(cm); + } + + if (setup_blkring(sc) != 0) + return; + + error = xs_printf(XST_NIL, node_path, + "ring-pages","%u", sc->ring_pages); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/ring-pages", + node_path); + return; + } + + error = xs_printf(XST_NIL, node_path, + "max-requests","%u", sc->max_requests); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/max-requests", + node_path); + return; + } + + error = xs_printf(XST_NIL, node_path, + "max-request-segments","%u", sc->max_request_segments); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/max-request-segments", + node_path); + return; + } + + error = xs_printf(XST_NIL, node_path, + "max-request-size","%u", sc->max_request_size); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/max-request-size", + node_path); + return; + } + + error = xs_printf(XST_NIL, node_path, "event-channel", + "%u", irq_to_evtchn_port(sc->irq)); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/event-channel", + node_path); + return; + } + + error = xs_printf(XST_NIL, node_path, + "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "writing %s/protocol", + node_path); + return; + } + + xenbus_set_state(sc->xb_dev, XenbusStateInitialised); } static int setup_blkring(struct xb_softc *sc) { blkif_sring_t *sring; + uintptr_t sring_page_addr; int error; + int i; - sc->ring_ref = GRANT_INVALID_REF; - - sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); + sring = malloc(sc->ring_pages * PAGE_SIZE, M_XENBLOCKFRONT, + M_NOWAIT|M_ZERO); if (sring == NULL) { xenbus_dev_fatal(sc->xb_dev, ENOMEM, "allocating shared ring"); - return ENOMEM; + return (ENOMEM); } SHARED_RING_INIT(sring); - FRONT_RING_INIT(&sc->ring, sring, PAGE_SIZE); + FRONT_RING_INIT(&sc->ring, sring, sc->ring_pages * PAGE_SIZE); - error = xenbus_grant_ring(sc->xb_dev, - (vtomach(sc->ring.sring) >> PAGE_SHIFT), &sc->ring_ref); - if (error) { - free(sring, M_DEVBUF); - sc->ring.sring = NULL; - goto fail; + for (i = 0, sring_page_addr = (uintptr_t)sring; + i < sc->ring_pages; + i++, sring_page_addr += PAGE_SIZE) { + + error = xenbus_grant_ring(sc->xb_dev, + (vtomach(sring_page_addr) >> PAGE_SHIFT), &sc->ring_ref[i]); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, + "granting ring_ref(%d)", i); + return (error); + } } - - error = bind_listening_port_to_irqhandler(xenbus_get_otherend_id(sc->xb_dev), + error = xs_printf(XST_NIL, xenbus_get_node(sc->xb_dev), + "ring-ref","%u", sc->ring_ref[0]); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, "writing %s/ring-ref", + xenbus_get_node(sc->xb_dev)); + return (error); + } + for (i = 1; i < sc->ring_pages; i++) { + char ring_ref_name[]= "ring_refXX"; + + snprintf(ring_ref_name, sizeof(ring_ref_name), "ring-ref%u", i); + error = xs_printf(XST_NIL, xenbus_get_node(sc->xb_dev), + ring_ref_name, "%u", sc->ring_ref[i]); + if (error) { + xenbus_dev_fatal(sc->xb_dev, error, "writing %s/%s", + xenbus_get_node(sc->xb_dev), + ring_ref_name); + return (error); + } + } + + error = bind_listening_port_to_irqhandler( + xenbus_get_otherend_id(sc->xb_dev), "xbd", (driver_intr_t *)blkif_int, sc, INTR_TYPE_BIO | INTR_MPSAFE, &sc->irq); if (error) { xenbus_dev_fatal(sc->xb_dev, error, "bind_evtchn_to_irqhandler failed"); - goto fail; + return (error); } return (0); - fail: - blkif_free(sc, 0); - return (error); } - /** * Callback received when the backend's state changes. */ @@ -640,15 +748,19 @@ blkfront_backend_changed(device_t dev, XenbusState backend_state) switch (backend_state) { case XenbusStateUnknown: case XenbusStateInitialising: - case XenbusStateInitWait: - case XenbusStateInitialised: - case XenbusStateClosed: case XenbusStateReconfigured: case XenbusStateReconfiguring: + case XenbusStateClosed: break; + case XenbusStateInitWait: + blkfront_initialize(sc); + break; + + case XenbusStateInitialised: case XenbusStateConnected: - connect(sc); + blkfront_initialize(sc); + blkfront_connect(sc); break; case XenbusStateClosing: @@ -657,20 +769,7 @@ blkfront_backend_changed(device_t dev, XenbusState backend_state) "Device in use; refusing to close"); else blkfront_closing(dev); -#ifdef notyet - bd = bdget(sc->dev); - if (bd == NULL) - xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); - - down(&bd->bd_sem); - if (sc->users > 0) - xenbus_dev_error(dev, -EBUSY, - "Device in use; refusing to close"); - else - blkfront_closing(dev); - up(&bd->bd_sem); - bdput(bd); -#endif + break; } return (0); @@ -681,7 +780,7 @@ blkfront_backend_changed(device_t dev, XenbusState backend_state) ** the details about the physical device - #sectors, size, etc). */ static void -connect(struct xb_softc *sc) +blkfront_connect(struct xb_softc *sc) { device_t dev = sc->xb_dev; unsigned long sectors, sector_size; @@ -694,20 +793,20 @@ connect(struct xb_softc *sc) DPRINTK("blkfront.c:connect:%s.\n", xenbus_get_otherend_path(dev)); - err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), - "sectors", "%lu", §ors, - "info", "%u", &binfo, - "sector-size", "%lu", §or_size, - NULL); + err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), + "sectors", "%lu", §ors, + "info", "%u", &binfo, + "sector-size", "%lu", §or_size, + NULL); if (err) { xenbus_dev_fatal(dev, err, "reading backend fields at %s", xenbus_get_otherend_path(dev)); return; } - err = xenbus_gather(XBT_NIL, xenbus_get_otherend_path(dev), - "feature-barrier", "%lu", &feature_barrier, - NULL); + err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev), + "feature-barrier", "%lu", &feature_barrier, + NULL); if (!err || feature_barrier) sc->xb_flags |= XB_BARRIER; @@ -741,15 +840,16 @@ blkfront_closing(device_t dev) { struct xb_softc *sc = device_get_softc(dev); + xenbus_set_state(dev, XenbusStateClosing); + DPRINTK("blkfront_closing: %s removed\n", xenbus_get_node(dev)); - if (sc->mi) { - DPRINTK("Calling xlvbd_del\n"); - xlvbd_del(sc); - sc->mi = NULL; + if (sc->xb_disk != NULL) { + disk_destroy(sc->xb_disk); + sc->xb_disk = NULL; } - xenbus_set_state(dev, XenbusStateClosed); + xenbus_set_state(dev, XenbusStateClosed); } @@ -778,11 +878,16 @@ flush_requests(struct xb_softc *sc) notify_remote_via_irq(sc->irq); } -static void blkif_restart_queue_callback(void *arg) +static void +blkif_restart_queue_callback(void *arg) { struct xb_softc *sc = arg; + mtx_lock(&sc->xb_io_lock); + xb_startio(sc); + + mtx_unlock(&sc->xb_io_lock); } static int @@ -874,20 +979,17 @@ xb_bio_command(struct xb_softc *sc) return (NULL); } - if (gnttab_alloc_grant_references(BLKIF_MAX_SEGMENTS_PER_REQUEST, - &cm->gref_head) < 0) { + if (gnttab_alloc_grant_references(sc->max_request_segments, + &cm->gref_head) != 0) { gnttab_request_free_callback(&sc->callback, blkif_restart_queue_callback, sc, - BLKIF_MAX_SEGMENTS_PER_REQUEST); + sc->max_request_segments); xb_requeue_bio(sc, bp); xb_enqueue_free(cm); sc->xb_flags |= XB_FROZEN; return (NULL); } - /* XXX Can we grab refs before doing the load so that the ref can - * be filled out here? - */ cm->bp = bp; cm->data = bp->bio_data; cm->datalen = bp->bio_bcount; @@ -921,13 +1023,19 @@ blkif_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) struct xb_softc *sc; struct xb_command *cm; blkif_request_t *ring_req; + struct blkif_request_segment *sg; + struct blkif_request_segment *last_block_sg; + grant_ref_t *sg_ref; vm_paddr_t buffer_ma; uint64_t fsect, lsect; - int ref, i, op; + int ref; + int op; + int block_segs; cm = arg; sc = cm->cm_sc; +//printf("%s: Start\n", __func__); if (error) { printf("error %d in blkif_queue_cb\n", error); cm->bp->bio_error = EIO; @@ -938,43 +1046,62 @@ blkif_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) /* Fill out a communications ring structure. */ ring_req = RING_GET_REQUEST(&sc->ring, sc->ring.req_prod_pvt); - if (ring_req == NULL) { - /* XXX Is this possible? */ - printf("ring_req NULL, requeuing\n"); - xb_enqueue_ready(cm); - return; - } - ring_req->id = cm->req.id; + sc->ring.req_prod_pvt++; + ring_req->id = cm->id; ring_req->operation = cm->operation; ring_req->sector_number = cm->sector_number; ring_req->handle = (blkif_vdev_t)(uintptr_t)sc->xb_disk; ring_req->nr_segments = nsegs; + cm->nseg = nsegs; - for (i = 0; i < nsegs; i++) { - buffer_ma = segs[i].ds_addr; - fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; - lsect = fsect + (segs[i].ds_len >> XBD_SECTOR_SHFT) - 1; + block_segs = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK); + sg = ring_req->seg; + last_block_sg = sg + block_segs; + sg_ref = cm->sg_refs; - KASSERT(lsect <= 7, - ("XEN disk driver data cannot cross a page boundary")); + while (1) { - /* install a grant reference. */ - ref = gnttab_claim_grant_reference(&cm->gref_head); - KASSERT( ref >= 0, ("grant_reference failed") ); + while (sg < last_block_sg) { + buffer_ma = segs->ds_addr; + fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; + lsect = fsect + (segs->ds_len >> XBD_SECTOR_SHFT) - 1; - gnttab_grant_foreign_access_ref( - ref, - xenbus_get_otherend_id(sc->xb_dev), - buffer_ma >> PAGE_SHIFT, - ring_req->operation & 1 ); /* ??? */ + KASSERT(lsect <= 7, ("XEN disk driver data cannot " + "cross a page boundary")); - ring_req->seg[i] = - (struct blkif_request_segment) { + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&cm->gref_head); + + /* + * GNTTAB_LIST_END == 0xffffffff, but it is private + * to gnttab.c. + */ + KASSERT(ref != ~0, ("grant_reference failed")); + + gnttab_grant_foreign_access_ref( + ref, + xenbus_get_otherend_id(sc->xb_dev), + buffer_ma >> PAGE_SHIFT, + ring_req->operation == BLKIF_OP_WRITE); + + *sg_ref = ref; + *sg = (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; - } + sg++; + sg_ref++; + segs++; + nsegs--; + } + block_segs = MIN(nsegs, BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK); + if (block_segs == 0) + break; + sg = BLKRING_GET_SG_REQUEST(&sc->ring, sc->ring.req_prod_pvt); + sc->ring.req_prod_pvt++; + last_block_sg = sg + block_segs; + } if (cm->operation == BLKIF_OP_READ) op = BUS_DMASYNC_PREREAD; @@ -984,15 +1111,10 @@ blkif_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) op = 0; bus_dmamap_sync(sc->xb_io_dmat, cm->map, op); - sc->ring.req_prod_pvt++; - - /* Keep a private copy so we can reissue requests when recovering. */ - cm->req = *ring_req; + gnttab_free_grant_references(cm->gref_head); xb_enqueue_busy(cm); - gnttab_free_grant_references(cm->gref_head); - /* * This flag means that we're probably executing in the busdma swi * instead of in the startio context, so an explicit flush is needed. @@ -1000,6 +1122,7 @@ blkif_queue_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) if (cm->cm_flags & XB_CMD_FROZEN) flush_requests(sc); +//printf("%s: Done\n", __func__); return; } @@ -1018,7 +1141,7 @@ xb_startio(struct xb_softc *sc) mtx_assert(&sc->xb_io_lock, MA_OWNED); - while (!RING_FULL(&sc->ring)) { + while (RING_FREE_REQUESTS(&sc->ring) >= sc->max_request_blocks) { if (sc->xb_flags & XB_FROZEN) break; @@ -1061,12 +1184,12 @@ blkif_int(void *xsc) rp = sc->ring.sring->rsp_prod; rmb(); /* Ensure we see queued responses up to 'rp'. */ - for (i = sc->ring.rsp_cons; i != rp; i++) { + for (i = sc->ring.rsp_cons; i != rp;) { bret = RING_GET_RESPONSE(&sc->ring, i); cm = &sc->shadow[bret->id]; xb_remove_busy(cm); - blkif_completion(cm); + i += blkif_completion(cm); if (cm->operation == BLKIF_OP_READ) op = BUS_DMASYNC_POSTREAD; @@ -1116,35 +1239,61 @@ blkif_int(void *xsc) static void blkif_free(struct xb_softc *sc, int suspend) { + uint8_t *sring_page_ptr; + int i; -/* Prevent new requests being issued until we fix things up. */ + /* Prevent new requests being issued until we fix things up. */ mtx_lock(&sc->xb_io_lock); sc->connected = suspend ? BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; mtx_unlock(&sc->xb_io_lock); /* Free resources associated with old device channel. */ - if (sc->ring_ref != GRANT_INVALID_REF) { - gnttab_end_foreign_access(sc->ring_ref, - sc->ring.sring); - sc->ring_ref = GRANT_INVALID_REF; + if (sc->ring.sring != NULL) { + sring_page_ptr = (uint8_t *)sc->ring.sring; + for (i = 0; i < sc->ring_pages; i++) { + if (sc->ring_ref[i] != GRANT_INVALID_REF) { + gnttab_end_foreign_access_ref(sc->ring_ref[i]); + sc->ring_ref[i] = GRANT_INVALID_REF; + } + sring_page_ptr += PAGE_SIZE; + } + free(sc->ring.sring, M_XENBLOCKFRONT); sc->ring.sring = NULL; } - if (sc->irq) - unbind_from_irqhandler(sc->irq); - sc->irq = 0; + if (sc->shadow) { + + for (i = 0; i < sc->max_requests; i++) { + struct xb_command *cm; + + cm = &sc->shadow[i]; + if (cm->sg_refs != NULL) { + free(cm->sg_refs, M_XENBLOCKFRONT); + cm->sg_refs = NULL; + } + + bus_dmamap_destroy(sc->xb_io_dmat, cm->map); + } + free(sc->shadow, M_XENBLOCKFRONT); + sc->shadow = NULL; + } + + if (sc->irq) { + unbind_from_irqhandler(sc->irq); + sc->irq = 0; + } } -static void +static int blkif_completion(struct xb_command *s) { - int i; - - for (i = 0; i < s->req.nr_segments; i++) - gnttab_end_foreign_access(s->req.seg[i].gref, 0UL); +//printf("%s: Req %p(%d)\n", __func__, s, s->nseg); + gnttab_end_foreign_access_references(s->nseg, s->sg_refs); + return (BLKIF_SEGS_TO_BLOCKS(s->nseg)); } +#if 0 static void blkif_recover(struct xb_softc *sc) { @@ -1157,6 +1306,7 @@ blkif_recover(struct xb_softc *sc) * has been removed until further notice. */ } +#endif /* ** Driver registration ** */ static device_method_t blkfront_methods[] = { @@ -1169,7 +1319,7 @@ static device_method_t blkfront_methods[] = { DEVMETHOD(device_resume, blkfront_resume), /* Xenbus interface */ - DEVMETHOD(xenbus_backend_changed, blkfront_backend_changed), + DEVMETHOD(xenbus_otherend_changed, blkfront_backend_changed), { 0, 0 } }; @@ -1181,4 +1331,4 @@ static driver_t blkfront_driver = { }; devclass_t blkfront_devclass; -DRIVER_MODULE(xbd, xenbus, blkfront_driver, blkfront_devclass, 0, 0); +DRIVER_MODULE(xbd, xenbusb_front, blkfront_driver, blkfront_devclass, 0, 0); diff --git a/sys/dev/xen/blkfront/block.h b/sys/dev/xen/blkfront/block.h index 32bfc96a095..6235e515afe 100644 --- a/sys/dev/xen/blkfront/block.h +++ b/sys/dev/xen/blkfront/block.h @@ -32,7 +32,43 @@ #ifndef __XEN_DRIVERS_BLOCK_H__ #define __XEN_DRIVERS_BLOCK_H__ -#include +#include + +/** + * The maximum number of outstanding requests blocks (request headers plus + * additional segment blocks) we will allow in a negotiated block-front/back + * communication channel. + */ +#define XBF_MAX_REQUESTS 256 + +/** + * The maximum mapped region size per request we will allow in a negotiated + * block-front/back communication channel. + * + * \note We reserve a segement from the maximum supported by the transport to + * guarantee we can handle an unaligned transfer without the need to + * use a bounce buffer.. + */ +#define XBF_MAX_REQUEST_SIZE \ + MIN(MAXPHYS, (BLKIF_MAX_SEGMENTS_PER_REQUEST - 1) * PAGE_SIZE) + +/** + * The maximum number of segments (within a request header and accompanying + * segment blocks) per request we will allow in a negotiated block-front/back + * communication channel. + */ +#define XBF_MAX_SEGMENTS_PER_REQUEST \ + (MIN(BLKIF_MAX_SEGMENTS_PER_REQUEST, \ + (XBF_MAX_REQUEST_SIZE / PAGE_SIZE) + 1)) + +/** + * The maximum number of shared memory ring pages we will allow in a + * negotiated block-front/back communication channel. Allow enough + * ring space for all requests to be XBF_MAX_REQUEST_SIZE'd. + */ +#define XBF_MAX_RING_PAGES \ + BLKIF_RING_PAGES(BLKIF_SEGS_TO_BLOCKS(XBF_MAX_SEGMENTS_PER_REQUEST) \ + * XBF_MAX_REQUESTS) struct xlbd_type_info { @@ -62,19 +98,19 @@ struct xb_command { #define XB_ON_XBQ_COMPLETE (1<<5) #define XB_ON_XBQ_MASK ((1<<2)|(1<<3)|(1<<4)|(1<<5)) bus_dmamap_t map; - blkif_request_t req; + uint64_t id; + grant_ref_t *sg_refs; struct bio *bp; grant_ref_t gref_head; void *data; size_t datalen; + u_int nseg; int operation; blkif_sector_t sector_number; int status; void (* cm_complete)(struct xb_command *); }; -#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) - #define XBQ_FREE 0 #define XBQ_BIO 1 #define XBQ_READY 2 @@ -108,10 +144,14 @@ struct xb_softc { int vdevice; blkif_vdev_t handle; int connected; - int ring_ref; + u_int ring_pages; + uint32_t max_requests; + uint32_t max_request_segments; + uint32_t max_request_blocks; + uint32_t max_request_size; + grant_ref_t ring_ref[XBF_MAX_RING_PAGES]; blkif_front_ring_t ring; unsigned int irq; - struct xlbd_major_info *mi; struct gnttab_free_callback callback; TAILQ_HEAD(,xb_command) cm_free; TAILQ_HEAD(,xb_command) cm_ready; @@ -126,11 +166,12 @@ struct xb_softc { */ int users; struct mtx xb_io_lock; - struct xb_command shadow[BLK_RING_SIZE]; + + struct xb_command *shadow; }; -int xlvbd_add(struct xb_softc *, blkif_sector_t capacity, int device, - uint16_t vdisk_info, uint16_t sector_size); +int xlvbd_add(struct xb_softc *, blkif_sector_t sectors, int device, + uint16_t vdisk_info, unsigned long sector_size); void xlvbd_del(struct xb_softc *); #define XBQ_ADD(sc, qname) \ @@ -188,7 +229,8 @@ void xlvbd_del(struct xb_softc *); struct xb_command *cm; \ \ if ((cm = TAILQ_FIRST(&sc->cm_ ## name)) != NULL) { \ - if ((cm->cm_flags & XB_ON_ ## index) == 0) { \ + if ((cm->cm_flags & XB_ON_XBQ_MASK) != \ + XB_ON_ ## index) { \ printf("command %p not in queue, " \ "flags = %#x, bit = %#x\n", cm, \ cm->cm_flags, XB_ON_ ## index); \ @@ -203,7 +245,7 @@ void xlvbd_del(struct xb_softc *); static __inline void \ xb_remove_ ## name (struct xb_command *cm) \ { \ - if ((cm->cm_flags & XB_ON_ ## index) == 0) { \ + if ((cm->cm_flags & XB_ON_XBQ_MASK) != XB_ON_ ## index){\ printf("command %p not in queue, flags = %#x, " \ "bit = %#x\n", cm, cm->cm_flags, \ XB_ON_ ## index); \ diff --git a/sys/dev/xen/control/control.c b/sys/dev/xen/control/control.c new file mode 100644 index 00000000000..c03d5365530 --- /dev/null +++ b/sys/dev/xen/control/control.c @@ -0,0 +1,493 @@ +/*- + * Copyright (c) 2010 Justin T. Gibbs, Spectra Logic Corporation + * 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 + * substantially 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 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. + */ + +/*- + * PV suspend/resume support: + * + * Copyright (c) 2004 Christian Limpach. + * Copyright (c) 2004-2006,2008 Kip Macy + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian Limpach. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * HVM suspend/resume support: + * + * Copyright (c) 2008 Citrix Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +__FBSDID("$FreeBSD$"); + +/** + * \file control.c + * + * \brief Device driver to repond to control domain events that impact + * this VM. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef XENHVM +#include +#include +#endif + + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*(x))) + +/*--------------------------- Forward Declarations --------------------------*/ +/** Function signature for shutdown event handlers. */ +typedef void (xctrl_shutdown_handler_t)(void); + +static xctrl_shutdown_handler_t xctrl_poweroff; +static xctrl_shutdown_handler_t xctrl_reboot; +static xctrl_shutdown_handler_t xctrl_suspend; +static xctrl_shutdown_handler_t xctrl_crash; +static xctrl_shutdown_handler_t xctrl_halt; + +/*-------------------------- Private Data Structures -------------------------*/ +/** Element type for lookup table of event name to handler. */ +struct xctrl_shutdown_reason { + const char *name; + xctrl_shutdown_handler_t *handler; +}; + +/** Lookup table for shutdown event name to handler. */ +static struct xctrl_shutdown_reason xctrl_shutdown_reasons[] = { + { "poweroff", xctrl_poweroff }, + { "reboot", xctrl_reboot }, + { "suspend", xctrl_suspend }, + { "crash", xctrl_crash }, + { "halt", xctrl_halt }, +}; + +struct xctrl_softc { + + /** Must be first */ + struct xs_watch xctrl_watch; +}; + +/*------------------------------ Event Handlers ------------------------------*/ +static void +xctrl_poweroff() +{ + shutdown_nice(RB_POWEROFF|RB_HALT); +} + +static void +xctrl_reboot() +{ + shutdown_nice(0); +} + +#ifndef XENHVM +extern void xencons_suspend(void); +extern void xencons_resume(void); + +/* Full PV mode suspension. */ +static void +xctrl_suspend() +{ + int i, j, k, fpp; + unsigned long max_pfn, start_info_mfn; + +#ifdef SMP + cpumask_t map; + /* + * Bind us to CPU 0 and stop any other VCPUs. + */ + thread_lock(curthread); + sched_bind(curthread, 0); + thread_unlock(curthread); + KASSERT(PCPU_GET(cpuid) == 0, ("xen_suspend: not running on cpu 0")); + + map = PCPU_GET(other_cpus) & ~stopped_cpus; + if (map) + stop_cpus(map); +#endif + + if (DEVICE_SUSPEND(root_bus) != 0) { + printf("xen_suspend: device_suspend failed\n"); +#ifdef SMP + if (map) + restart_cpus(map); +#endif + return; + } + + local_irq_disable(); + + xencons_suspend(); + gnttab_suspend(); + + max_pfn = HYPERVISOR_shared_info->arch.max_pfn; + + void *shared_info = HYPERVISOR_shared_info; + HYPERVISOR_shared_info = NULL; + pmap_kremove((vm_offset_t) shared_info); + PT_UPDATES_FLUSH(); + + xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn); + xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn); + + /* + * We'll stop somewhere inside this hypercall. When it returns, + * we'll start resuming after the restore. + */ + start_info_mfn = VTOMFN(xen_start_info); + pmap_suspend(); + HYPERVISOR_suspend(start_info_mfn); + pmap_resume(); + + pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info); + HYPERVISOR_shared_info = shared_info; + + HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = + VTOMFN(xen_pfn_to_mfn_frame_list_list); + + fpp = PAGE_SIZE/sizeof(unsigned long); + for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { + if ((j % fpp) == 0) { + k++; + xen_pfn_to_mfn_frame_list_list[k] = + VTOMFN(xen_pfn_to_mfn_frame_list[k]); + j = 0; + } + xen_pfn_to_mfn_frame_list[k][j] = + VTOMFN(&xen_phys_machine[i]); + } + HYPERVISOR_shared_info->arch.max_pfn = max_pfn; + + gnttab_resume(); + irq_resume(); + local_irq_enable(); + xencons_resume(); + +#ifdef CONFIG_SMP + for_each_cpu(i) + vcpu_prepare(i); + +#endif + /* + * Only resume xenbus /after/ we've prepared our VCPUs; otherwise + * the VCPU hotplug callback can race with our vcpu_prepare + */ + DEVICE_RESUME(root_bus); + +#ifdef SMP + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + if (map) + restart_cpus(map); +#endif +} + +static void +xen_pv_shutdown_final(void *arg, int howto) +{ + /* + * Inform the hypervisor that shutdown is complete. + * This is not necessary in HVM domains since Xen + * emulates ACPI in that mode and FreeBSD's ACPI + * support will request this transition. + */ + if (howto & (RB_HALT | RB_POWEROFF)) + HYPERVISOR_shutdown(SHUTDOWN_poweroff); + else + HYPERVISOR_shutdown(SHUTDOWN_reboot); +} + +#else +extern void xenpci_resume(void); + +/* HVM mode suspension. */ +static void +xctrl_suspend() +{ + int suspend_cancelled; + + if (DEVICE_SUSPEND(root_bus)) { + printf("xen_suspend: device_suspend failed\n"); + return; + } + + /* + * Make sure we don't change cpus or switch to some other + * thread. for the duration. + */ + critical_enter(); + + /* + * Prevent any races with evtchn_interrupt() handler. + */ + irq_suspend(); + disable_intr(); + + suspend_cancelled = HYPERVISOR_suspend(0); + if (!suspend_cancelled) + xenpci_resume(); + + /* + * Re-enable interrupts and put the scheduler back to normal. + */ + enable_intr(); + critical_exit(); + + /* + * FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or + * similar. + */ + if (!suspend_cancelled) + DEVICE_RESUME(root_bus); +} +#endif + +static void +xctrl_crash() +{ + panic("Xen directed crash"); +} + +static void +xctrl_halt() +{ + shutdown_nice(RB_HALT); +} + +/*------------------------------ Event Reception -----------------------------*/ +static void +xctrl_on_watch_event(struct xs_watch *watch, const char **vec, unsigned int len) +{ + struct xctrl_shutdown_reason *reason; + struct xctrl_shutdown_reason *last_reason; + char *result; + int error; + int result_len; + + error = xs_read(XST_NIL, "control", "shutdown", + &result_len, (void **)&result); + if (error != 0) + return; + + reason = xctrl_shutdown_reasons; + last_reason = reason + NUM_ELEMENTS(xctrl_shutdown_reasons); + while (reason < last_reason) { + + if (!strcmp(result, reason->name)) { + reason->handler(); + break; + } + reason++; + } + + free(result, M_XENSTORE); +} + +/*------------------ Private Device Attachment Functions --------------------*/ +/** + * \brief Identify instances of this device type in the system. + * + * \param driver The driver performing this identify action. + * \param parent The NewBus parent device for any devices this method adds. + */ +static void +xctrl_identify(driver_t *driver __unused, device_t parent) +{ + /* + * A single device instance for our driver is always present + * in a system operating under Xen. + */ + BUS_ADD_CHILD(parent, 0, driver->name, 0); +} + +/** + * \brief Probe for the existance of the Xen Control device + * + * \param dev NewBus device_t for this Xen control instance. + * + * \return Always returns 0 indicating success. + */ +static int +xctrl_probe(device_t dev) +{ + device_set_desc(dev, "Xen Control Device"); + + return (0); +} + +/** + * \brief Attach the Xen control device. + * + * \param dev NewBus device_t for this Xen control instance. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xctrl_attach(device_t dev) +{ + struct xctrl_softc *xctrl; + + xctrl = device_get_softc(dev); + + /* Activate watch */ + xctrl->xctrl_watch.node = "control/shutdown"; + xctrl->xctrl_watch.callback = xctrl_on_watch_event; + xs_register_watch(&xctrl->xctrl_watch); + +#ifndef XENHVM + EVENTHANDLER_REGISTER(shutdown_final, xen_pv_shutdown_final, NULL, + SHUTDOWN_PRI_LAST); +#endif + + return (0); +} + +/** + * \brief Detach the Xen control device. + * + * \param dev NewBus device_t for this Xen control device instance. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xctrl_detach(device_t dev) +{ + struct xctrl_softc *xctrl; + + xctrl = device_get_softc(dev); + + /* Release watch */ + xs_unregister_watch(&xctrl->xctrl_watch); + + return (0); +} + +/*-------------------- Private Device Attachment Data -----------------------*/ +static device_method_t xctrl_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, xctrl_identify), + DEVMETHOD(device_probe, xctrl_probe), + DEVMETHOD(device_attach, xctrl_attach), + DEVMETHOD(device_detach, xctrl_detach), + + { 0, 0 } +}; + +DEFINE_CLASS_0(xctrl, xctrl_driver, xctrl_methods, sizeof(struct xctrl_softc)); +devclass_t xctrl_devclass; + +DRIVER_MODULE(xctrl, xenstore, xctrl_driver, xctrl_devclass, 0, 0); diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c index a6fd9ea2886..423df976154 100644 --- a/sys/dev/xen/netfront/netfront.c +++ b/sys/dev/xen/netfront/netfront.c @@ -91,8 +91,6 @@ __FBSDID("$FreeBSD$"); #define XN_CSUM_FEATURES (CSUM_TCP | CSUM_UDP | CSUM_TSO) -#define GRANT_INVALID_REF 0 - #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) @@ -373,7 +371,8 @@ xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) { int i = xennet_rxidx(ri); grant_ref_t ref = np->grant_rx_ref[i]; - np->grant_rx_ref[i] = GRANT_INVALID_REF; + KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n")); + np->grant_rx_ref[i] = GRANT_REF_INVALID; return ref; } @@ -404,7 +403,7 @@ xen_net_read_mac(device_t dev, uint8_t mac[]) int error, i; char *s, *e, *macstr; - error = xenbus_read(XBT_NIL, xenbus_get_node(dev), "mac", NULL, + error = xs_read(XST_NIL, xenbus_get_node(dev), "mac", NULL, (void **) &macstr); if (error) return (error); @@ -413,12 +412,12 @@ xen_net_read_mac(device_t dev, uint8_t mac[]) for (i = 0; i < ETHER_ADDR_LEN; i++) { mac[i] = strtoul(s, &e, 16); if (s == e || (e[0] != ':' && e[0] != 0)) { - free(macstr, M_DEVBUF); + free(macstr, M_XENBUS); return (ENOENT); } s = &e[1]; } - free(macstr, M_DEVBUF); + free(macstr, M_XENBUS); return (0); } @@ -483,7 +482,7 @@ static int talk_to_backend(device_t dev, struct netfront_info *info) { const char *message; - struct xenbus_transaction xbt; + struct xs_transaction xst; const char *node = xenbus_get_node(dev); int err; @@ -499,54 +498,54 @@ talk_to_backend(device_t dev, struct netfront_info *info) goto out; again: - err = xenbus_transaction_start(&xbt); + err = xs_transaction_start(&xst); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); goto destroy_ring; } - err = xenbus_printf(xbt, node, "tx-ring-ref","%u", + err = xs_printf(xst, node, "tx-ring-ref","%u", info->tx_ring_ref); if (err) { message = "writing tx ring-ref"; goto abort_transaction; } - err = xenbus_printf(xbt, node, "rx-ring-ref","%u", + err = xs_printf(xst, node, "rx-ring-ref","%u", info->rx_ring_ref); if (err) { message = "writing rx ring-ref"; goto abort_transaction; } - err = xenbus_printf(xbt, node, + err = xs_printf(xst, node, "event-channel", "%u", irq_to_evtchn_port(info->irq)); if (err) { message = "writing event-channel"; goto abort_transaction; } - err = xenbus_printf(xbt, node, "request-rx-copy", "%u", + err = xs_printf(xst, node, "request-rx-copy", "%u", info->copying_receiver); if (err) { message = "writing request-rx-copy"; goto abort_transaction; } - err = xenbus_printf(xbt, node, "feature-rx-notify", "%d", 1); + err = xs_printf(xst, node, "feature-rx-notify", "%d", 1); if (err) { message = "writing feature-rx-notify"; goto abort_transaction; } - err = xenbus_printf(xbt, node, "feature-sg", "%d", 1); + err = xs_printf(xst, node, "feature-sg", "%d", 1); if (err) { message = "writing feature-sg"; goto abort_transaction; } #if __FreeBSD_version >= 700000 - err = xenbus_printf(xbt, node, "feature-gso-tcpv4", "%d", 1); + err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } #endif - err = xenbus_transaction_end(xbt, 0); + err = xs_transaction_end(xst, 0); if (err) { if (err == EAGAIN) goto again; @@ -557,7 +556,7 @@ talk_to_backend(device_t dev, struct netfront_info *info) return 0; abort_transaction: - xenbus_transaction_end(xbt, 1); + xs_transaction_end(xst, 1); xenbus_dev_fatal(dev, err, "%s", message); destroy_ring: netif_free(info); @@ -576,8 +575,8 @@ setup_device(device_t dev, struct netfront_info *info) ifp = info->xn_ifp; - info->tx_ring_ref = GRANT_INVALID_REF; - info->rx_ring_ref = GRANT_INVALID_REF; + info->tx_ring_ref = GRANT_REF_INVALID; + info->rx_ring_ref = GRANT_REF_INVALID; info->rx.sring = NULL; info->tx.sring = NULL; info->irq = 0; @@ -750,7 +749,7 @@ netif_release_tx_bufs(struct netfront_info *np) GNTMAP_readonly); gnttab_release_grant_reference(&np->gref_tx_head, np->grant_tx_ref[i]); - np->grant_tx_ref[i] = GRANT_INVALID_REF; + np->grant_tx_ref[i] = GRANT_REF_INVALID; add_id_to_freelist(np->tx_mbufs, i); np->xn_cdata.xn_tx_chain_cnt--; if (np->xn_cdata.xn_tx_chain_cnt < 0) { @@ -854,7 +853,8 @@ refill: sc->rx_mbufs[id] = m_new; ref = gnttab_claim_grant_reference(&sc->gref_rx_head); - KASSERT((short)ref >= 0, ("negative ref")); + KASSERT(ref != GNTTAB_LIST_END, + ("reserved grant references exhuasted")); sc->grant_rx_ref[id] = ref; vaddr = mtod(m_new, vm_offset_t); @@ -1135,7 +1135,7 @@ xn_txeof(struct netfront_info *np) np->grant_tx_ref[id]); gnttab_release_grant_reference( &np->gref_tx_head, np->grant_tx_ref[id]); - np->grant_tx_ref[id] = GRANT_INVALID_REF; + np->grant_tx_ref[id] = GRANT_REF_INVALID; np->tx_mbufs[id] = NULL; add_id_to_freelist(np->tx_mbufs, id); @@ -1318,12 +1318,13 @@ xennet_get_responses(struct netfront_info *np, * the backend driver. In future this should flag the bad * situation to the system controller to reboot the backed. */ - if (ref == GRANT_INVALID_REF) { + if (ref == GRANT_REF_INVALID) { #if 0 if (net_ratelimit()) WPRINTK("Bad rx response id %d.\n", rx->id); #endif + printf("%s: Bad rx response id %d.\n", __func__,rx->id); err = EINVAL; goto next; } @@ -1384,7 +1385,7 @@ next_skip_queue: err = ENOENT; printf("%s: cons %u frags %u rp %u, not enough frags\n", __func__, *cons, frags, rp); - break; + break; } /* * Note that m can be NULL, if rx->status < 0 or if @@ -1526,6 +1527,11 @@ xn_assemble_tx_request(struct netfront_info *sc, struct mbuf *m_head) * tell the TCP stack to generate a shorter chain of packets. */ if (nfrags > MAX_TX_REQ_FRAGS) { +#ifdef DEBUG + printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback " + "won't be able to handle it, dropping\n", + __func__, nfrags, MAX_TX_REQ_FRAGS); +#endif m_freem(m_head); return (EMSGSIZE); } @@ -1881,11 +1887,11 @@ network_connect(struct netfront_info *np) netif_rx_request_t *req; u_int feature_rx_copy, feature_rx_flip; - error = xenbus_scanf(XBT_NIL, xenbus_get_otherend_path(np->xbdev), + error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), "feature-rx-copy", NULL, "%u", &feature_rx_copy); if (error) feature_rx_copy = 0; - error = xenbus_scanf(XBT_NIL, xenbus_get_otherend_path(np->xbdev), + error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev), "feature-rx-flip", NULL, "%u", &feature_rx_flip); if (error) feature_rx_flip = 1; @@ -1999,14 +2005,14 @@ create_netdev(device_t dev) /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ for (i = 0; i <= NET_TX_RING_SIZE; i++) { np->tx_mbufs[i] = (void *) ((u_long) i+1); - np->grant_tx_ref[i] = GRANT_INVALID_REF; + np->grant_tx_ref[i] = GRANT_REF_INVALID; } np->tx_mbufs[NET_TX_RING_SIZE] = (void *)0; for (i = 0; i <= NET_RX_RING_SIZE; i++) { np->rx_mbufs[i] = NULL; - np->grant_rx_ref[i] = GRANT_INVALID_REF; + np->grant_rx_ref[i] = GRANT_REF_INVALID; } /* A grant for every tx ring slot */ if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, @@ -2128,8 +2134,8 @@ netif_disconnect_backend(struct netfront_info *info) end_access(info->tx_ring_ref, info->tx.sring); end_access(info->rx_ring_ref, info->rx.sring); - info->tx_ring_ref = GRANT_INVALID_REF; - info->rx_ring_ref = GRANT_INVALID_REF; + info->tx_ring_ref = GRANT_REF_INVALID; + info->rx_ring_ref = GRANT_REF_INVALID; info->tx.sring = NULL; info->rx.sring = NULL; @@ -2143,7 +2149,7 @@ netif_disconnect_backend(struct netfront_info *info) static void end_access(int ref, void *page) { - if (ref != GRANT_INVALID_REF) + if (ref != GRANT_REF_INVALID) gnttab_end_foreign_access(ref, page); } @@ -2171,7 +2177,7 @@ static device_method_t netfront_methods[] = { DEVMETHOD(device_resume, netfront_resume), /* Xenbus interface */ - DEVMETHOD(xenbus_backend_changed, netfront_backend_changed), + DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed), { 0, 0 } }; @@ -2183,4 +2189,4 @@ static driver_t netfront_driver = { }; devclass_t netfront_devclass; -DRIVER_MODULE(xe, xenbus, netfront_driver, netfront_devclass, 0, 0); +DRIVER_MODULE(xe, xenbusb_front, netfront_driver, netfront_devclass, 0, 0); diff --git a/sys/dev/xen/xenpci/evtchn.c b/sys/dev/xen/xenpci/evtchn.c index bdf3ad15572..ea53a7e371c 100644 --- a/sys/dev/xen/xenpci/evtchn.c +++ b/sys/dev/xen/xenpci/evtchn.c @@ -181,6 +181,49 @@ bind_listening_port_to_irqhandler(unsigned int remote_domain, return (0); } +int +bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain, + unsigned int remote_port, const char *devname, driver_intr_t handler, + void *arg, unsigned long irqflags, unsigned int *irqp) +{ + struct evtchn_bind_interdomain bind_interdomain; + unsigned int irq; + int error; + + irq = alloc_xen_irq(); + if (irq < 0) + return irq; + + mtx_lock(&irq_evtchn[irq].lock); + + bind_interdomain.remote_dom = remote_domain; + bind_interdomain.remote_port = remote_port; + error = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, + &bind_interdomain); + if (error) { + mtx_unlock(&irq_evtchn[irq].lock); + free_xen_irq(irq); + return (-error); + } + + irq_evtchn[irq].handler = handler; + irq_evtchn[irq].arg = arg; + irq_evtchn[irq].evtchn = bind_interdomain.local_port; + irq_evtchn[irq].close = 1; + irq_evtchn[irq].mpsafe = (irqflags & INTR_MPSAFE) != 0; + + evtchn_to_irq[bind_interdomain.local_port] = irq; + + unmask_evtchn(bind_interdomain.local_port); + + mtx_unlock(&irq_evtchn[irq].lock); + + if (irqp) + *irqp = irq; + return (0); +} + + int bind_caller_port_to_irqhandler(unsigned int caller_port, const char *devname, driver_intr_t handler, void *arg, diff --git a/sys/dev/xen/xenpci/xenpci.c b/sys/dev/xen/xenpci/xenpci.c index 2f2a79fff21..f4c9f73d686 100644 --- a/sys/dev/xen/xenpci/xenpci.c +++ b/sys/dev/xen/xenpci/xenpci.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); char *hypercall_stubs; shared_info_t *HYPERVISOR_shared_info; static vm_paddr_t shared_info_pa; +static device_t nexus; /* * This is used to find our platform device instance. @@ -80,7 +81,7 @@ xenpci_cpuid_base(void) { uint32_t base, regs[4]; - for (base = 0x40000000; base < 0x40001000; base += 0x100) { + for (base = 0x40000000; base < 0x40010000; base += 0x100) { do_cpuid(base, regs); if (!memcmp("XenVMMXenVMM", ®s[1], 12) && (regs[0] - base) >= 2) @@ -204,14 +205,21 @@ xenpci_allocate_resources(device_t dev) scp->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &scp->rid_irq, RF_SHAREABLE|RF_ACTIVE); - if (scp->res_irq == NULL) + if (scp->res_irq == NULL) { + printf("xenpci Could not allocate irq.\n"); goto errexit; + } scp->rid_memory = PCIR_BAR(1); scp->res_memory = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &scp->rid_memory, RF_ACTIVE); - if (scp->res_memory == NULL) + if (scp->res_memory == NULL) { + printf("xenpci Could not allocate memory bar.\n"); goto errexit; + } + + scp->phys_next = rman_get_start(scp->res_memory); + return (0); errexit: @@ -254,6 +262,36 @@ xenpci_alloc_space(size_t sz, vm_paddr_t *pa) } } +static struct resource * +xenpci_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + return (BUS_ALLOC_RESOURCE(nexus, child, type, rid, start, + end, count, flags)); +} + + +static int +xenpci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + return (BUS_RELEASE_RESOURCE(nexus, child, type, rid, r)); +} + +static int +xenpci_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + return (BUS_ACTIVATE_RESOURCE(nexus, child, type, rid, r)); +} + +static int +xenpci_deactivate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + return (BUS_DEACTIVATE_RESOURCE(nexus, child, type, rid, r)); +} + /* * Called very early in the resume sequence - reinitialise the various * bits of Xen machinery including the hypercall page and the shared @@ -303,20 +341,36 @@ xenpci_probe(device_t dev) static int xenpci_attach(device_t dev) { - int error; + int error; struct xenpci_softc *scp = device_get_softc(dev); struct xen_add_to_physmap xatp; vm_offset_t shared_va; + devclass_t dc; + + /* + * Find and record nexus0. Since we are not really on the + * PCI bus, all resource operations are directed to nexus + * instead of through our parent. + */ + if ((dc = devclass_find("nexus")) == 0 + || (nexus = devclass_get_device(dc, 0)) == 0) { + device_printf(dev, "unable to find nexus."); + return (ENOENT); + } error = xenpci_allocate_resources(dev); - if (error) + if (error) { + device_printf(dev, "xenpci_allocate_resources failed(%d).\n", + error); goto errexit; - - scp->phys_next = rman_get_start(scp->res_memory); + } error = xenpci_init_hypercall_stubs(dev, scp); - if (error) + if (error) { + device_printf(dev, "xenpci_init_hypercall_stubs failed(%d).\n", + error); goto errexit; + } setup_xen_features(); @@ -346,7 +400,7 @@ errexit: * Undo anything we may have done. */ xenpci_deallocate_resources(dev); - return (error); + return (error); } /* @@ -364,8 +418,9 @@ xenpci_detach(device_t dev) */ if (scp->intr_cookie != NULL) { if (BUS_TEARDOWN_INTR(parent, dev, - scp->res_irq, scp->intr_cookie) != 0) - printf("intr teardown failed.. continuing\n"); + scp->res_irq, scp->intr_cookie) != 0) + device_printf(dev, + "intr teardown failed.. continuing\n"); scp->intr_cookie = NULL; } @@ -386,6 +441,10 @@ static device_method_t xenpci_methods[] = { /* Bus interface */ DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_alloc_resource, xenpci_alloc_resource), + DEVMETHOD(bus_release_resource, xenpci_release_resource), + DEVMETHOD(bus_activate_resource, xenpci_activate_resource), + DEVMETHOD(bus_deactivate_resource, xenpci_deactivate_resource), { 0, 0 } }; diff --git a/sys/dev/xl/if_xl.c b/sys/dev/xl/if_xl.c index 05150af2b7f..0d77e12947e 100644 --- a/sys/dev/xl/if_xl.c +++ b/sys/dev/xl/if_xl.c @@ -246,6 +246,7 @@ static int xl_watchdog(struct xl_softc *); static int xl_shutdown(device_t); static int xl_suspend(device_t); static int xl_resume(device_t); +static void xl_setwol(struct xl_softc *); #ifdef DEVICE_POLLING static int xl_poll(struct ifnet *ifp, enum poll_cmd cmd, int count); @@ -522,16 +523,6 @@ xl_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - /* - * Pretend that PHYs are only available at MII address 24. - * This is to guard against problems with certain 3Com ASIC - * revisions that incorrectly map the internal transceiver - * control registers at all MII addresses. This can cause - * the miibus code to attach the same PHY several times over. - */ - if ((sc->xl_flags & XL_FLAG_PHYOK) == 0 && phy != 24) - return (0); - bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; @@ -549,9 +540,6 @@ xl_miibus_writereg(device_t dev, int phy, int reg, int data) sc = device_get_softc(dev); - if ((sc->xl_flags & XL_FLAG_PHYOK) == 0 && phy != 24) - return (0); - bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; frame.mii_regaddr = reg; @@ -1145,11 +1133,11 @@ static int xl_attach(device_t dev) { u_char eaddr[ETHER_ADDR_LEN]; - u_int16_t xcvr[2]; + u_int16_t sinfo2, xcvr[2]; struct xl_softc *sc; struct ifnet *ifp; - int media; - int unit, error = 0, rid, res; + int media, pmcap; + int error = 0, phy, rid, res, unit; uint16_t did; sc = device_get_softc(dev); @@ -1405,6 +1393,18 @@ xl_attach(device_t dev) else sc->xl_type = XL_TYPE_90X; + /* Check availability of WOL. */ + if ((sc->xl_caps & XL_CAPS_PWRMGMT) != 0 && + pci_find_extcap(dev, PCIY_PMG, &pmcap) == 0) { + sc->xl_pmcap = pmcap; + sc->xl_flags |= XL_FLAG_WOL; + sinfo2 = 0; + xl_read_eeprom(sc, (caddr_t)&sinfo2, XL_EE_SOFTINFO2, 1, 0); + if ((sinfo2 & XL_SINFO2_AUX_WOL_CON) == 0 && bootverbose) + device_printf(dev, + "No auxiliary remote wakeup connector!\n"); + } + /* Set the TX start threshold for best performance. */ sc->xl_tx_thresh = XL_MIN_FRAMELEN; @@ -1419,6 +1419,8 @@ xl_attach(device_t dev) ifp->if_capabilities |= IFCAP_HWCSUM; #endif } + if ((sc->xl_flags & XL_FLAG_WOL) != 0) + ifp->if_capabilities |= IFCAP_WOL_MAGIC; ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; @@ -1452,10 +1454,19 @@ xl_attach(device_t dev) if (bootverbose) device_printf(dev, "found MII/AUTO\n"); xl_setcfg(sc); - if (mii_phy_probe(dev, &sc->xl_miibus, - xl_ifmedia_upd, xl_ifmedia_sts)) { - device_printf(dev, "no PHY found!\n"); - error = ENXIO; + /* + * Attach PHYs only at MII address 24 if !XL_FLAG_PHYOK. + * This is to guard against problems with certain 3Com ASIC + * revisions that incorrectly map the internal transceiver + * control registers at all MII addresses. + */ + phy = MII_PHY_ANY; + if ((sc->xl_flags & XL_FLAG_PHYOK) != 0) + phy = 24; + error = mii_attach(dev, &sc->xl_miibus, ifp, xl_ifmedia_upd, + xl_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } goto done; @@ -1635,7 +1646,6 @@ xl_detach(device_t dev) /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { XL_LOCK(sc); - xl_reset(sc); xl_stop(sc); XL_UNLOCK(sc); taskqueue_drain(taskqueue_swi, &sc->xl_task); @@ -2246,7 +2256,7 @@ xl_intr(void *arg) } if (status & XL_STAT_ADFAIL) { - xl_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; xl_init_locked(sc); } @@ -2317,7 +2327,7 @@ xl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) } if (status & XL_STAT_ADFAIL) { - xl_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; xl_init_locked(sc); } @@ -2745,11 +2755,16 @@ xl_init_locked(struct xl_softc *sc) XL_LOCK_ASSERT(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; /* * Cancel pending I/O and free all RX/TX buffers. */ xl_stop(sc); + /* Reset the chip to a known state. */ + xl_reset(sc); + if (sc->xl_miibus == NULL) { CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_RESET); xl_wait(sc); @@ -2761,6 +2776,15 @@ xl_init_locked(struct xl_softc *sc) if (sc->xl_miibus != NULL) mii = device_get_softc(sc->xl_miibus); + /* + * Clear WOL status and disable all WOL feature as WOL + * would interfere Rx operation under normal environments. + */ + if ((sc->xl_flags & XL_FLAG_WOL) != 0) { + XL_SEL_WIN(7); + CSR_READ_2(sc, XL_W7_BM_PME); + CSR_WRITE_2(sc, XL_W7_BM_PME, 0); + } /* Init our MAC address */ XL_SEL_WIN(2); for (i = 0; i < ETHER_ADDR_LEN; i++) { @@ -2993,6 +3017,7 @@ xl_ifmedia_upd(struct ifnet *ifp) if (sc->xl_media & XL_MEDIAOPT_MII || sc->xl_media & XL_MEDIAOPT_BTX || sc->xl_media & XL_MEDIAOPT_BT4) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; xl_init_locked(sc); } else { xl_setmode(sc, ifm->ifm_media); @@ -3083,7 +3108,7 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct xl_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; - int error = 0; + int error = 0, mask; struct mii_data *mii = NULL; u_int8_t rxfilt; @@ -3108,10 +3133,8 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt); XL_SEL_WIN(7); - } else { - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - xl_init_locked(sc); - } + } else + xl_init_locked(sc); } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) xl_stop(sc); @@ -3143,40 +3166,50 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) &mii->mii_media, command); break; case SIOCSIFCAP: + mask = ifr->ifr_reqcap ^ ifp->if_capenable; #ifdef DEVICE_POLLING - if (ifr->ifr_reqcap & IFCAP_POLLING && - !(ifp->if_capenable & IFCAP_POLLING)) { - error = ether_poll_register(xl_poll, ifp); - if (error) - return(error); - XL_LOCK(sc); - /* Disable interrupts */ - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); - ifp->if_capenable |= IFCAP_POLLING; - XL_UNLOCK(sc); - return (error); - } - if (!(ifr->ifr_reqcap & IFCAP_POLLING) && - ifp->if_capenable & IFCAP_POLLING) { - error = ether_poll_deregister(ifp); - /* Enable interrupts. */ - XL_LOCK(sc); - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ACK|0xFF); - CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|XL_INTRS); - if (sc->xl_flags & XL_FLAG_FUNCREG) - bus_space_write_4(sc->xl_ftag, sc->xl_fhandle, - 4, 0x8000); - ifp->if_capenable &= ~IFCAP_POLLING; - XL_UNLOCK(sc); - return (error); + if ((mask & IFCAP_POLLING) != 0 && + (ifp->if_capabilities & IFCAP_POLLING) != 0) { + ifp->if_capenable ^= IFCAP_POLLING; + if ((ifp->if_capenable & IFCAP_POLLING) != 0) { + error = ether_poll_register(xl_poll, ifp); + if (error) + break; + XL_LOCK(sc); + /* Disable interrupts */ + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0); + ifp->if_capenable |= IFCAP_POLLING; + XL_UNLOCK(sc); + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupts. */ + XL_LOCK(sc); + CSR_WRITE_2(sc, XL_COMMAND, + XL_CMD_INTR_ACK | 0xFF); + CSR_WRITE_2(sc, XL_COMMAND, + XL_CMD_INTR_ENB | XL_INTRS); + if (sc->xl_flags & XL_FLAG_FUNCREG) + bus_space_write_4(sc->xl_ftag, + sc->xl_fhandle, 4, 0x8000); + XL_UNLOCK(sc); + } } #endif /* DEVICE_POLLING */ XL_LOCK(sc); - ifp->if_capenable = ifr->ifr_reqcap; - if (ifp->if_capenable & IFCAP_TXCSUM) - ifp->if_hwassist = XL905B_CSUM_FEATURES; - else - ifp->if_hwassist = 0; + if ((mask & IFCAP_TXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { + ifp->if_capenable ^= IFCAP_TXCSUM; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist |= XL905B_CSUM_FEATURES; + else + ifp->if_hwassist &= ~XL905B_CSUM_FEATURES; + } + if ((mask & IFCAP_RXCSUM) != 0 && + (ifp->if_capabilities & IFCAP_RXCSUM) != 0) + ifp->if_capenable ^= IFCAP_RXCSUM; + if ((mask & IFCAP_WOL_MAGIC) != 0 && + (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; XL_UNLOCK(sc); break; default: @@ -3226,7 +3259,7 @@ xl_watchdog(struct xl_softc *sc) device_printf(sc->xl_dev, "no carrier - transceiver cable problem?\n"); - xl_reset(sc); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; xl_init_locked(sc); if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { @@ -3319,16 +3352,8 @@ xl_stop(struct xl_softc *sc) static int xl_shutdown(device_t dev) { - struct xl_softc *sc; - sc = device_get_softc(dev); - - XL_LOCK(sc); - xl_reset(sc); - xl_stop(sc); - XL_UNLOCK(sc); - - return (0); + return (xl_suspend(dev)); } static int @@ -3340,6 +3365,7 @@ xl_suspend(device_t dev) XL_LOCK(sc); xl_stop(sc); + xl_setwol(sc); XL_UNLOCK(sc); return (0); @@ -3356,11 +3382,43 @@ xl_resume(device_t dev) XL_LOCK(sc); - xl_reset(sc); - if (ifp->if_flags & IFF_UP) + if (ifp->if_flags & IFF_UP) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; xl_init_locked(sc); + } XL_UNLOCK(sc); return (0); } + +static void +xl_setwol(struct xl_softc *sc) +{ + struct ifnet *ifp; + u_int16_t cfg, pmstat; + + if ((sc->xl_flags & XL_FLAG_WOL) == 0) + return; + + ifp = sc->xl_ifp; + XL_SEL_WIN(7); + /* Clear any pending PME events. */ + CSR_READ_2(sc, XL_W7_BM_PME); + cfg = 0; + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + cfg |= XL_BM_PME_MAGIC; + CSR_WRITE_2(sc, XL_W7_BM_PME, cfg); + /* Enable RX. */ + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_ENABLE); + /* Request PME. */ + pmstat = pci_read_config(sc->xl_dev, + sc->xl_pmcap + PCIR_POWER_STATUS, 2); + if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) + pmstat |= PCIM_PSTAT_PMEENABLE; + else + pmstat &= ~PCIM_PSTAT_PMEENABLE; + pci_write_config(sc->xl_dev, + sc->xl_pmcap + PCIR_POWER_STATUS, pmstat, 2); +} diff --git a/sys/dev/xl/if_xlreg.h b/sys/dev/xl/if_xlreg.h index 538661410d5..2685c44a592 100644 --- a/sys/dev/xl/if_xlreg.h +++ b/sys/dev/xl/if_xlreg.h @@ -81,6 +81,17 @@ #define XL_CAPS_100MBPS 0x1000 #define XL_CAPS_PWRMGMT 0x2000 +/* + * Bits in the software information 2 word + */ +#define XL_SINFO2_FIXED_BCAST_RX_BUG 0x0002 +#define XL_SINFO2_FIXED_ENDEC_LOOP_BUG 0x0004 +#define XL_SINFO2_AUX_WOL_CON 0x0008 +#define XL_SINFO2_PME_PULSED 0x0010 +#define XL_SINFO2_FIXED_MWI_BUG 0x0020 +#define XL_SINFO2_WOL_AFTER_PWR_LOSS 0x0040 +#define XL_SINFO2_AUTO_RST_TO_D0 0x0080 + #define XL_PACKET_SIZE 1540 #define XL_MAX_FRAMELEN (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) @@ -408,7 +419,12 @@ #define XL_W7_BM_LEN 0x06 #define XL_W7_BM_STATUS 0x0B #define XL_W7_BM_TIMEr 0x0A +#define XL_W7_BM_PME 0x0C +#define XL_BM_PME_WAKE 0x0001 +#define XL_BM_PME_MAGIC 0x0002 +#define XL_BM_PME_LINKCHG 0x0004 +#define XL_BM_PME_WAKETIMER 0x0008 /* * bus master control registers */ @@ -577,6 +593,7 @@ struct xl_mii_frame { #define XL_FLAG_NO_XCVR_PWR 0x0080 #define XL_FLAG_USE_MMIO 0x0100 #define XL_FLAG_NO_MMIO 0x0200 +#define XL_FLAG_WOL 0x0400 #define XL_NO_XCVR_PWR_MAGICBITS 0x0900 @@ -599,6 +616,7 @@ struct xl_softc { u_int16_t xl_caps; u_int8_t xl_stats_no_timeout; u_int16_t xl_tx_thresh; + int xl_pmcap; int xl_if_flags; struct xl_list_data xl_ldata; struct xl_chain_data xl_cdata; diff --git a/sys/fs/cd9660/cd9660_mount.h b/sys/fs/cd9660/cd9660_mount.h index 518677d19ae..f59dfc0c687 100644 --- a/sys/fs/cd9660/cd9660_mount.h +++ b/sys/fs/cd9660/cd9660_mount.h @@ -40,7 +40,7 @@ */ struct iso_args { char *fspec; /* block special device to mount */ - struct export_args export; /* network export info */ + struct oexport_args export; /* network export info */ int flags; /* mounting flags, see below */ int ssector; /* starting sector, 0 for 1st session */ char *cs_disk; /* disk charset for Joliet cs conversion */ diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c index e27daf8bb04..77757f2c64f 100644 --- a/sys/fs/cd9660/cd9660_vfsops.c +++ b/sys/fs/cd9660/cd9660_vfsops.c @@ -98,14 +98,16 @@ static int cd9660_cmount(struct mntarg *ma, void *data, int flags) { struct iso_args args; + struct export_args exp; int error; error = copyin(data, &args, sizeof args); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); ma = mount_argsu(ma, "cs_disk", args.cs_disk, 64); ma = mount_argsu(ma, "cs_local", args.cs_local, 64); ma = mount_argf(ma, "ssector", "%u", args.ssector); diff --git a/sys/fs/devfs/devfs.h b/sys/fs/devfs/devfs.h index ee5eafb31c8..d148f8e487c 100644 --- a/sys/fs/devfs/devfs.h +++ b/sys/fs/devfs/devfs.h @@ -122,6 +122,10 @@ struct devfs_rule { MALLOC_DECLARE(M_DEVFS); #endif +struct componentname; + +TAILQ_HEAD(devfs_dlist_head, devfs_dirent); + struct devfs_dirent { struct cdev_priv *de_cdp; int de_inode; @@ -131,10 +135,11 @@ struct devfs_dirent { #define DE_DOTDOT 0x04 #define DE_DOOMED 0x08 #define DE_COVERED 0x10 +#define DE_USER 0x20 int de_holdcnt; struct dirent *de_dirent; TAILQ_ENTRY(devfs_dirent) de_list; - TAILQ_HEAD(, devfs_dirent) de_dlist; + struct devfs_dlist_head de_dlist; struct devfs_dirent *de_dir; int de_links; mode_t de_mode; @@ -170,20 +175,28 @@ extern unsigned devfs_rule_depth; #define DEVFS_DMP_HOLD(dmp) ((dmp)->dm_holdcnt++) #define DEVFS_DMP_DROP(dmp) (--(dmp)->dm_holdcnt == 0) -void devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de); -void devfs_rules_cleanup (struct devfs_mount *dm); -int devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td); -int devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, - struct vnode **vpp); -void devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int vp_locked); -void devfs_dirent_free(struct devfs_dirent *de); -void devfs_populate (struct devfs_mount *dm); -void devfs_cleanup (struct devfs_mount *dm); -void devfs_unmount_final(struct devfs_mount *mp); -struct devfs_dirent *devfs_newdirent (char *name, int namelen); -struct devfs_dirent *devfs_parent_dirent(struct devfs_dirent *de); -struct devfs_dirent *devfs_vmkdir (struct devfs_mount *, char *name, int namelen, struct devfs_dirent *dotdot, u_int inode); -struct devfs_dirent *devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type); +#define DEVFS_DEL_VNLOCKED 0x01 +#define DEVFS_DEL_NORECURSE 0x02 + +void devfs_rules_apply(struct devfs_mount *, struct devfs_dirent *); +void devfs_rules_cleanup(struct devfs_mount *); +int devfs_rules_ioctl(struct devfs_mount *, u_long, caddr_t, + struct thread *); +int devfs_allocv(struct devfs_dirent *, struct mount *, int, + struct vnode **); +char *devfs_fqpn(char *, struct devfs_mount *, struct devfs_dirent *, + struct componentname *); +void devfs_delete(struct devfs_mount *, struct devfs_dirent *, int); +void devfs_dirent_free(struct devfs_dirent *); +void devfs_populate(struct devfs_mount *); +void devfs_cleanup(struct devfs_mount *); +void devfs_unmount_final(struct devfs_mount *); +struct devfs_dirent *devfs_newdirent(char *, int); +struct devfs_dirent *devfs_parent_dirent(struct devfs_dirent *); +struct devfs_dirent *devfs_vmkdir(struct devfs_mount *, char *, int, + struct devfs_dirent *, u_int); +struct devfs_dirent *devfs_find(struct devfs_dirent *, const char *, int, + int); #endif /* _KERNEL */ diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index a11544f8003..52e6567069b 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -142,6 +142,27 @@ devfs_alloc(int flags) return (cdev); } +int +devfs_dev_exists(const char *name) +{ + struct cdev_priv *cdp; + + mtx_assert(&devmtx, MA_OWNED); + + TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) { + if ((cdp->cdp_flags & CDP_ACTIVE) == 0) + continue; + if (devfs_pathpath(cdp->cdp_c.si_name, name) != 0) + return (1); + if (devfs_pathpath(name, cdp->cdp_c.si_name) != 0) + return (1); + } + if (devfs_dir_find(name) != 0) + return (1); + + return (0); +} + void devfs_free(struct cdev *cdev) { @@ -171,6 +192,8 @@ devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type) continue; break; } + KASSERT(de == NULL || (de->de_flags & DE_DOOMED) == 0, + ("devfs_find: returning a doomed entry")); return (de); } @@ -274,18 +297,75 @@ devfs_dirent_free(struct devfs_dirent *de) free(de, M_DEVFS3); } +/* + * Removes a directory if it is empty. Also empty parent directories are + * removed recursively. + */ +static void +devfs_rmdir_empty(struct devfs_mount *dm, struct devfs_dirent *de) +{ + struct devfs_dirent *dd, *de_dot, *de_dotdot; + + sx_assert(&dm->dm_lock, SX_XLOCKED); + + for (;;) { + KASSERT(de->de_dirent->d_type == DT_DIR, + ("devfs_rmdir_empty: de is not a directory")); + + if ((de->de_flags & DE_DOOMED) != 0 || de == dm->dm_rootdir) + return; + + de_dot = TAILQ_FIRST(&de->de_dlist); + KASSERT(de_dot != NULL, ("devfs_rmdir_empty: . missing")); + de_dotdot = TAILQ_NEXT(de_dot, de_list); + KASSERT(de_dotdot != NULL, ("devfs_rmdir_empty: .. missing")); + /* Return if the directory is not empty. */ + if (TAILQ_NEXT(de_dotdot, de_list) != NULL) + return; + + dd = devfs_parent_dirent(de); + KASSERT(dd != NULL, ("devfs_rmdir_empty: NULL dd")); + TAILQ_REMOVE(&de->de_dlist, de_dot, de_list); + TAILQ_REMOVE(&de->de_dlist, de_dotdot, de_list); + TAILQ_REMOVE(&dd->de_dlist, de, de_list); + DEVFS_DE_HOLD(dd); + devfs_delete(dm, de, DEVFS_DEL_NORECURSE); + devfs_delete(dm, de_dot, DEVFS_DEL_NORECURSE); + devfs_delete(dm, de_dotdot, DEVFS_DEL_NORECURSE); + if (DEVFS_DE_DROP(dd)) { + devfs_dirent_free(dd); + return; + } + + de = dd; + } +} + /* * The caller needs to hold the dm for the duration of the call since * dm->dm_lock may be temporary dropped. */ void -devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int vp_locked) +devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int flags) { + struct devfs_dirent *dd; struct vnode *vp; KASSERT((de->de_flags & DE_DOOMED) == 0, ("devfs_delete doomed dirent")); de->de_flags |= DE_DOOMED; + + if ((flags & DEVFS_DEL_NORECURSE) == 0) { + dd = devfs_parent_dirent(de); + if (dd != NULL) + DEVFS_DE_HOLD(dd); + if (de->de_flags & DE_USER) { + KASSERT(dd != NULL, ("devfs_delete: NULL dd")); + devfs_dir_unref_de(dm, dd); + } + } else + dd = NULL; + mtx_lock(&devfs_de_interlock); vp = de->de_vnode; if (vp != NULL) { @@ -293,12 +373,12 @@ devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int vp_locked) mtx_unlock(&devfs_de_interlock); vholdl(vp); sx_unlock(&dm->dm_lock); - if (!vp_locked) + if ((flags & DEVFS_DEL_VNLOCKED) == 0) vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY); else VI_UNLOCK(vp); vgone(vp); - if (!vp_locked) + if ((flags & DEVFS_DEL_VNLOCKED) == 0) VOP_UNLOCK(vp, 0); vdrop(vp); sx_xlock(&dm->dm_lock); @@ -317,6 +397,13 @@ devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int vp_locked) } if (DEVFS_DE_DROP(de)) devfs_dirent_free(de); + + if (dd != NULL) { + if (DEVFS_DE_DROP(dd)) + devfs_dirent_free(dd); + else + devfs_rmdir_empty(dm, dd); + } } /* @@ -331,19 +418,31 @@ devfs_purge(struct devfs_mount *dm, struct devfs_dirent *dd) struct devfs_dirent *de; sx_assert(&dm->dm_lock, SX_XLOCKED); + + DEVFS_DE_HOLD(dd); for (;;) { - de = TAILQ_FIRST(&dd->de_dlist); + /* + * Use TAILQ_LAST() to remove "." and ".." last. + * We might need ".." to resolve a path in + * devfs_dir_unref_de(). + */ + de = TAILQ_LAST(&dd->de_dlist, devfs_dlist_head); if (de == NULL) break; TAILQ_REMOVE(&dd->de_dlist, de, de_list); - if (de->de_flags & (DE_DOT|DE_DOTDOT)) - devfs_delete(dm, de, 0); + if (de->de_flags & DE_USER) + devfs_dir_unref_de(dm, dd); + if (de->de_flags & (DE_DOT | DE_DOTDOT)) + devfs_delete(dm, de, DEVFS_DEL_NORECURSE); else if (de->de_dirent->d_type == DT_DIR) devfs_purge(dm, de); - else - devfs_delete(dm, de, 0); + else + devfs_delete(dm, de, DEVFS_DEL_NORECURSE); } - devfs_delete(dm, dd, 0); + if (DEVFS_DE_DROP(dd)) + devfs_dirent_free(dd); + else if ((dd->de_flags & DE_DOOMED) == 0) + devfs_delete(dm, dd, DEVFS_DEL_NORECURSE); } /* diff --git a/sys/fs/devfs/devfs_dir.c b/sys/fs/devfs/devfs_dir.c new file mode 100644 index 00000000000..c497e554258 --- /dev/null +++ b/sys/fs/devfs/devfs_dir.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 2010 Jaakko Heinonen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct dirlistent { + char *dir; + int refcnt; + LIST_ENTRY(dirlistent) link; +}; + +static LIST_HEAD(, dirlistent) devfs_dirlist = + LIST_HEAD_INITIALIZER(devfs_dirlist); + +static MALLOC_DEFINE(M_DEVFS4, "DEVFS4", "DEVFS directory list"); + +static struct mtx dirlist_mtx; +MTX_SYSINIT(dirlist_mtx, &dirlist_mtx, "devfs dirlist lock", MTX_DEF); + +/* Returns 1 if the path is in the directory list. */ +int +devfs_dir_find(const char *path) +{ + struct dirlistent *dle; + + mtx_lock(&dirlist_mtx); + LIST_FOREACH(dle, &devfs_dirlist, link) { + if (devfs_pathpath(dle->dir, path) != 0) { + mtx_unlock(&dirlist_mtx); + return (1); + } + } + mtx_unlock(&dirlist_mtx); + + return (0); +} + +static struct dirlistent * +devfs_dir_findent_locked(const char *dir) +{ + struct dirlistent *dle; + + mtx_assert(&dirlist_mtx, MA_OWNED); + + LIST_FOREACH(dle, &devfs_dirlist, link) { + if (strcmp(dir, dle->dir) == 0) + return (dle); + } + + return (NULL); +} + +static void +devfs_dir_ref(const char *dir) +{ + struct dirlistent *dle, *dle_new; + + if (*dir == '\0') + return; + + dle_new = malloc(sizeof(*dle), M_DEVFS4, M_WAITOK); + dle_new->dir = strdup(dir, M_DEVFS4); + dle_new->refcnt = 1; + + mtx_lock(&dirlist_mtx); + dle = devfs_dir_findent_locked(dir); + if (dle != NULL) { + dle->refcnt++; + mtx_unlock(&dirlist_mtx); + free(dle_new->dir, M_DEVFS4); + free(dle_new, M_DEVFS4); + return; + } + LIST_INSERT_HEAD(&devfs_dirlist, dle_new, link); + mtx_unlock(&dirlist_mtx); +} + +void +devfs_dir_ref_de(struct devfs_mount *dm, struct devfs_dirent *de) +{ + char dirname[SPECNAMELEN + 1], *namep; + + namep = devfs_fqpn(dirname, dm, de, NULL); + KASSERT(namep != NULL, ("devfs_ref_dir_de: NULL namep")); + + devfs_dir_ref(namep); +} + +static void +devfs_dir_unref(const char *dir) +{ + struct dirlistent *dle; + + if (*dir == '\0') + return; + + mtx_lock(&dirlist_mtx); + dle = devfs_dir_findent_locked(dir); + KASSERT(dle != NULL, ("devfs_dir_unref: dir %s not referenced", dir)); + dle->refcnt--; + KASSERT(dle->refcnt >= 0, ("devfs_dir_unref: negative refcnt")); + if (dle->refcnt == 0) { + LIST_REMOVE(dle, link); + mtx_unlock(&dirlist_mtx); + free(dle->dir, M_DEVFS4); + free(dle, M_DEVFS4); + } else + mtx_unlock(&dirlist_mtx); +} + +void +devfs_dir_unref_de(struct devfs_mount *dm, struct devfs_dirent *de) +{ + char dirname[SPECNAMELEN + 1], *namep; + + namep = devfs_fqpn(dirname, dm, de, NULL); + KASSERT(namep != NULL, ("devfs_unref_dir_de: NULL namep")); + + devfs_dir_unref(namep); +} + +/* Returns 1 if the path p1 contains the path p2. */ +int +devfs_pathpath(const char *p1, const char *p2) +{ + + for (;;p1++, p2++) { + if (*p1 != *p2) { + if (*p1 == '/' && *p2 == '\0') + return (1); + else + return (0); + } else if (*p1 == '\0') + return (1); + } + /* NOTREACHED */ +} diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h index f5612e1580f..cdc6aba74e7 100644 --- a/sys/fs/devfs/devfs_int.h +++ b/sys/fs/devfs/devfs_int.h @@ -38,6 +38,7 @@ #ifdef _KERNEL struct devfs_dirent; +struct devfs_mount; struct cdev_privdata { struct file *cdpd_fp; @@ -70,11 +71,17 @@ struct cdev_priv { #define cdev2priv(c) member2struct(cdev_priv, cdp_c, c) -struct cdev *devfs_alloc(int); -void devfs_free(struct cdev *); -void devfs_create(struct cdev *dev); -void devfs_destroy(struct cdev *dev); -void devfs_destroy_cdevpriv(struct cdev_privdata *p); +struct cdev *devfs_alloc(int); +int devfs_dev_exists(const char *); +void devfs_free(struct cdev *); +void devfs_create(struct cdev *); +void devfs_destroy(struct cdev *); +void devfs_destroy_cdevpriv(struct cdev_privdata *); + +int devfs_dir_find(const char *); +void devfs_dir_ref_de(struct devfs_mount *, struct devfs_dirent *); +void devfs_dir_unref_de(struct devfs_mount *, struct devfs_dirent *); +int devfs_pathpath(const char *, const char *); extern struct unrhdr *devfs_inos; extern struct mtx devmtx; diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 542ecaed35e..5f1063dbadd 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -36,7 +36,6 @@ /* * TODO: - * remove empty directories * mkdir: want it ? */ @@ -185,6 +184,51 @@ devfs_clear_cdevpriv(void) devfs_fpdrop(fp); } +/* + * On success devfs_populate_vp() returns with dmp->dm_lock held. + */ +static int +devfs_populate_vp(struct vnode *vp) +{ + struct devfs_dirent *de; + struct devfs_mount *dmp; + int locked; + + ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); + + dmp = VFSTODEVFS(vp->v_mount); + locked = VOP_ISLOCKED(vp); + + sx_xlock(&dmp->dm_lock); + DEVFS_DMP_HOLD(dmp); + + /* Can't call devfs_populate() with the vnode lock held. */ + VOP_UNLOCK(vp, 0); + devfs_populate(dmp); + + sx_xunlock(&dmp->dm_lock); + vn_lock(vp, locked | LK_RETRY); + sx_xlock(&dmp->dm_lock); + if (DEVFS_DMP_DROP(dmp)) { + sx_xunlock(&dmp->dm_lock); + devfs_unmount_final(dmp); + return (EBADF); + } + if ((vp->v_iflag & VI_DOOMED) != 0) { + sx_xunlock(&dmp->dm_lock); + return (EBADF); + } + de = vp->v_data; + KASSERT(de != NULL, + ("devfs_populate_vp: vp->v_data == NULL but vnode not doomed")); + if ((de->de_flags & DE_DOOMED) != 0) { + sx_xunlock(&dmp->dm_lock); + return (EBADF); + } + + return (0); +} + static int devfs_vptocnp(struct vop_vptocnp_args *ap) { @@ -197,11 +241,13 @@ devfs_vptocnp(struct vop_vptocnp_args *ap) int i, error; dmp = VFSTODEVFS(vp->v_mount); + + error = devfs_populate_vp(vp); + if (error != 0) + return (error); + i = *buflen; dd = vp->v_data; - error = 0; - - sx_xlock(&dmp->dm_lock); if (vp->v_type == VCHR) { i -= strlen(dd->de_cdp->cdp_c.si_name); @@ -253,29 +299,34 @@ finished: } /* - * Construct the fully qualified path name relative to the mountpoint + * Construct the fully qualified path name relative to the mountpoint. + * If a NULL cnp is provided, no '/' is appended to the resulting path. */ -static char * -devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp) +char * +devfs_fqpn(char *buf, struct devfs_mount *dmp, struct devfs_dirent *dd, + struct componentname *cnp) { int i; - struct devfs_dirent *de, *dd; - struct devfs_mount *dmp; + struct devfs_dirent *de; + + sx_assert(&dmp->dm_lock, SA_LOCKED); - dmp = VFSTODEVFS(dvp->v_mount); - dd = dvp->v_data; i = SPECNAMELEN; buf[i] = '\0'; - i -= cnp->cn_namelen; + if (cnp != NULL) + i -= cnp->cn_namelen; if (i < 0) return (NULL); - bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); + if (cnp != NULL) + bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); de = dd; while (de != dmp->dm_rootdir) { - i--; - if (i < 0) - return (NULL); - buf[i] = '/'; + if (cnp != NULL || i < SPECNAMELEN) { + i--; + if (i < 0) + return (NULL); + buf[i] = '/'; + } i -= de->de_dirent->d_namlen; if (i < 0) return (NULL); @@ -412,8 +463,8 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, int lockmode, } else { vp->v_type = VBAD; } - VN_LOCK_ASHARE(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_NOWITNESS); + VN_LOCK_ASHARE(vp); mtx_lock(&devfs_de_interlock); vp->v_data = de; de->de_vnode = vp; @@ -581,10 +632,18 @@ devfs_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; - int error = 0; + int error; struct devfs_dirent *de; + struct devfs_mount *dmp; struct cdev *dev; + error = devfs_populate_vp(vp); + if (error != 0) + return (error); + + dmp = VFSTODEVFS(vp->v_mount); + sx_xunlock(&dmp->dm_lock); + de = vp->v_data; KASSERT(de != NULL, ("Null dirent in devfs_getattr vp=%p", vp)); if (vp->v_type == VDIR) { @@ -813,14 +872,6 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) return (error); } - DEVFS_DMP_HOLD(dmp); - devfs_populate(dmp); - if (DEVFS_DMP_DROP(dmp)) { - *dm_unlock = 0; - sx_xunlock(&dmp->dm_lock); - devfs_unmount_final(dmp); - return (ENOENT); - } dd = dvp->v_data; de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen, 0); while (de == NULL) { /* While(...) so we can use break */ @@ -832,7 +883,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) * OK, we didn't have an entry for the name we were asked for * so we try to see if anybody can create it on demand. */ - pname = devfs_fqpn(specname, dvp, cnp); + pname = devfs_fqpn(specname, dmp, dd, cnp); if (pname == NULL) break; @@ -843,25 +894,32 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) EVENTHANDLER_INVOKE(dev_clone, td->td_ucred, pname, strlen(pname), &cdev); sx_sunlock(&clone_drain_lock); - sx_xlock(&dmp->dm_lock); + + if (cdev == NULL) + sx_xlock(&dmp->dm_lock); + else if (devfs_populate_vp(dvp) != 0) { + *dm_unlock = 0; + sx_xlock(&dmp->dm_lock); + if (DEVFS_DMP_DROP(dmp)) { + sx_xunlock(&dmp->dm_lock); + devfs_unmount_final(dmp); + } else + sx_xunlock(&dmp->dm_lock); + dev_rel(cdev); + return (ENOENT); + } if (DEVFS_DMP_DROP(dmp)) { *dm_unlock = 0; sx_xunlock(&dmp->dm_lock); devfs_unmount_final(dmp); + if (cdev != NULL) + dev_rel(cdev); return (ENOENT); } + if (cdev == NULL) break; - DEVFS_DMP_HOLD(dmp); - devfs_populate(dmp); - if (DEVFS_DMP_DROP(dmp)) { - *dm_unlock = 0; - sx_xunlock(&dmp->dm_lock); - devfs_unmount_final(dmp); - return (ENOENT); - } - dev_lock(); dde = &cdev2priv(cdev)->cdp_dirents[dmp->dm_idx]; if (dde != NULL && *dde != NULL) @@ -906,9 +964,11 @@ devfs_lookup(struct vop_lookup_args *ap) struct devfs_mount *dmp; int dm_unlock; + if (devfs_populate_vp(ap->a_dvp) != 0) + return (ENOTDIR); + dmp = VFSTODEVFS(ap->a_dvp->v_mount); dm_unlock = 1; - sx_xlock(&dmp->dm_lock); j = devfs_lookupx(ap, &dm_unlock); if (dm_unlock == 1) sx_xunlock(&dmp->dm_lock); @@ -1136,12 +1196,7 @@ devfs_readdir(struct vop_readdir_args *ap) } dmp = VFSTODEVFS(ap->a_vp->v_mount); - sx_xlock(&dmp->dm_lock); - DEVFS_DMP_HOLD(dmp); - devfs_populate(dmp); - if (DEVFS_DMP_DROP(dmp)) { - sx_xunlock(&dmp->dm_lock); - devfs_unmount_final(dmp); + if (devfs_populate_vp(ap->a_vp) != 0) { if (tmp_ncookies != NULL) ap->a_ncookies = tmp_ncookies; return (EIO); @@ -1230,11 +1285,15 @@ devfs_reclaim(struct vop_reclaim_args *ap) static int devfs_remove(struct vop_remove_args *ap) { + struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; struct devfs_dirent *dd; struct devfs_dirent *de, *de_covered; struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); + ASSERT_VOP_ELOCKED(dvp, "devfs_remove"); + ASSERT_VOP_ELOCKED(vp, "devfs_remove"); + sx_xlock(&dmp->dm_lock); dd = ap->a_dvp->v_data; de = vp->v_data; @@ -1246,11 +1305,19 @@ devfs_remove(struct vop_remove_args *ap) if (de_covered != NULL) de_covered->de_flags &= ~DE_COVERED; } - devfs_delete(dmp, de, 1); + /* We need to unlock dvp because devfs_delete() may lock it. */ + VOP_UNLOCK(vp, 0); + if (dvp != vp) + VOP_UNLOCK(dvp, 0); + devfs_delete(dmp, de, 0); + sx_xunlock(&dmp->dm_lock); + if (dvp != vp) + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); } else { de->de_flags |= DE_WHITEOUT; + sx_xunlock(&dmp->dm_lock); } - sx_xunlock(&dmp->dm_lock); return (0); } @@ -1492,17 +1559,21 @@ devfs_symlink(struct vop_symlink_args *ap) if (error) return(error); dmp = VFSTODEVFS(ap->a_dvp->v_mount); + if (devfs_populate_vp(ap->a_dvp) != 0) + return (ENOENT); + dd = ap->a_dvp->v_data; de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); + de->de_flags = DE_USER; de->de_uid = 0; de->de_gid = 0; de->de_mode = 0755; de->de_inode = alloc_unr(devfs_inos); + de->de_dir = dd; de->de_dirent->d_type = DT_LNK; i = strlen(ap->a_target) + 1; de->de_symlink = malloc(i, M_DEVFS, M_WAITOK); bcopy(ap->a_target, de->de_symlink, i); - sx_xlock(&dmp->dm_lock); #ifdef MAC mac_devfs_create_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); #endif @@ -1517,6 +1588,7 @@ devfs_symlink(struct vop_symlink_args *ap) de_dotdot = TAILQ_FIRST(&dd->de_dlist); /* "." */ de_dotdot = TAILQ_NEXT(de_dotdot, de_list); /* ".." */ TAILQ_INSERT_AFTER(&dd->de_dlist, de_dotdot, de, de_list); + devfs_dir_ref_de(dmp, dd); return (devfs_allocv(de, ap->a_dvp->v_mount, LK_EXCLUSIVE, ap->a_vpp)); } diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index 1095100aa9b..6f244957b45 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -75,20 +75,6 @@ static daddr_t ext2_mapsearch(struct m_ext2fs *, char *, daddr_t); * inode for the file. * 2) quadradically rehash into other cylinder groups, until an * available block is located. - * - * A preference may be optionally specified. If a preference is given - * the following hierarchy is used to allocate a block: - * 1) allocate the requested block. - * 2) allocate a rotationally optimal block in the same cylinder. - * 3) allocate a block in the same cylinder group. - * 4) quadradically rehash into other cylinder groups, until an - * available block is located. - * If no block preference is given the following hierarchy is used - * to allocate a block: - * 1) allocate a block in the cylinder group that contains the - * inode for the file. - * 2) quadradically rehash into other cylinder groups, until an - * available block is located. */ int diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c index 9aa95ffd3c3..676b5c711ed 100644 --- a/sys/fs/hpfs/hpfs_vfsops.c +++ b/sys/fs/hpfs/hpfs_vfsops.c @@ -76,14 +76,16 @@ hpfs_cmount ( int flags) { struct hpfs_args args; + struct export_args exp; int error; error = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args)); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); ma = mount_argf(ma, "uid", "%d", args.uid); ma = mount_argf(ma, "gid", "%d", args.gid); ma = mount_argf(ma, "mode", "%d", args.mode); diff --git a/sys/fs/hpfs/hpfsmount.h b/sys/fs/hpfs/hpfsmount.h index 3566776b96a..5ca42b3bf66 100644 --- a/sys/fs/hpfs/hpfsmount.h +++ b/sys/fs/hpfs/hpfsmount.h @@ -29,7 +29,7 @@ #define HPFSMNT_TABLES 0x0001 struct hpfs_args { char *fspec; /* block special device to mount */ - struct export_args export; /* network export information */ + struct oexport_args export; /* network export information */ uid_t uid; /* uid that owns hpfs files */ gid_t gid; /* gid that owns hpfs files */ mode_t mode; /* mask to be applied for hpfs perms */ diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index 279ee9990d8..9ad892e9c70 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -240,7 +240,7 @@ deget(pmp, dirclust, diroffset, depp) *depp = NULL; return (error); } - DE_INTERNALIZE(ldep, direntptr); + (void)DE_INTERNALIZE(ldep, direntptr); brelse(bp); } diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c index 999125d4eb8..51b6dc8abbd 100644 --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -594,10 +594,15 @@ msdosfs_deget_dotdot(struct vnode *vp, u_long cluster, int blkoff, vfs_unbusy(mp); if (error == 0) *rvp = DETOV(rdp); - vn_lock(vp, ltype | LK_RETRY); + if (*rvp != vp) + vn_lock(vp, ltype | LK_RETRY); if (vp->v_iflag & VI_DOOMED) { - if (error == 0) - vput(*rvp); + if (error == 0) { + if (*rvp == vp) + vunref(*rvp); + else + vput(*rvp); + } error = ENOENT; } return (error); diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c index a0801bde22a..e04ef9c14e8 100644 --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -200,6 +200,7 @@ static int msdosfs_cmount(struct mntarg *ma, void *data, int flags) { struct msdosfs_args args; + struct export_args exp; int error; if (data == NULL) @@ -207,9 +208,10 @@ msdosfs_cmount(struct mntarg *ma, void *data, int flags) error = copyin(data, &args, sizeof args); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); ma = mount_argf(ma, "uid", "%d", args.uid); ma = mount_argf(ma, "gid", "%d", args.gid); ma = mount_argf(ma, "mask", "%d", args.mask); diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c index 7a194124d79..300b71c0536 100644 --- a/sys/fs/msdosfs/msdosfs_vnops.c +++ b/sys/fs/msdosfs/msdosfs_vnops.c @@ -1258,6 +1258,14 @@ abortit: } } + /* + * The msdosfs lookup is case insensitive. Several aliases may + * be inserted for a single directory entry. As a consequnce, + * name cache purge done by lookup for fvp when DELETE op for + * namei is specified, might be not enough to expunge all + * namecache entries that were installed for this direntry. + */ + cache_purge(fvp); VOP_UNLOCK(fvp, 0); bad: if (xp) diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h index 2951b2c9f0b..417923fa805 100644 --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -234,7 +234,7 @@ uint32_t msdosfs_fileno_map(struct mount *, uint64_t); */ struct msdosfs_args { char *fspec; /* blocks special holding the fs to mount */ - struct export_args export; /* network export information */ + struct oexport_args export; /* network export information */ uid_t uid; /* uid that owns msdosfs files */ gid_t gid; /* gid that owns msdosfs files */ mode_t mask; /* file mask to be applied for msdosfs perms */ diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index dc5b2dcc991..6585fced6d5 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -1823,6 +1823,21 @@ nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex) lp->nfslock_usecnt++; } +/* + * Get a reference as above, but return failure instead of sleeping if + * an exclusive lock is held. + */ +APPLESTATIC int +nfsv4_getref_nonblock(struct nfsv4lock *lp) +{ + + if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) + return (0); + + lp->nfslock_usecnt++; + return (1); +} + /* * Test for a lock. Return 1 if locked, 0 otherwise. */ diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index d6ecda21731..0fdb61dd4d7 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -251,6 +251,7 @@ int nfsv4_lock(struct nfsv4lock *, int, int *, void *); void nfsv4_unlock(struct nfsv4lock *, int); void nfsv4_relref(struct nfsv4lock *); void nfsv4_getref(struct nfsv4lock *, int *, void *); +int nfsv4_getref_nonblock(struct nfsv4lock *); int nfsv4_testlock(struct nfsv4lock *); int nfsrv_mtostr(struct nfsrv_descript *, char *, int); int nfsrv_checkutf8(u_int8_t *, int); @@ -575,6 +576,7 @@ void nfsvno_unlockvfs(mount_t); int nfsvno_lockvfs(mount_t); int nfsrv_v4rootexport(void *, struct ucred *, NFSPROC_T *); int nfsvno_testexp(struct nfsrv_descript *, struct nfsexstuff *); +uint32_t nfsrv_hashfh(fhandle_t *); /* nfs_commonkrpc.c */ int newnfs_nmcancelreqs(struct nfsmount *); diff --git a/sys/fs/nfs/nfsdport.h b/sys/fs/nfs/nfsdport.h index 42dbe082f98..4888866d6e1 100644 --- a/sys/fs/nfs/nfsdport.h +++ b/sys/fs/nfs/nfsdport.h @@ -70,11 +70,10 @@ struct nfsexstuff { #define NFSVNO_CMPFH(f1, f2) \ ((f1)->fh_fsid.val[0] == (f2)->fh_fsid.val[0] && \ (f1)->fh_fsid.val[1] == (f2)->fh_fsid.val[1] && \ - !bcmp((f1)->fh_fid.fid_data, (f2)->fh_fid.fid_data, \ - (f1)->fh_fid.fid_len)) + bcmp(&(f1)->fh_fid, &(f2)->fh_fid, sizeof(struct fid)) == 0) #define NFSLOCKHASH(f) \ - (&nfslockhash[(*((u_int32_t *)((f)->fh_fid.fid_data))) % NFSLOCKHASHSIZE]) + (&nfslockhash[nfsrv_hashfh(f) % NFSLOCKHASHSIZE]) #define NFSFPVNODE(f) ((struct vnode *)((f)->f_data)) #define NFSFPCRED(f) ((f)->f_cred) diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c index a98172f8a3d..98363e85d77 100644 --- a/sys/fs/nfsclient/nfs_clbio.c +++ b/sys/fs/nfsclient/nfs_clbio.c @@ -510,10 +510,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred) rabp = nfs_getcacheblk(vp, rabn, biosize, td); if (!rabp) { error = newnfs_sigintr(nmp, td); - if (error) - return (error); - else - break; + return (error ? error : EINTR); } if ((rabp->b_flags & (B_CACHE|B_DELWRI)) == 0) { rabp->b_flags |= B_ASYNC; diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index e36431fa0ec..8ca1c4337a4 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -53,12 +54,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include + extern struct vop_vector newnfs_vnodeops; extern struct buf_ops buf_ops_newnfs; MALLOC_DECLARE(M_NEWNFSREQ); uma_zone_t newnfsnode_zone; -vop_reclaim_t *ncl_reclaim_p = NULL; void ncl_nhinit(void) @@ -140,6 +142,7 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp) /* * NFS supports recursive and shared locking. */ + lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); VN_LOCK_AREC(vp); VN_LOCK_ASHARE(vp); /* @@ -157,7 +160,6 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp) M_NFSFH, M_WAITOK); bcopy(fhp, np->n_fhp->nfh_fh, fhsize); np->n_fhp->nfh_len = fhsize; - lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); error = insmntque(vp, mntp); if (error != 0) { *npp = NULL; @@ -238,8 +240,8 @@ ncl_reclaim(struct vop_reclaim_args *ap) * If the NLM is running, give it a chance to abort pending * locks. */ - if (ncl_reclaim_p) - ncl_reclaim_p(ap); + if (nfs_reclaim_p != NULL) + nfs_reclaim_p(ap); /* * Destroy the vm object and flush associated pages. diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 4d610b42c38..595c90876cd 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -230,9 +230,9 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp, /* * NFS supports recursive and shared locking. */ + lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); VN_LOCK_AREC(vp); VN_LOCK_ASHARE(vp); - lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); error = insmntque(vp, mntp); if (error != 0) { *npp = NULL; diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 89fd0a28511..2512ad4869b 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -3293,8 +3293,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, ndp->ni_vp = newvp; NFSCNHASH(cnp, HASHINIT); if (cnp->cn_namelen <= NCHNAMLEN) { - np->n_ctime = - np->n_vattr.na_ctime.tv_sec; + np->n_ctime = np->n_vattr.na_ctime; cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp); } if (unlocknewvp) diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index b2cd92b253a..d7245ee2b6f 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -96,10 +96,13 @@ SYSCTL_INT(_vfs_newnfs, NFS_TPRINTF_DELAY, static void nfs_sec_name(char *, int *); static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, - struct nfs_args *argp, struct ucred *, struct thread *); + struct nfs_args *argp, const char *, struct ucred *, + struct thread *); static int mountnfs(struct nfs_args *, struct mount *, struct sockaddr *, char *, u_char *, u_char *, u_char *, struct vnode **, struct ucred *, struct thread *, int); +static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, + struct sockaddr_storage *, int *, off_t *); static vfs_mount_t nfs_mount; static vfs_cmount_t nfs_cmount; static vfs_unmount_t nfs_unmount; @@ -518,10 +521,11 @@ nfs_sec_name(char *sec, int *flagsp) static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, - struct ucred *cred, struct thread *td) + const char *hostname, struct ucred *cred, struct thread *td) { int s; int adjsock; + char *p; s = splnet(); @@ -659,6 +663,14 @@ nfs_decode_args(struct mount *mp, struct nfsmount *nmp, struct nfs_args *argp, nmp->nm_sotype = argp->sotype; nmp->nm_soproto = argp->proto; } + + if (hostname != NULL) { + strlcpy(nmp->nm_hostname, hostname, + sizeof(nmp->nm_hostname)); + p = strchr(nmp->nm_hostname, ':'); + if (p != NULL) + *p = '\0'; + } } static const char *nfs_opts[] = { "from", @@ -933,7 +945,7 @@ nfs_mount(struct mount *mp) NFSMNT_INTEGRITY | NFSMNT_PRIVACY | NFSMNT_NOLOCKD /*|NFSMNT_XLATECOOKIE*/)); - nfs_decode_args(mp, nmp, &args, td->td_ucred, td); + nfs_decode_args(mp, nmp, &args, NULL, td->td_ucred, td); goto out; } @@ -1110,13 +1122,14 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, nmp->nm_sockreq.nr_cred = crhold(cred); mtx_init(&nmp->nm_sockreq.nr_mtx, "nfssock", NULL, MTX_DEF); mp->mnt_data = nmp; + nmp->nm_getinfo = nfs_getnlminfo; } vfs_getnewfsid(mp); nmp->nm_mountp = mp; mtx_init(&nmp->nm_mtx, "NFSmount lock", NULL, MTX_DEF | MTX_DUPOK); nmp->nm_negnametimeo = negnametimeo; - nfs_decode_args(mp, nmp, argp, cred, td); + nfs_decode_args(mp, nmp, argp, hst, cred, td); /* * V2 can only handle 32 bit filesizes. A 4GB-1 limit may be too @@ -1447,3 +1460,26 @@ nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) return (0); } +/* + * Extract the information needed by the nlm from the nfs vnode. + */ +static void +nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, + struct sockaddr_storage *sp, int *is_v3p, off_t *sizep) +{ + struct nfsmount *nmp; + struct nfsnode *np = VTONFS(vp); + + nmp = VFSTONFS(vp->v_mount); + if (fhlenp != NULL) + *fhlenp = (size_t)np->n_fhp->nfh_len; + if (fhp != NULL) + bcopy(np->n_fhp->nfh_fh, fhp, np->n_fhp->nfh_len); + if (sp != NULL) + bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); + if (is_v3p != NULL) + *is_v3p = NFS_ISV3(vp); + if (sizep != NULL) + *sizep = np->n_size; +} + diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 9daf51324f5..b02c4bf6c13 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -84,7 +84,6 @@ __FBSDID("$FreeBSD$"); extern struct nfsstats newnfsstats; MALLOC_DECLARE(M_NEWNFSREQ); -vop_advlock_t *ncl_advlock_p = nfs_dolock; /* * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these @@ -988,7 +987,7 @@ nfs_lookup(struct vop_lookup_args *ap) struct nfsfh *nfhp; struct nfsvattr dnfsva, nfsva; struct vattr vattr; - time_t dmtime; + struct timespec dmtime; *vpp = NULLVP; if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) && @@ -1038,7 +1037,7 @@ nfs_lookup(struct vop_lookup_args *ap) } if (nfscl_nodeleg(newvp, 0) == 0 || (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 && - vattr.va_ctime.tv_sec == newnp->n_ctime)) { + timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==))) { NFSINCRGLOBAL(newnfsstats.lookupcache_hits); if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) @@ -1065,13 +1064,13 @@ nfs_lookup(struct vop_lookup_args *ap) if ((u_int)(ticks - np->n_dmtime_ticks) < (nmp->nm_negnametimeo * hz) && VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && - vattr.va_mtime.tv_sec == np->n_dmtime) { + timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) { NFSINCRGLOBAL(newnfsstats.lookupcache_hits); return (ENOENT); } cache_purge_negative(dvp); mtx_lock(&np->n_mtx); - np->n_dmtime = 0; + timespecclear(&np->n_dmtime); mtx_unlock(&np->n_mtx); } @@ -1086,7 +1085,7 @@ nfs_lookup(struct vop_lookup_args *ap) * the lookup RPC has been performed on the server but before * n_dmtime is set at the end of this function. */ - dmtime = np->n_vattr.na_mtime.tv_sec; + dmtime = np->n_vattr.na_mtime; error = 0; newvp = NULLVP; NFSINCRGLOBAL(newnfsstats.lookupcache_misses); @@ -1139,8 +1138,8 @@ nfs_lookup(struct vop_lookup_args *ap) * lookup. */ mtx_lock(&np->n_mtx); - if (np->n_dmtime <= dmtime) { - if (np->n_dmtime == 0) { + if (timespeccmp(&np->n_dmtime, &dmtime, <=)) { + if (!timespecisset(&np->n_dmtime)) { np->n_dmtime = dmtime; np->n_dmtime_ticks = ticks; } @@ -1241,7 +1240,7 @@ nfs_lookup(struct vop_lookup_args *ap) cnp->cn_flags |= SAVENAME; if ((cnp->cn_flags & MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { - np->n_ctime = np->n_vattr.na_vattr.va_ctime.tv_sec; + np->n_ctime = np->n_vattr.na_vattr.va_ctime; cache_enter(dvp, newvp, cnp); } *vpp = newvp; @@ -2937,10 +2936,12 @@ nfs_advlock(struct vop_advlock_args *ap) VOP_UNLOCK(vp, 0); error = lf_advlock(ap, &(vp->v_lockf), size); } else { - if (ncl_advlock_p) - error = ncl_advlock_p(ap); - else + if (nfs_advlock_p != NULL) + error = nfs_advlock_p(ap); + else { + VOP_UNLOCK(vp, 0); error = ENOLCK; + } } } return (error); diff --git a/sys/fs/nfsclient/nfsmount.h b/sys/fs/nfsclient/nfsmount.h index 9fd93311e68..5bc69f8e82b 100644 --- a/sys/fs/nfsclient/nfsmount.h +++ b/sys/fs/nfsclient/nfsmount.h @@ -35,22 +35,19 @@ #ifndef _NFSCLIENT_NFSMOUNT_H_ #define _NFSCLIENT_NFSMOUNT_H_ +#include + /* * Mount structure. * One allocated on every NFS mount. * Holds NFS specific information for mount. */ struct nfsmount { - struct mtx nm_mtx; - int nm_flag; /* Flags for soft/hard... */ - int nm_state; /* Internal state flags */ - struct mount *nm_mountp; /* Vfs structure for this filesystem */ + struct nfsmount_common nm_com; /* Common fields for nlm */ int nm_numgrps; /* Max. size of groupslist */ u_char nm_fh[NFSX_FHMAX]; /* File handle of root dir */ int nm_fhsize; /* Size of root file handle */ struct nfssockreq nm_sockreq; /* Socket Info */ - int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ - int nm_retry; /* Max retries */ int nm_timeouts; /* Request timeouts */ int nm_rsize; /* Max size of read rpc */ int nm_wsize; /* Max size of write rpc */ @@ -89,6 +86,14 @@ struct nfsmount { #define nm_soproto nm_sockreq.nr_soproto #define nm_client nm_sockreq.nr_client #define nm_krbname nm_name +#define nm_mtx nm_com.nmcom_mtx +#define nm_flag nm_com.nmcom_flag +#define nm_state nm_com.nmcom_state +#define nm_mountp nm_com.nmcom_mountp +#define nm_timeo nm_com.nmcom_timeo +#define nm_retry nm_com.nmcom_retry +#define nm_hostname nm_com.nmcom_hostname +#define nm_getinfo nm_com.nmcom_getinfo #define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1])) #define NFSMNT_SRVKRBNAME(m) \ diff --git a/sys/fs/nfsclient/nfsnode.h b/sys/fs/nfsclient/nfsnode.h index 8bbb3bc9825..204b20cd33a 100644 --- a/sys/fs/nfsclient/nfsnode.h +++ b/sys/fs/nfsclient/nfsnode.h @@ -96,10 +96,9 @@ struct nfsnode { time_t n_attrstamp; /* Attr. cache timestamp */ struct nfs_accesscache n_accesscache[NFS_ACCESSCACHESIZE]; struct timespec n_mtime; /* Prev modify time. */ - time_t n_ctime; /* Prev create time. */ - time_t n_dmtime; /* Prev dir modify time. */ + struct timespec n_ctime; /* Prev create time. */ + struct timespec n_dmtime; /* Prev dir modify time. */ int n_dmtime_ticks; /* Tick of -ve cache entry */ - time_t n_expiry; /* Lease expiry time */ struct nfsfh *n_fhp; /* NFS File Handle */ struct vnode *n_vnode; /* associated vnode */ struct vnode *n_dvp; /* parent vnode */ diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 5bcac95da6d..380aa721036 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); */ #include +#include #include #include #include @@ -1933,7 +1934,15 @@ again: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - r = VOP_LOOKUP(vp, &nvp, &cn); + if ((vp->v_vflag & VV_ROOT) != 0 + && (cn.cn_flags & ISDOTDOT) + != 0) { + vref(vp); + nvp = vp; + r = 0; + } else + r = VOP_LOOKUP(vp, &nvp, + &cn); } } if (!r) { @@ -2825,7 +2834,7 @@ nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first, struct flock fl; u_int64_t tlen; - if (!nfsrv_dolocallocks) + if (nfsrv_dolocallocks == 0) return (0); fl.l_whence = SEEK_SET; fl.l_type = ftype; @@ -2850,8 +2859,12 @@ nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first, fl.l_sysid = (int)nfsv4_sysid; NFSVOPUNLOCK(vp, 0, td); - error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl, - (F_POSIX | F_REMOTE)); + if (ftype == F_UNLCK) + error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl, + (F_POSIX | F_REMOTE)); + else + error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl, + (F_POSIX | F_REMOTE)); NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, td); return (error); } @@ -3075,6 +3088,18 @@ nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp) return (1); } +/* + * Calculate a hash value for the fid in a file handle. + */ +uint32_t +nfsrv_hashfh(fhandle_t *fhp) +{ + uint32_t hashval; + + hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0); + return (hashval); +} + extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *); /* diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index c95fef22a46..af1a3fa7e95 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -533,8 +533,6 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, NFSV4ROOTLOCKMUTEXPTR); NFSUNLOCKV4ROOTMUTEX(); if (igotlock) { - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ /* * If I got the lock, I can update the stable storage file. * Done when the grace period is over or a client has long diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 6c89e6b2d9b..908c02878b4 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -164,8 +164,6 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp, NFSV4ROOTLOCKMUTEXPTR); } while (!igotlock); NFSUNLOCKV4ROOTMUTEX(); - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ /* * Search for a match in the client list. @@ -416,8 +414,6 @@ nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp, NFSV4ROOTLOCKMUTEXPTR); } while (!igotlock); NFSUNLOCKV4ROOTMUTEX(); - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ } else if (opflags != CLOPS_RENEW) { NFSLOCKSTATE(); } @@ -547,8 +543,6 @@ nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p) NFSV4ROOTLOCKMUTEXPTR); } while (!igotlock); NFSUNLOCKV4ROOTMUTEX(); - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ /* * Search for a match in the client list. @@ -824,11 +818,8 @@ nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldumpp, int maxcnt, /* * Server timer routine. It can scan any linked list, so long - * as it holds the spin lock and there is no exclusive lock on + * as it holds the spin/mutex lock and there is no exclusive lock on * nfsv4rootfs_lock. - * Must be called by a kernel thread and not a timer interrupt, - * so that it only runs when the nfsd threads are sleeping on a - * uniprocessor and uses the State spin lock for an SMP system. * (For OpenBSD, a kthread is ok. For FreeBSD, I think it is ok * to do this from a callout, since the spin locks work. For * Darwin, I'm not sure what will work correctly yet.) @@ -839,7 +830,7 @@ nfsrv_servertimer(void) { struct nfsclient *clp, *nclp; struct nfsstate *stp, *nstp; - int i; + int got_ref, i; /* * Make sure nfsboottime is set. This is used by V3 as well @@ -867,13 +858,14 @@ nfsrv_servertimer(void) } /* - * Return now if an nfsd thread has the exclusive lock on - * nfsv4rootfs_lock. The dirty trick here is that we have - * the spin lock already and the nfsd threads do a: - * NFSLOCKSTATE, NFSUNLOCKSTATE after getting the exclusive - * lock, so they won't race with code after this check. + * Try and get a reference count on the nfsv4rootfs_lock so that + * no nfsd thread can acquire an exclusive lock on it before this + * call is done. If it is already exclusively locked, just return. */ - if (nfsv4rootfs_lock.nfslock_lock & NFSV4LOCK_LOCK) { + NFSLOCKV4ROOTMUTEX(); + got_ref = nfsv4_getref_nonblock(&nfsv4rootfs_lock); + NFSUNLOCKV4ROOTMUTEX(); + if (got_ref == 0) { NFSUNLOCKSTATE(); return; } @@ -945,6 +937,9 @@ nfsrv_servertimer(void) } } NFSUNLOCKSTATE(); + NFSLOCKV4ROOTMUTEX(); + nfsv4_relref(&nfsv4rootfs_lock); + NFSUNLOCKV4ROOTMUTEX(); } /* @@ -1090,8 +1085,11 @@ nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) * associated with the open. * If there are locks associated with the open, the * nfslockfile structure can be freed via nfsrv_freelockowner(). - * (That is why the call must be here instead of after the loop.) + * Acquire the state mutex to avoid races with calls to + * nfsrv_getlockfile(). */ + if (cansleep != 0) + NFSLOCKSTATE(); if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) && LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) && @@ -1101,6 +1099,8 @@ nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p) ret = 1; } else ret = 0; + if (cansleep != 0) + NFSUNLOCKSTATE(); FREE((caddr_t)stp, M_NFSDSTATE); newnfsstats.srvopens--; nfsrv_openpluslock--; @@ -1137,6 +1137,7 @@ nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, struct nfslockfile *lfp = NULL; int gottvp = 0; vnode_t tvp = NULL; + uint64_t first, end; lop = LIST_FIRST(&stp->ls_lock); while (lop != LIST_END(&stp->ls_lock)) { @@ -1167,14 +1168,16 @@ nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep, if (tvp != NULL) { if (cansleep == 0) panic("allnfs2"); - nfsrv_localunlock(tvp, lfp, lop->lo_first, - lop->lo_end, p); + first = lop->lo_first; + end = lop->lo_end; + nfsrv_freenfslock(lop); + nfsrv_localunlock(tvp, lfp, first, end, p); LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) free(rlp, M_NFSDROLLBACK); LIST_INIT(&lfp->lf_rollback); - } - nfsrv_freenfslock(lop); + } else + nfsrv_freenfslock(lop); lop = nlop; } if (vp == NULL && tvp != NULL) @@ -4224,8 +4227,6 @@ nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, __unused vnode_t vp, NFSV4ROOTLOCKMUTEXPTR); } while (!gotlock); NFSUNLOCKV4ROOTMUTEX(); - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ *haslockp = 1; NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); return (1); @@ -4390,8 +4391,6 @@ nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p, NFSV4ROOTLOCKMUTEXPTR); } while (!gotlock); NFSUNLOCKV4ROOTMUTEX(); - NFSLOCKSTATE(); /* to avoid a race with */ - NFSUNLOCKSTATE(); /* nfsrv_servertimer() */ *haslockp = 1; NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); return (-1); @@ -4571,6 +4570,14 @@ nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p) nfsrv_issuedelegs == 0) return; + /* + * First, get a reference on the nfsv4rootfs_lock so that an + * exclusive lock cannot be acquired by another thread. + */ + NFSLOCKV4ROOTMUTEX(); + nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR); + NFSUNLOCKV4ROOTMUTEX(); + /* * Now, call nfsrv_checkremove() in a loop while it returns * NFSERR_DELAY. Return upon any other error or when timed out. @@ -4585,11 +4592,14 @@ nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p) NFS_REMOVETIMEO && ((u_int32_t)mytime.tv_sec - starttime) < 100000) - return; + break; /* Sleep for a short period of time */ (void) nfs_catnap(PZERO, 0, "nfsremove"); } } while (error == NFSERR_DELAY); + NFSLOCKV4ROOTMUTEX(); + nfsv4_relref(&nfsv4rootfs_lock); + NFSUNLOCKV4ROOTMUTEX(); } APPLESTATIC void @@ -4947,31 +4957,56 @@ nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags, /* * Local lock unlock. Unlock all byte ranges that are no longer locked - * by NFSv4. + * by NFSv4. To do this, unlock any subranges of first-->end that + * do not overlap with the byte ranges of any lock in the lfp->lf_lock + * list. This list has all locks for the file held by other + * tuples. The list is ordered by increasing + * lo_first value, but may have entries that overlap each other, for + * the case of read locks. */ static void nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first, uint64_t init_end, NFSPROC_T *p) { struct nfslock *lop; - - uint64_t first, end; + uint64_t first, end, prevfirst; first = init_first; end = init_end; while (first < init_end) { /* Loop through all nfs locks, adjusting first and end */ + prevfirst = 0; LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) { + KASSERT(prevfirst <= lop->lo_first, + ("nfsv4 locks out of order")); + KASSERT(lop->lo_first < lop->lo_end, + ("nfsv4 bogus lock")); + prevfirst = lop->lo_first; if (first >= lop->lo_first && first < lop->lo_end) - /* Overlaps initial part */ + /* + * Overlaps with initial part, so trim + * off that initial part by moving first past + * it. + */ first = lop->lo_end; else if (end > lop->lo_first && - lop->lo_first >= first) - /* Begins before end and past first */ + lop->lo_first > first) { + /* + * This lock defines the end of the + * segment to unlock, so set end to the + * start of it and break out of the loop. + */ end = lop->lo_first; + break; + } if (first >= end) - /* shrunk to 0 so this iteration is done */ + /* + * There is no segment left to do, so + * break out of this loop and then exit + * the outer while() since first will be set + * to end, which must equal init_end here. + */ break; } if (first < end) { @@ -4981,7 +5016,10 @@ nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first, nfsrv_locallock_commit(lfp, NFSLCK_UNLOCK, first, end); } - /* and move on to the rest of the range */ + /* + * Now move past this segment and look for any further + * segment in the range, if there is one. + */ first = end; end = init_end; } diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c index ab5eede3f72..b5e024be993 100644 --- a/sys/fs/ntfs/ntfs_vfsops.c +++ b/sys/fs/ntfs/ntfs_vfsops.c @@ -119,14 +119,16 @@ ntfs_cmount ( void *data, int flags) { - int error; struct ntfs_args args; + struct export_args exp; + int error; - error = copyin(data, (caddr_t)&args, sizeof args); + error = copyin(data, &args, sizeof(args)); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); ma = mount_argf(ma, "uid", "%d", args.uid); ma = mount_argf(ma, "gid", "%d", args.gid); ma = mount_argf(ma, "mode", "%d", args.mode); diff --git a/sys/fs/ntfs/ntfsmount.h b/sys/fs/ntfs/ntfsmount.h index 5497ad9f217..f64652c4725 100644 --- a/sys/fs/ntfs/ntfsmount.h +++ b/sys/fs/ntfs/ntfsmount.h @@ -34,7 +34,7 @@ struct ntfs_args { char *fspec; /* block special device to mount */ - struct export_args export; /* network export information */ + struct oexport_args export; /* network export information */ uid_t uid; /* uid that owns ntfs files */ gid_t gid; /* gid that owns ntfs files */ mode_t mode; /* mask to be applied for ntfs perms */ diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index af49e3e18c1..b86ba83cb30 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -498,6 +498,32 @@ null_accessx(struct vop_accessx_args *ap) return (null_bypass((struct vop_generic_args *)ap)); } +/* + * Increasing refcount of lower vnode is needed at least for the case + * when lower FS is NFS to do sillyrename if the file is in use. + * Unfortunately v_usecount is incremented in many places in + * the kernel and, as such, there may be races that result in + * the NFS client doing an extraneous silly rename, but that seems + * preferable to not doing a silly rename when it is needed. + */ +static int +null_remove(struct vop_remove_args *ap) +{ + int retval, vreleit; + struct vnode *lvp; + + if (vrefcnt(ap->a_vp) > 1) { + lvp = NULLVPTOLOWERVP(ap->a_vp); + VREF(lvp); + vreleit = 1; + } else + vreleit = 0; + retval = null_bypass(&ap->a_gen); + if (vreleit != 0) + vrele(lvp); + return (retval); +} + /* * We handle this to eliminate null FS to lower FS * file moving. Don't know why we don't allow this, @@ -809,6 +835,7 @@ struct vop_vector null_vnodeops = { .vop_open = null_open, .vop_print = null_print, .vop_reclaim = null_reclaim, + .vop_remove = null_remove, .vop_rename = null_rename, .vop_setattr = null_setattr, .vop_strategy = VOP_EOPNOTSUPP, diff --git a/sys/fs/nwfs/nwfs_node.c b/sys/fs/nwfs/nwfs_node.c index fc9b41bd890..cf6f6d951b9 100644 --- a/sys/fs/nwfs/nwfs_node.c +++ b/sys/fs/nwfs/nwfs_node.c @@ -185,7 +185,6 @@ rescan: if (dvp) { np->n_parent = VTONW(dvp)->n_fid; } - VN_LOCK_AREC(vp); sx_xlock(&nwhashlock); /* * Another process can create vnode while we blocked in malloc() or @@ -202,6 +201,7 @@ rescan: nhpp = NWNOHASH(fid); LIST_INSERT_HEAD(nhpp, np, n_hash); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + VN_LOCK_AREC(vp); sx_xunlock(&nwhashlock); ASSERT_VOP_LOCKED(dvp, "nwfs_allocvp"); diff --git a/sys/fs/nwfs/nwfs_vfsops.c b/sys/fs/nwfs/nwfs_vfsops.c index 497414ed714..c20159f5cd8 100644 --- a/sys/fs/nwfs/nwfs_vfsops.c +++ b/sys/fs/nwfs/nwfs_vfsops.c @@ -186,8 +186,7 @@ static int nwfs_mount(struct mount *mp) ncp_conn_unlock(conn, td); /* we keep the ref */ mp->mnt_stat.f_iosize = conn->buffer_size; /* We must malloc our own mount info */ - nmp = malloc(sizeof(struct nwmount),M_NWFSDATA, - M_WAITOK | M_USE_RESERVE | M_ZERO); + nmp = malloc(sizeof(struct nwmount), M_NWFSDATA, M_WAITOK | M_ZERO); if (nmp == NULL) { nwfs_printf("could not alloc nwmount\n"); error = ENOMEM; diff --git a/sys/fs/pseudofs/pseudofs_vncache.c b/sys/fs/pseudofs/pseudofs_vncache.c index 035f2c79dd7..19cc70d9a5a 100644 --- a/sys/fs/pseudofs/pseudofs_vncache.c +++ b/sys/fs/pseudofs/pseudofs_vncache.c @@ -189,8 +189,8 @@ retry: if ((pn->pn_flags & PFS_PROCDEP) != 0) (*vpp)->v_vflag |= VV_PROCDEP; pvd->pvd_vnode = *vpp; - VN_LOCK_AREC(*vpp); vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); + VN_LOCK_AREC(*vpp); error = insmntque(*vpp, mp); if (error != 0) { free(pvd, M_PFSVNCACHE); diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c index a0543e28ffa..661579cf220 100644 --- a/sys/fs/smbfs/smbfs_node.c +++ b/sys/fs/smbfs/smbfs_node.c @@ -253,8 +253,8 @@ loop: } else if (vp->v_type == VREG) SMBERROR("new vnode '%s' born without parent ?\n", np->n_name); - VN_LOCK_AREC(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + VN_LOCK_AREC(vp); smbfs_hash_lock(smp); LIST_FOREACH(np2, nhpp, n_hash) { diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c index 16352d7a31f..ac0c5e729c4 100644 --- a/sys/fs/smbfs/smbfs_vfsops.c +++ b/sys/fs/smbfs/smbfs_vfsops.c @@ -175,8 +175,7 @@ smbfs_mount(struct mount *mp) #ifdef SMBFS_USEZONE smp = zalloc(smbfsmount_zone); #else - smp = malloc(sizeof(*smp), M_SMBFSDATA, - M_WAITOK|M_USE_RESERVE); + smp = malloc(sizeof(*smp), M_SMBFSDATA, M_WAITOK); #endif if (smp == NULL) { printf("could not alloc smbmount\n"); diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h index 04b1a06cd24..b1c42496e66 100644 --- a/sys/fs/tmpfs/tmpfs.h +++ b/sys/fs/tmpfs/tmpfs.h @@ -72,7 +72,8 @@ struct tmpfs_dirent { * td_namelen field must always be used when accessing its value. */ char * td_name; - /* Pointer to the node this entry refers to. */ + /* Pointer to the node this entry refers to. In case this field + * is NULL, the node is a whiteout. */ struct tmpfs_node * td_node; }; @@ -434,6 +435,8 @@ int tmpfs_dir_getdotdent(struct tmpfs_node *, struct uio *); int tmpfs_dir_getdotdotdent(struct tmpfs_node *, struct uio *); struct tmpfs_dirent * tmpfs_dir_lookupbycookie(struct tmpfs_node *, off_t); int tmpfs_dir_getdents(struct tmpfs_node *, struct uio *, off_t *); +int tmpfs_dir_whiteout_add(struct vnode *, struct componentname *); +void tmpfs_dir_whiteout_remove(struct vnode *, struct componentname *); int tmpfs_reg_resize(struct vnode *, off_t); int tmpfs_chflags(struct vnode *, int, struct ucred *, struct thread *); int tmpfs_chmod(struct vnode *, mode_t, struct ucred *, struct thread *); diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index b6c5cfe68b2..84a2038112f 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -261,7 +261,8 @@ tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node, memcpy(nde->td_name, name, len); nde->td_node = node; - node->tn_links++; + if (node != NULL) + node->tn_links++; *de = nde; @@ -287,9 +288,10 @@ tmpfs_free_dirent(struct tmpfs_mount *tmp, struct tmpfs_dirent *de, struct tmpfs_node *node; node = de->td_node; - - MPASS(node->tn_links > 0); - node->tn_links--; + if (node != NULL) { + MPASS(node->tn_links > 0); + node->tn_links--; + } } free(de->td_name, M_TMPFSNAME); @@ -518,6 +520,8 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap, /* Now that all required items are allocated, we can proceed to * insert the new node into the directory, an operation that * cannot fail. */ + if (cnp->cn_flags & ISWHITEOUT) + tmpfs_dir_whiteout_remove(dvp, cnp); tmpfs_dir_attach(dvp, de); out: @@ -768,39 +772,44 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) /* Create a dirent structure representing the current * tmpfs_node and fill it. */ - d.d_fileno = de->td_node->tn_id; - switch (de->td_node->tn_type) { - case VBLK: - d.d_type = DT_BLK; - break; + if (de->td_node == NULL) { + d.d_fileno = 1; + d.d_type = DT_WHT; + } else { + d.d_fileno = de->td_node->tn_id; + switch (de->td_node->tn_type) { + case VBLK: + d.d_type = DT_BLK; + break; - case VCHR: - d.d_type = DT_CHR; - break; + case VCHR: + d.d_type = DT_CHR; + break; - case VDIR: - d.d_type = DT_DIR; - break; + case VDIR: + d.d_type = DT_DIR; + break; - case VFIFO: - d.d_type = DT_FIFO; - break; + case VFIFO: + d.d_type = DT_FIFO; + break; - case VLNK: - d.d_type = DT_LNK; - break; + case VLNK: + d.d_type = DT_LNK; + break; - case VREG: - d.d_type = DT_REG; - break; + case VREG: + d.d_type = DT_REG; + break; - case VSOCK: - d.d_type = DT_SOCK; - break; + case VSOCK: + d.d_type = DT_SOCK; + break; - default: - panic("tmpfs_dir_getdents: type %p %d", - de->td_node, (int)de->td_node->tn_type); + default: + panic("tmpfs_dir_getdents: type %p %d", + de->td_node, (int)de->td_node->tn_type); + } } d.d_namlen = de->td_namelen; MPASS(de->td_namelen < sizeof(d.d_name)); @@ -837,6 +846,31 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, off_t *cntp) return error; } +int +tmpfs_dir_whiteout_add(struct vnode *dvp, struct componentname *cnp) +{ + struct tmpfs_dirent *de; + int error; + + error = tmpfs_alloc_dirent(VFS_TO_TMPFS(dvp->v_mount), NULL, + cnp->cn_nameptr, cnp->cn_namelen, &de); + if (error != 0) + return (error); + tmpfs_dir_attach(dvp, de); + return (0); +} + +void +tmpfs_dir_whiteout_remove(struct vnode *dvp, struct componentname *cnp) +{ + struct tmpfs_dirent *de; + + de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); + MPASS(de != NULL && de->td_node == NULL); + tmpfs_dir_detach(dvp, de); + tmpfs_free_dirent(VFS_TO_TMPFS(dvp->v_mount), de, TRUE); +} + /* --------------------------------------------------------------------- */ /* diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c index 88e09399648..059a7909104 100644 --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -109,14 +109,19 @@ tmpfs_lookup(struct vop_cachedlookup_args *v) error = 0; } else { de = tmpfs_dir_lookup(dnode, NULL, cnp); - if (de == NULL) { + if (de != NULL && de->td_node == NULL) + cnp->cn_flags |= ISWHITEOUT; + if (de == NULL || de->td_node == NULL) { /* The entry was not found in the directory. * This is OK if we are creating or renaming an * entry and are working on the last component of * the path name. */ if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == CREATE || \ - cnp->cn_nameiop == RENAME)) { + cnp->cn_nameiop == RENAME || + (cnp->cn_nameiop == DELETE && + cnp->cn_flags & DOWHITEOUT && + cnp->cn_flags & ISWHITEOUT))) { error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_thread); if (error != 0) @@ -533,6 +538,8 @@ lookupvpg: VM_OBJECT_UNLOCK(vobj); return (error); } else if (m != NULL && uio->uio_segflg == UIO_NOCOPY) { + KASSERT(offset == 0, + ("unexpected offset in tmpfs_mappedread for sendfile")); if ((m->oflags & VPO_BUSY) != 0) { /* * Reference the page before unlocking and sleeping so @@ -548,15 +555,18 @@ lookupvpg: sched_pin(); sf = sf_buf_alloc(m, SFB_CPUPRIVATE); ma = (char *)sf_buf_kva(sf); - error = tmpfs_nocacheread_buf(tobj, idx, offset, tlen, - ma + offset); + error = tmpfs_nocacheread_buf(tobj, idx, 0, tlen, ma); if (error == 0) { + if (tlen != PAGE_SIZE) + bzero(ma + tlen, PAGE_SIZE - tlen); uio->uio_offset += tlen; uio->uio_resid -= tlen; } sf_buf_free(sf); sched_unpin(); VM_OBJECT_LOCK(vobj); + if (error == 0) + m->valid = VM_PAGE_BITS_ALL; vm_page_wakeup(m); VM_OBJECT_UNLOCK(vobj); return (error); @@ -834,6 +844,8 @@ tmpfs_remove(struct vop_remove_args *v) /* Remove the entry from the directory; as it is a file, we do not * have to change the number of hard links of the directory. */ tmpfs_dir_detach(dvp, de); + if (v->a_cnp->cn_flags & DOWHITEOUT) + tmpfs_dir_whiteout_add(dvp, v->a_cnp); /* Free the directory entry we just deleted. Note that the node * referred by it will not be removed until the vnode is really @@ -904,6 +916,8 @@ tmpfs_link(struct vop_link_args *v) goto out; /* Insert the new directory entry into the appropriate directory. */ + if (cnp->cn_flags & ISWHITEOUT) + tmpfs_dir_whiteout_remove(dvp, cnp); tmpfs_dir_attach(dvp, de); /* vp link count has changed, so update node times. */ @@ -972,10 +986,14 @@ tmpfs_rename(struct vop_rename_args *v) fnode = VP_TO_TMPFS_NODE(fvp); de = tmpfs_dir_lookup(fdnode, fnode, fcnp); - /* Avoid manipulating '.' and '..' entries. */ + /* Entry can disappear before we lock fdvp, + * also avoid manipulating '.' and '..' entries. */ if (de == NULL) { - MPASS(fvp->v_type == VDIR); - error = EINVAL; + if ((fcnp->cn_flags & ISDOTDOT) != 0 || + (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')) + error = EINVAL; + else + error = ENOENT; goto out_locked; } MPASS(de->td_node == fnode); @@ -1099,6 +1117,10 @@ tmpfs_rename(struct vop_rename_args *v) /* Do the move: just remove the entry from the source directory * and insert it into the target one. */ tmpfs_dir_detach(fdvp, de); + if (fcnp->cn_flags & DOWHITEOUT) + tmpfs_dir_whiteout_add(fdvp, fcnp); + if (tcnp->cn_flags & ISWHITEOUT) + tmpfs_dir_whiteout_remove(tdvp, tcnp); tmpfs_dir_attach(tdvp, de); } @@ -1223,6 +1245,8 @@ tmpfs_rmdir(struct vop_rmdir_args *v) /* Detach the directory entry from the directory (dnode). */ tmpfs_dir_detach(dvp, de); + if (v->a_cnp->cn_flags & DOWHITEOUT) + tmpfs_dir_whiteout_add(dvp, v->a_cnp); /* No vnode should be allocated for this entry from this point */ TMPFS_NODE_LOCK(node); @@ -1541,6 +1565,29 @@ tmpfs_vptofh(struct vop_vptofh_args *ap) return (0); } +static int +tmpfs_whiteout(struct vop_whiteout_args *ap) +{ + struct vnode *dvp = ap->a_dvp; + struct componentname *cnp = ap->a_cnp; + struct tmpfs_dirent *de; + + switch (ap->a_flags) { + case LOOKUP: + return (0); + case CREATE: + de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), NULL, cnp); + if (de != NULL) + return (de->td_node == NULL ? 0 : EEXIST); + return (tmpfs_dir_whiteout_add(dvp, cnp)); + case DELETE: + tmpfs_dir_whiteout_remove(dvp, cnp); + return (0); + default: + panic("tmpfs_whiteout: unknown op"); + } +} + /* --------------------------------------------------------------------- */ /* @@ -1573,6 +1620,7 @@ struct vop_vector tmpfs_vnodeop_entries = { .vop_print = tmpfs_print, .vop_pathconf = tmpfs_pathconf, .vop_vptofh = tmpfs_vptofh, + .vop_whiteout = tmpfs_whiteout, .vop_bmap = VOP_EOPNOTSUPP, }; diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index dbed54e6298..2e74844d4d4 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -775,6 +775,11 @@ unionfs_mkshadowdir(struct unionfs_mount *ump, struct vnode *udvp, /* Authority change to root */ rootinfo = uifind((uid_t)0); cred = crdup(cnp->cn_cred); + /* + * The calls to chgproccnt() are needed to compensate for change_ruid() + * calling chgproccnt(). + */ + chgproccnt(cred->cr_ruidinfo, 1, 0); change_euid(cred, rootinfo); change_ruid(cred, rootinfo); change_svuid(cred, (uid_t)0); @@ -824,6 +829,7 @@ unionfs_mkshadowdir_free_out: unionfs_mkshadowdir_abort: cnp->cn_cred = credbk; + chgproccnt(cred->cr_ruidinfo, -1, 0); crfree(cred); return (error); diff --git a/sys/fs/unionfs/union_vfsops.c b/sys/fs/unionfs/union_vfsops.c index 604d4a3943f..e11219c1d02 100644 --- a/sys/fs/unionfs/union_vfsops.c +++ b/sys/fs/unionfs/union_vfsops.c @@ -89,7 +89,6 @@ unionfs_domount(struct mount *mp) u_short ufile; unionfs_copymode copymode; unionfs_whitemode whitemode; - struct componentname fakecn; struct nameidata nd, *ndp; struct vattr va; @@ -279,26 +278,6 @@ unionfs_domount(struct mount *mp) */ mp->mnt_flag |= ump->um_uppervp->v_mount->mnt_flag & MNT_RDONLY; - /* - * Check whiteout - */ - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - memset(&fakecn, 0, sizeof(fakecn)); - fakecn.cn_nameiop = LOOKUP; - fakecn.cn_thread = td; - error = VOP_WHITEOUT(ump->um_uppervp, &fakecn, LOOKUP); - if (error) { - if (below) { - VOP_UNLOCK(ump->um_uppervp, 0); - vrele(upperrootvp); - } else - vput(ump->um_uppervp); - free(ump, M_UNIONFSMNT); - mp->mnt_data = NULL; - return (error); - } - } - /* * Unlock the node */ diff --git a/sys/gdb/gdb_cons.c b/sys/gdb/gdb_cons.c index 1c7bdeadfa6..2e01cd4eddb 100644 --- a/sys/gdb/gdb_cons.c +++ b/sys/gdb/gdb_cons.c @@ -126,7 +126,7 @@ oktousecallout(void *data __unused) { calloutok = 1; } -SYSINIT(gdbhack, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY, oktousecallout, NULL); +SYSINIT(gdbhack, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, oktousecallout, NULL); static void gdb_cnputc(struct consdev *cp, int c) diff --git a/sys/geom/concat/g_concat.c b/sys/geom/concat/g_concat.c index 1f523755c7d..545cb8f4ce7 100644 --- a/sys/geom/concat/g_concat.c +++ b/sys/geom/concat/g_concat.c @@ -211,6 +211,39 @@ g_concat_access(struct g_provider *pp, int dr, int dw, int de) return (error); } +static void +g_concat_kernel_dump(struct bio *bp) +{ + struct g_concat_softc *sc; + struct g_concat_disk *disk; + struct bio *cbp; + struct g_kerneldump *gkd; + u_int i; + + sc = bp->bio_to->geom->softc; + gkd = (struct g_kerneldump *)bp->bio_data; + for (i = 0; i < sc->sc_ndisks; i++) { + if (sc->sc_disks[i].d_start <= gkd->offset && + sc->sc_disks[i].d_end > gkd->offset) + break; + } + if (i == sc->sc_ndisks) + g_io_deliver(bp, EOPNOTSUPP); + disk = &sc->sc_disks[i]; + gkd->offset -= disk->d_start; + if (gkd->length > disk->d_end - disk->d_start - gkd->offset) + gkd->length = disk->d_end - disk->d_start - gkd->offset; + cbp = g_clone_bio(bp); + if (cbp == NULL) { + g_io_deliver(bp, ENOMEM); + return; + } + cbp->bio_done = g_std_done; + g_io_request(cbp, disk->d_consumer); + G_CONCAT_DEBUG(1, "Kernel dump will go to %s.", + disk->d_consumer->provider->name); +} + static void g_concat_flush(struct g_concat_softc *sc, struct bio *bp) { @@ -280,7 +313,12 @@ g_concat_start(struct bio *bp) g_concat_flush(sc, bp); return; case BIO_GETATTR: + if (strcmp("GEOM::kerneldump", bp->bio_attribute) == 0) { + g_concat_kernel_dump(bp); + return; + } /* To which provider it should be delivered? */ + /* FALLTHROUGH */ default: g_io_deliver(bp, EOPNOTSUPP); return; diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c index a3746c09e1a..deffeb717a8 100644 --- a/sys/geom/eli/g_eli.c +++ b/sys/geom/eli/g_eli.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,9 +56,9 @@ MALLOC_DEFINE(M_ELI, "eli data", "GEOM_ELI Data"); SYSCTL_DECL(_kern_geom); SYSCTL_NODE(_kern_geom, OID_AUTO, eli, CTLFLAG_RW, 0, "GEOM_ELI stuff"); -u_int g_eli_debug = 0; +int g_eli_debug = 0; TUNABLE_INT("kern.geom.eli.debug", &g_eli_debug); -SYSCTL_UINT(_kern_geom_eli, OID_AUTO, debug, CTLFLAG_RW, &g_eli_debug, 0, +SYSCTL_INT(_kern_geom_eli, OID_AUTO, debug, CTLFLAG_RW, &g_eli_debug, 0, "Debug level"); static u_int g_eli_tries = 3; TUNABLE_INT("kern.geom.eli.tries", &g_eli_tries); @@ -69,7 +69,7 @@ TUNABLE_INT("kern.geom.eli.visible_passphrase", &g_eli_visible_passphrase); SYSCTL_UINT(_kern_geom_eli, OID_AUTO, visible_passphrase, CTLFLAG_RW, &g_eli_visible_passphrase, 0, "Turn on echo when entering the passphrase (for debug purposes only!!)"); -u_int g_eli_overwrites = 5; +u_int g_eli_overwrites = G_ELI_OVERWRITES; TUNABLE_INT("kern.geom.eli.overwrites", &g_eli_overwrites); SYSCTL_UINT(_kern_geom_eli, OID_AUTO, overwrites, CTLFLAG_RW, &g_eli_overwrites, 0, "Number of times on-disk keys should be overwritten when destroying them"); @@ -106,7 +106,7 @@ struct g_class g_eli_class = { /* * Code paths: * BIO_READ: - * g_eli_start -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver + * g_eli_start -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver * BIO_WRITE: * g_eli_start -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver */ @@ -148,7 +148,7 @@ g_eli_crypto_rerun(struct cryptop *crp) /* * The function is called afer reading encrypted data from the provider. * - * g_eli_start -> g_io_request -> G_ELI_READ_DONE -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver + * g_eli_start -> g_eli_crypto_read -> g_io_request -> G_ELI_READ_DONE -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver */ void g_eli_read_done(struct bio *bp) @@ -167,6 +167,7 @@ g_eli_read_done(struct bio *bp) if (pbp->bio_inbed < pbp->bio_children) return; g_destroy_bio(bp); + sc = pbp->bio_to->geom->softc; if (pbp->bio_error != 0) { G_ELI_LOGREQ(0, pbp, "%s() failed", __func__); pbp->bio_completed = 0; @@ -175,9 +176,9 @@ g_eli_read_done(struct bio *bp) pbp->bio_driver2 = NULL; } g_io_deliver(pbp, pbp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); return; } - sc = pbp->bio_to->geom->softc; mtx_lock(&sc->sc_queue_mtx); bioq_insert_tail(&sc->sc_queue, pbp); mtx_unlock(&sc->sc_queue_mtx); @@ -192,6 +193,7 @@ g_eli_read_done(struct bio *bp) void g_eli_write_done(struct bio *bp) { + struct g_eli_softc *sc; struct bio *pbp; G_ELI_LOGREQ(2, bp, "Request done."); @@ -218,7 +220,9 @@ g_eli_write_done(struct bio *bp) * Write is finished, send it up. */ pbp->bio_completed = pbp->bio_length; + sc = pbp->bio_to->geom->softc; g_io_deliver(pbp, pbp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); } /* @@ -241,12 +245,14 @@ g_eli_orphan(struct g_consumer *cp) sc = cp->geom->softc; if (sc == NULL) return; - g_eli_destroy(sc, 1); + g_eli_destroy(sc, TRUE); } /* - * BIO_READ : G_ELI_START -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver - * BIO_WRITE: G_ELI_START -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver + * BIO_READ: + * G_ELI_START -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver + * BIO_WRITE: + * G_ELI_START -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver */ static void g_eli_start(struct bio *bp) @@ -282,24 +288,16 @@ g_eli_start(struct bio *bp) g_io_deliver(bp, ENOMEM); return; } + bp->bio_driver1 = cbp; + bp->bio_pflags = G_ELI_NEW_BIO; switch (bp->bio_cmd) { case BIO_READ: if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) { - bp->bio_driver2 = NULL; - cbp->bio_done = g_eli_read_done; - cp = LIST_FIRST(&sc->sc_geom->consumer); - cbp->bio_to = cp->provider; - G_ELI_LOGREQ(2, cbp, "Sending request."); - /* - * Read encrypted data from provider. - */ - g_io_request(cbp, cp); + g_eli_crypto_read(sc, bp, 0); break; } - bp->bio_pflags = 255; /* FALLTHROUGH */ case BIO_WRITE: - bp->bio_driver1 = cbp; mtx_lock(&sc->sc_queue_mtx); bioq_insert_tail(&sc->sc_queue, bp); mtx_unlock(&sc->sc_queue_mtx); @@ -316,6 +314,104 @@ g_eli_start(struct bio *bp) } } +static int +g_eli_newsession(struct g_eli_worker *wr) +{ + struct g_eli_softc *sc; + struct cryptoini crie, cria; + int error; + + sc = wr->w_softc; + + bzero(&crie, sizeof(crie)); + crie.cri_alg = sc->sc_ealgo; + crie.cri_klen = sc->sc_ekeylen; + if (sc->sc_ealgo == CRYPTO_AES_XTS) + crie.cri_klen <<= 1; + crie.cri_key = sc->sc_ekeys[0]; + if (sc->sc_flags & G_ELI_FLAG_AUTH) { + bzero(&cria, sizeof(cria)); + cria.cri_alg = sc->sc_aalgo; + cria.cri_klen = sc->sc_akeylen; + cria.cri_key = sc->sc_akey; + crie.cri_next = &cria; + } + + switch (sc->sc_crypto) { + case G_ELI_CRYPTO_SW: + error = crypto_newsession(&wr->w_sid, &crie, + CRYPTOCAP_F_SOFTWARE); + break; + case G_ELI_CRYPTO_HW: + error = crypto_newsession(&wr->w_sid, &crie, + CRYPTOCAP_F_HARDWARE); + break; + case G_ELI_CRYPTO_UNKNOWN: + error = crypto_newsession(&wr->w_sid, &crie, + CRYPTOCAP_F_HARDWARE); + if (error == 0) { + mtx_lock(&sc->sc_queue_mtx); + if (sc->sc_crypto == G_ELI_CRYPTO_UNKNOWN) + sc->sc_crypto = G_ELI_CRYPTO_HW; + mtx_unlock(&sc->sc_queue_mtx); + } else { + error = crypto_newsession(&wr->w_sid, &crie, + CRYPTOCAP_F_SOFTWARE); + mtx_lock(&sc->sc_queue_mtx); + if (sc->sc_crypto == G_ELI_CRYPTO_UNKNOWN) + sc->sc_crypto = G_ELI_CRYPTO_SW; + mtx_unlock(&sc->sc_queue_mtx); + } + break; + default: + panic("%s: invalid condition", __func__); + } + + return (error); +} + +static void +g_eli_freesession(struct g_eli_worker *wr) +{ + + crypto_freesession(wr->w_sid); +} + +static void +g_eli_cancel(struct g_eli_softc *sc) +{ + struct bio *bp; + + mtx_assert(&sc->sc_queue_mtx, MA_OWNED); + + while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL) { + KASSERT(bp->bio_pflags == G_ELI_NEW_BIO, + ("Not new bio when canceling (bp=%p).", bp)); + g_io_deliver(bp, ENXIO); + } +} + +static struct bio * +g_eli_takefirst(struct g_eli_softc *sc) +{ + struct bio *bp; + + mtx_assert(&sc->sc_queue_mtx, MA_OWNED); + + if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND)) + return (bioq_takefirst(&sc->sc_queue)); + /* + * Device suspended, so we skip new I/O requests. + */ + TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { + if (bp->bio_pflags != G_ELI_NEW_BIO) + break; + } + if (bp != NULL) + bioq_remove(&sc->sc_queue, bp); + return (bp); +} + /* * This is the main function for kernel worker thread when we don't have * hardware acceleration and we have to do cryptography in software. @@ -328,6 +424,7 @@ g_eli_worker(void *arg) struct g_eli_softc *sc; struct g_eli_worker *wr; struct bio *bp; + int error; wr = arg; sc = wr->w_softc; @@ -349,11 +446,13 @@ g_eli_worker(void *arg) for (;;) { mtx_lock(&sc->sc_queue_mtx); - bp = bioq_takefirst(&sc->sc_queue); +again: + bp = g_eli_takefirst(sc); if (bp == NULL) { if (sc->sc_flags & G_ELI_FLAG_DESTROY) { + g_eli_cancel(sc); LIST_REMOVE(wr, w_next); - crypto_freesession(wr->w_sid); + g_eli_freesession(wr); free(wr, M_ELI); G_ELI_DEBUG(1, "Thread %s exiting.", curthread->td_proc->p_comm); @@ -361,19 +460,94 @@ g_eli_worker(void *arg) mtx_unlock(&sc->sc_queue_mtx); kproc_exit(0); } + while (sc->sc_flags & G_ELI_FLAG_SUSPEND) { + if (sc->sc_inflight > 0) { + G_ELI_DEBUG(0, "inflight=%d", sc->sc_inflight); + /* + * We still have inflight BIOs, so + * sleep and retry. + */ + msleep(sc, &sc->sc_queue_mtx, PRIBIO, + "geli:inf", hz / 5); + goto again; + } + /* + * Suspend requested, mark the worker as + * suspended and go to sleep. + */ + if (wr->w_active) { + g_eli_freesession(wr); + wr->w_active = FALSE; + } + wakeup(&sc->sc_workers); + msleep(sc, &sc->sc_queue_mtx, PRIBIO, + "geli:suspend", 0); + if (!wr->w_active && + !(sc->sc_flags & G_ELI_FLAG_SUSPEND)) { + error = g_eli_newsession(wr); + KASSERT(error == 0, + ("g_eli_newsession() failed on resume (error=%d)", + error)); + wr->w_active = TRUE; + } + goto again; + } msleep(sc, &sc->sc_queue_mtx, PDROP, "geli:w", 0); continue; } + if (bp->bio_pflags == G_ELI_NEW_BIO) + atomic_add_int(&sc->sc_inflight, 1); mtx_unlock(&sc->sc_queue_mtx); - if (bp->bio_cmd == BIO_READ && bp->bio_pflags == 255) - g_eli_auth_read(sc, bp); - else if (sc->sc_flags & G_ELI_FLAG_AUTH) - g_eli_auth_run(wr, bp); - else - g_eli_crypto_run(wr, bp); + if (bp->bio_pflags == G_ELI_NEW_BIO) { + bp->bio_pflags = 0; + if (sc->sc_flags & G_ELI_FLAG_AUTH) { + if (bp->bio_cmd == BIO_READ) + g_eli_auth_read(sc, bp); + else + g_eli_auth_run(wr, bp); + } else { + if (bp->bio_cmd == BIO_READ) + g_eli_crypto_read(sc, bp, 1); + else + g_eli_crypto_run(wr, bp); + } + } else { + if (sc->sc_flags & G_ELI_FLAG_AUTH) + g_eli_auth_run(wr, bp); + else + g_eli_crypto_run(wr, bp); + } } } +/* + * Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one + * key available for all the data. If the flag is not present select the key + * based on data offset. + */ +uint8_t * +g_eli_crypto_key(struct g_eli_softc *sc, off_t offset, size_t blocksize) +{ + u_int nkey; + + if (sc->sc_nekeys == 1) + return (sc->sc_ekeys[0]); + + KASSERT(sc->sc_nekeys > 1, ("%s: sc_nekeys=%u", __func__, + sc->sc_nekeys)); + KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0, + ("%s: SINGLE_KEY flag set, but sc_nekeys=%u", __func__, + sc->sc_nekeys)); + + /* We switch key every 2^G_ELI_KEY_SHIFT blocks. */ + nkey = (offset >> G_ELI_KEY_SHIFT) / blocksize; + + KASSERT(nkey < sc->sc_nekeys, ("%s: nkey=%u >= sc_nekeys=%u", __func__, + nkey, sc->sc_nekeys)); + + return (sc->sc_ekeys[nkey]); +} + /* * Here we generate IV. It is unique for every sector. */ @@ -381,16 +555,31 @@ void g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv, size_t size) { - u_char off[8], hash[SHA256_DIGEST_LENGTH]; - SHA256_CTX ctx; + uint8_t off[8]; - if (!(sc->sc_flags & G_ELI_FLAG_NATIVE_BYTE_ORDER)) + if ((sc->sc_flags & G_ELI_FLAG_NATIVE_BYTE_ORDER) != 0) + bcopy(&offset, off, sizeof(off)); + else le64enc(off, (uint64_t)offset); - /* Copy precalculated SHA256 context for IV-Key. */ - bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx)); - SHA256_Update(&ctx, (uint8_t *)&offset, sizeof(offset)); - SHA256_Final(hash, &ctx); - bcopy(hash, iv, size); + + switch (sc->sc_ealgo) { + case CRYPTO_AES_XTS: + bcopy(off, iv, sizeof(off)); + bzero(iv + sizeof(off), size - sizeof(off)); + break; + default: + { + u_char hash[SHA256_DIGEST_LENGTH]; + SHA256_CTX ctx; + + /* Copy precalculated SHA256 context for IV-Key. */ + bcopy(&sc->sc_ivctx, &ctx, sizeof(ctx)); + SHA256_Update(&ctx, off, sizeof(off)); + SHA256_Final(hash, &ctx); + bcopy(hash, iv, MIN(sizeof(hash), size)); + break; + } + } } int @@ -457,7 +646,7 @@ g_eli_last_close(struct g_eli_softc *sc) gp = sc->sc_geom; pp = LIST_FIRST(&gp->provider); strlcpy(ppname, pp->name, sizeof(ppname)); - error = g_eli_destroy(sc, 1); + error = g_eli_destroy(sc, TRUE); KASSERT(error == 0, ("Cannot detach %s on last close (error=%d).", ppname, error)); G_ELI_DEBUG(0, "Detached %s on last close.", ppname); @@ -514,7 +703,6 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, struct g_geom *gp; struct g_provider *pp; struct g_consumer *cp; - struct cryptoini crie, cria; u_int i, threads; int error; @@ -541,18 +729,16 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, else gp->access = g_std_access; - sc->sc_crypto = G_ELI_CRYPTO_SW; + sc->sc_inflight = 0; + sc->sc_crypto = G_ELI_CRYPTO_UNKNOWN; sc->sc_flags = md->md_flags; /* Backward compatibility. */ - if (md->md_version < 2) + if (md->md_version < 4) sc->sc_flags |= G_ELI_FLAG_NATIVE_BYTE_ORDER; + if (md->md_version < 5) + sc->sc_flags |= G_ELI_FLAG_SINGLE_KEY; sc->sc_ealgo = md->md_ealgo; sc->sc_nkey = nkey; - /* - * Remember the keys in our softc structure. - */ - g_eli_mkey_propagate(sc, mkey); - sc->sc_ekeylen = md->md_keylen; if (sc->sc_flags & G_ELI_FLAG_AUTH) { sc->sc_akeylen = sizeof(sc->sc_akey) * 8; @@ -572,24 +758,8 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, sc->sc_bytes_per_sector = (md->md_sectorsize - 1) / sc->sc_data_per_sector + 1; sc->sc_bytes_per_sector *= bpp->sectorsize; - /* - * Precalculate SHA256 for HMAC key generation. - * This is expensive operation and we can do it only once now or - * for every access to sector, so now will be much better. - */ - SHA256_Init(&sc->sc_akeyctx); - SHA256_Update(&sc->sc_akeyctx, sc->sc_akey, - sizeof(sc->sc_akey)); } - /* - * Precalculate SHA256 for IV generation. - * This is expensive operation and we can do it only once now or for - * every access to sector, so now will be much better. - */ - SHA256_Init(&sc->sc_ivctx); - SHA256_Update(&sc->sc_ivctx, sc->sc_ivkey, sizeof(sc->sc_ivkey)); - gp->softc = sc; sc->sc_geom = gp; @@ -631,20 +801,25 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, goto failed; } - LIST_INIT(&sc->sc_workers); - - bzero(&crie, sizeof(crie)); - crie.cri_alg = sc->sc_ealgo; - crie.cri_klen = sc->sc_ekeylen; - crie.cri_key = sc->sc_ekey; - if (sc->sc_flags & G_ELI_FLAG_AUTH) { - bzero(&cria, sizeof(cria)); - cria.cri_alg = sc->sc_aalgo; - cria.cri_klen = sc->sc_akeylen; - cria.cri_key = sc->sc_akey; - crie.cri_next = &cria; + sc->sc_sectorsize = md->md_sectorsize; + sc->sc_mediasize = bpp->mediasize; + if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) + sc->sc_mediasize -= bpp->sectorsize; + if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) + sc->sc_mediasize -= (sc->sc_mediasize % sc->sc_sectorsize); + else { + sc->sc_mediasize /= sc->sc_bytes_per_sector; + sc->sc_mediasize *= sc->sc_sectorsize; } + /* + * Remember the keys in our softc structure. + */ + g_eli_mkey_propagate(sc, mkey); + sc->sc_ekeylen = md->md_keylen; + + LIST_INIT(&sc->sc_workers); + threads = g_eli_threads; if (threads == 0) threads = mp_ncpus; @@ -662,21 +837,9 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, wr = malloc(sizeof(*wr), M_ELI, M_WAITOK | M_ZERO); wr->w_softc = sc; wr->w_number = i; + wr->w_active = TRUE; - /* - * If this is the first pass, try to get hardware support. - * Use software cryptography, if we cannot get it. - */ - if (LIST_EMPTY(&sc->sc_workers)) { - error = crypto_newsession(&wr->w_sid, &crie, - CRYPTOCAP_F_HARDWARE); - if (error == 0) - sc->sc_crypto = G_ELI_CRYPTO_HW; - } - if (sc->sc_crypto == G_ELI_CRYPTO_SW) { - error = crypto_newsession(&wr->w_sid, &crie, - CRYPTOCAP_F_SOFTWARE); - } + error = g_eli_newsession(wr); if (error != 0) { free(wr, M_ELI); if (req != NULL) { @@ -692,7 +855,7 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, error = kproc_create(g_eli_worker, wr, &wr->w_proc, 0, 0, "g_eli[%u] %s", i, bpp->name); if (error != 0) { - crypto_freesession(wr->w_sid); + g_eli_freesession(wr); free(wr, M_ELI); if (req != NULL) { gctl_error(req, "Cannot create kernel thread " @@ -713,16 +876,8 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp, * Create decrypted provider. */ pp = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX); - pp->sectorsize = md->md_sectorsize; - pp->mediasize = bpp->mediasize; - if (!(sc->sc_flags & G_ELI_FLAG_ONETIME)) - pp->mediasize -= bpp->sectorsize; - if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) - pp->mediasize -= (pp->mediasize % pp->sectorsize); - else { - pp->mediasize /= sc->sc_bytes_per_sector; - pp->mediasize *= pp->sectorsize; - } + pp->mediasize = sc->sc_mediasize; + pp->sectorsize = sc->sc_sectorsize; g_error_provider(pp, 0); @@ -753,6 +908,11 @@ failed: } g_destroy_consumer(cp); g_destroy_geom(gp); + if (sc->sc_ekeys != NULL) { + bzero(sc->sc_ekeys, + sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN)); + free(sc->sc_ekeys, M_ELI); + } bzero(sc, sizeof(*sc)); free(sc, M_ELI); return (NULL); @@ -792,6 +952,12 @@ g_eli_destroy(struct g_eli_softc *sc, boolean_t force) } mtx_destroy(&sc->sc_queue_mtx); gp->softc = NULL; + if (sc->sc_ekeys != NULL) { + /* The sc_ekeys field can be NULL is device is suspended. */ + bzero(sc->sc_ekeys, + sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN)); + free(sc->sc_ekeys, M_ELI); + } bzero(sc, sizeof(*sc)); free(sc, M_ELI); @@ -809,7 +975,7 @@ g_eli_destroy_geom(struct gctl_req *req __unused, struct g_eli_softc *sc; sc = gp->softc; - return (g_eli_destroy(sc, 0)); + return (g_eli_destroy(sc, FALSE)); } static int @@ -1040,6 +1206,8 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, sbuf_printf(sb, name); \ } \ } while (0) + ADD_FLAG(G_ELI_FLAG_SUSPEND, "SUSPEND"); + ADD_FLAG(G_ELI_FLAG_SINGLE_KEY, "SINGLE-KEY"); ADD_FLAG(G_ELI_FLAG_NATIVE_BYTE_ORDER, "NATIVE-BYTE-ORDER"); ADD_FLAG(G_ELI_FLAG_ONETIME, "ONETIME"); ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT"); @@ -1079,6 +1247,8 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, sc->sc_ekeylen); sbuf_printf(sb, "%s%s\n", indent, g_eli_algo2str(sc->sc_ealgo)); + sbuf_printf(sb, "%s%s\n", indent, + (sc->sc_flags & G_ELI_FLAG_SUSPEND) ? "SUSPENDED" : "ACTIVE"); } static void @@ -1100,7 +1270,7 @@ g_eli_shutdown_pre_sync(void *arg, int howto) pp = LIST_FIRST(&gp->provider); KASSERT(pp != NULL, ("No provider? gp=%p (%s)", gp, gp->name)); if (pp->acr + pp->acw + pp->ace == 0) - error = g_eli_destroy(sc, 1); + error = g_eli_destroy(sc, TRUE); else { sc->sc_flags |= G_ELI_FLAG_RW_DETACH; gp->access = g_eli_access; diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h index 8079c9dd4a1..d67e43653c4 100644 --- a/sys/geom/eli/g_eli.h +++ b/sys/geom/eli/g_eli.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,11 +57,12 @@ * 1 - Added data authentication support (md_aalgo field and * G_ELI_FLAG_AUTH flag). * 2 - Added G_ELI_FLAG_READONLY. - * - IV is generated from offset converted to little-endian - * (flag G_ELI_FLAG_NATIVE_BYTE_ORDER will be set for older versions). * 3 - Added 'configure' subcommand. + * 4 - IV is generated from offset converted to little-endian + * (flag G_ELI_FLAG_NATIVE_BYTE_ORDER will be set for older versions). + * 5 - Added multiple encrypton keys and AES-XTS support. */ -#define G_ELI_VERSION 3 +#define G_ELI_VERSION 5 /* ON DISK FLAGS. */ /* Use random, onetime keys. */ @@ -83,6 +84,12 @@ #define G_ELI_FLAG_DESTROY 0x00020000 /* Provider uses native byte-order for IV generation. */ #define G_ELI_FLAG_NATIVE_BYTE_ORDER 0x00040000 +/* Provider uses single encryption key. */ +#define G_ELI_FLAG_SINGLE_KEY 0x00080000 +/* Device suspended. */ +#define G_ELI_FLAG_SUSPEND 0x00100000 + +#define G_ELI_NEW_BIO 255 #define SHA512_MDLEN 64 #define G_ELI_AUTH_SECKEYLEN SHA256_DIGEST_LENGTH @@ -97,12 +104,16 @@ #define G_ELI_DATAIVKEYLEN (G_ELI_DATAKEYLEN + G_ELI_IVKEYLEN) /* Data-Key, IV-Key, HMAC_SHA512(Derived-Key, Data-Key+IV-Key) */ #define G_ELI_MKEYLEN (G_ELI_DATAIVKEYLEN + SHA512_MDLEN) +#define G_ELI_OVERWRITES 5 +/* Switch data encryption key every 2^20 blocks. */ +#define G_ELI_KEY_SHIFT 20 #ifdef _KERNEL -extern u_int g_eli_debug; +extern int g_eli_debug; extern u_int g_eli_overwrites; extern u_int g_eli_batch; +#define G_ELI_CRYPTO_UNKNOWN 0 #define G_ELI_CRYPTO_HW 1 #define G_ELI_CRYPTO_SW 2 @@ -134,31 +145,36 @@ struct g_eli_worker { struct proc *w_proc; u_int w_number; uint64_t w_sid; + boolean_t w_active; LIST_ENTRY(g_eli_worker) w_next; }; struct g_eli_softc { - struct g_geom *sc_geom; - u_int sc_crypto; - uint8_t sc_mkey[G_ELI_DATAIVKEYLEN]; - uint8_t sc_ekey[G_ELI_DATAKEYLEN]; - u_int sc_ealgo; - u_int sc_ekeylen; - uint8_t sc_akey[G_ELI_AUTHKEYLEN]; - u_int sc_aalgo; - u_int sc_akeylen; - u_int sc_alen; - SHA256_CTX sc_akeyctx; - uint8_t sc_ivkey[G_ELI_IVKEYLEN]; - SHA256_CTX sc_ivctx; - int sc_nkey; - uint32_t sc_flags; - u_int sc_bytes_per_sector; - u_int sc_data_per_sector; + struct g_geom *sc_geom; + u_int sc_crypto; + uint8_t sc_mkey[G_ELI_DATAIVKEYLEN]; + uint8_t **sc_ekeys; + u_int sc_nekeys; + u_int sc_ealgo; + u_int sc_ekeylen; + uint8_t sc_akey[G_ELI_AUTHKEYLEN]; + u_int sc_aalgo; + u_int sc_akeylen; + u_int sc_alen; + SHA256_CTX sc_akeyctx; + uint8_t sc_ivkey[G_ELI_IVKEYLEN]; + SHA256_CTX sc_ivctx; + int sc_nkey; + uint32_t sc_flags; + int sc_inflight; + off_t sc_mediasize; + size_t sc_sectorsize; + u_int sc_bytes_per_sector; + u_int sc_data_per_sector; /* Only for software cryptography. */ struct bio_queue_head sc_queue; - struct mtx sc_queue_mtx; + struct mtx sc_queue_mtx; LIST_HEAD(, g_eli_worker) sc_workers; }; #define sc_name sc_geom->name @@ -228,8 +244,9 @@ eli_metadata_decode_v0(const u_char *data, struct g_eli_metadata *md) return (EINVAL); return (0); } + static __inline int -eli_metadata_decode_v1v2v3(const u_char *data, struct g_eli_metadata *md) +eli_metadata_decode_v1v2v3v4v5(const u_char *data, struct g_eli_metadata *md) { MD5_CTX ctx; const u_char *p; @@ -266,7 +283,9 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md) case 1: case 2: case 3: - error = eli_metadata_decode_v1v2v3(data, md); + case 4: + case 5: + error = eli_metadata_decode_v1v2v3v4v5(data, md); break; default: error = EINVAL; @@ -282,14 +301,26 @@ g_eli_str2ealgo(const char *name) if (strcasecmp("null", name) == 0) return (CRYPTO_NULL_CBC); + else if (strcasecmp("null-cbc", name) == 0) + return (CRYPTO_NULL_CBC); else if (strcasecmp("aes", name) == 0) + return (CRYPTO_AES_XTS); + else if (strcasecmp("aes-cbc", name) == 0) return (CRYPTO_AES_CBC); + else if (strcasecmp("aes-xts", name) == 0) + return (CRYPTO_AES_XTS); else if (strcasecmp("blowfish", name) == 0) return (CRYPTO_BLF_CBC); + else if (strcasecmp("blowfish-cbc", name) == 0) + return (CRYPTO_BLF_CBC); else if (strcasecmp("camellia", name) == 0) return (CRYPTO_CAMELLIA_CBC); + else if (strcasecmp("camellia-cbc", name) == 0) + return (CRYPTO_CAMELLIA_CBC); else if (strcasecmp("3des", name) == 0) return (CRYPTO_3DES_CBC); + else if (strcasecmp("3des-cbc", name) == 0) + return (CRYPTO_3DES_CBC); return (CRYPTO_ALGORITHM_MIN - 1); } @@ -321,6 +352,8 @@ g_eli_algo2str(u_int algo) return ("NULL"); case CRYPTO_AES_CBC: return ("AES-CBC"); + case CRYPTO_AES_XTS: + return ("AES-XTS"); case CRYPTO_BLF_CBC: return ("Blowfish-CBC"); case CRYPTO_CAMELLIA_CBC: @@ -394,7 +427,7 @@ g_eli_keylen(u_int algo, u_int keylen) keylen = 0; } return (keylen); - case CRYPTO_AES_CBC: /* FALLTHROUGH */ + case CRYPTO_AES_CBC: case CRYPTO_CAMELLIA_CBC: switch (keylen) { case 0: @@ -406,6 +439,16 @@ g_eli_keylen(u_int algo, u_int keylen) default: return (0); } + case CRYPTO_AES_XTS: + switch (keylen) { + case 0: + return (128); + case 128: + case 256: + return (keylen); + default: + return (0); + } case CRYPTO_BLF_CBC: if (keylen == 0) return (128); @@ -458,9 +501,12 @@ void g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb); void g_eli_read_done(struct bio *bp); void g_eli_write_done(struct bio *bp); int g_eli_crypto_rerun(struct cryptop *crp); +uint8_t *g_eli_crypto_key(struct g_eli_softc *sc, off_t offset, + size_t blocksize); void g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv, size_t size); +void g_eli_crypto_read(struct g_eli_softc *sc, struct bio *bp, boolean_t fromworker); void g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp); void g_eli_auth_read(struct g_eli_softc *sc, struct bio *bp); diff --git a/sys/geom/eli/g_eli_crypto.c b/sys/geom/eli/g_eli_crypto.c index b247efc70fb..8cf9ec10c50 100644 --- a/sys/geom/eli/g_eli_crypto.c +++ b/sys/geom/eli/g_eli_crypto.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,6 +69,9 @@ g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, u_char *p; int error; + KASSERT(algo != CRYPTO_AES_XTS, + ("%s: CRYPTO_AES_XTS unexpected here", __func__)); + bzero(&cri, sizeof(cri)); cri.cri_alg = algo; cri.cri_key = __DECONST(void *, key); @@ -136,6 +139,8 @@ g_eli_crypto_cipher(u_int algo, int enc, u_char *data, size_t datasize, u_char iv[keysize]; int outsize; + assert(algo != CRYPTO_AES_XTS); + switch (algo) { case CRYPTO_NULL_CBC: type = EVP_enc_null(); @@ -212,6 +217,10 @@ g_eli_crypto_encrypt(u_int algo, u_char *data, size_t datasize, const u_char *key, size_t keysize) { + /* We prefer AES-CBC for metadata protection. */ + if (algo == CRYPTO_AES_XTS) + algo = CRYPTO_AES_CBC; + return (g_eli_crypto_cipher(algo, 1, data, datasize, key, keysize)); } @@ -220,6 +229,10 @@ g_eli_crypto_decrypt(u_int algo, u_char *data, size_t datasize, const u_char *key, size_t keysize) { + /* We prefer AES-CBC for metadata protection. */ + if (algo == CRYPTO_AES_XTS) + algo = CRYPTO_AES_CBC; + return (g_eli_crypto_cipher(algo, 0, data, datasize, key, keysize)); } diff --git a/sys/geom/eli/g_eli_ctl.c b/sys/geom/eli/g_eli_ctl.c index 558a4f278f1..24139187e76 100644 --- a/sys/geom/eli/g_eli_ctl.c +++ b/sys/geom/eli/g_eli_ctl.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,7 +217,7 @@ g_eli_ctl_detach(struct gctl_req *req, struct g_class *mp) sc->sc_flags |= G_ELI_FLAG_RW_DETACH; sc->sc_geom->access = g_eli_access; } else { - error = g_eli_destroy(sc, *force); + error = g_eli_destroy(sc, *force ? TRUE : FALSE); if (error != 0) { gctl_error(req, "Cannot destroy device %s (error=%d).", @@ -269,7 +269,7 @@ g_eli_ctl_onetime(struct gctl_req *req, struct g_class *mp) gctl_error(req, "No '%s' argument.", "aalgo"); return; } - if (strcmp(name, "none") != 0) { + if (*name != '\0') { md.md_aalgo = g_eli_str2aalgo(name); if (md.md_aalgo >= CRYPTO_ALGORITHM_MIN && md.md_aalgo <= CRYPTO_ALGORITHM_MAX) { @@ -688,7 +688,7 @@ g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) * Flush write cache so we don't overwrite data N times in cache * and only once on disk. */ - g_io_flush(cp); + (void)g_io_flush(cp); } bzero(&md, sizeof(md)); bzero(sector, sizeof(sector)); @@ -699,6 +699,201 @@ g_eli_ctl_delkey(struct gctl_req *req, struct g_class *mp) G_ELI_DEBUG(1, "Key %d removed from %s.", nkey, pp->name); } +static void +g_eli_suspend_one(struct g_eli_softc *sc, struct gctl_req *req) +{ + struct g_eli_worker *wr; + + g_topology_assert(); + + KASSERT(sc != NULL, ("NULL sc")); + + if (sc->sc_flags & G_ELI_FLAG_ONETIME) { + gctl_error(req, + "Device %s is using one-time key, suspend not supported.", + sc->sc_name); + return; + } + + mtx_lock(&sc->sc_queue_mtx); + if (sc->sc_flags & G_ELI_FLAG_SUSPEND) { + mtx_unlock(&sc->sc_queue_mtx); + gctl_error(req, "Device %s already suspended.", + sc->sc_name); + return; + } + sc->sc_flags |= G_ELI_FLAG_SUSPEND; + wakeup(sc); + for (;;) { + LIST_FOREACH(wr, &sc->sc_workers, w_next) { + if (wr->w_active) + break; + } + if (wr == NULL) + break; + /* Not all threads suspended. */ + msleep(&sc->sc_workers, &sc->sc_queue_mtx, PRIBIO, + "geli:suspend", 0); + } + /* + * Clear sensitive data on suspend, they will be recovered on resume. + */ + bzero(sc->sc_mkey, sizeof(sc->sc_mkey)); + bzero(sc->sc_ekeys, + sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN)); + free(sc->sc_ekeys, M_ELI); + sc->sc_ekeys = NULL; + bzero(sc->sc_akey, sizeof(sc->sc_akey)); + bzero(&sc->sc_akeyctx, sizeof(sc->sc_akeyctx)); + bzero(sc->sc_ivkey, sizeof(sc->sc_ivkey)); + bzero(&sc->sc_ivctx, sizeof(sc->sc_ivctx)); + mtx_unlock(&sc->sc_queue_mtx); + G_ELI_DEBUG(0, "Device %s has been suspended.", sc->sc_name); +} + +static void +g_eli_ctl_suspend(struct gctl_req *req, struct g_class *mp) +{ + struct g_eli_softc *sc; + int *all, *nargs; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument.", "nargs"); + return; + } + all = gctl_get_paraml(req, "all", sizeof(*all)); + if (all == NULL) { + gctl_error(req, "No '%s' argument.", "all"); + return; + } + if (!*all && *nargs == 0) { + gctl_error(req, "Too few arguments."); + return; + } + + if (*all) { + struct g_geom *gp, *gp2; + + LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { + sc = gp->softc; + if (sc->sc_flags & G_ELI_FLAG_ONETIME) { + G_ELI_DEBUG(0, + "Device %s is using one-time key, suspend not supported, skipping.", + sc->sc_name); + continue; + } + g_eli_suspend_one(sc, req); + } + } else { + const char *prov; + char param[16]; + int i; + + for (i = 0; i < *nargs; i++) { + snprintf(param, sizeof(param), "arg%d", i); + prov = gctl_get_asciiparam(req, param); + if (prov == NULL) { + G_ELI_DEBUG(0, "No 'arg%d' argument.", i); + continue; + } + + sc = g_eli_find_device(mp, prov); + if (sc == NULL) { + G_ELI_DEBUG(0, "No such provider: %s.", prov); + continue; + } + g_eli_suspend_one(sc, req); + } + } +} + +static void +g_eli_ctl_resume(struct gctl_req *req, struct g_class *mp) +{ + struct g_eli_metadata md; + struct g_eli_softc *sc; + struct g_provider *pp; + struct g_consumer *cp; + const char *name; + u_char *key, mkey[G_ELI_DATAIVKEYLEN]; + int *nargs, keysize, error; + u_int nkey; + + g_topology_assert(); + + nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); + if (nargs == NULL) { + gctl_error(req, "No '%s' argument.", "nargs"); + return; + } + if (*nargs != 1) { + gctl_error(req, "Invalid number of arguments."); + return; + } + + name = gctl_get_asciiparam(req, "arg0"); + if (name == NULL) { + gctl_error(req, "No 'arg%u' argument.", 0); + return; + } + sc = g_eli_find_device(mp, name); + if (sc == NULL) { + gctl_error(req, "Provider %s is invalid.", name); + return; + } + cp = LIST_FIRST(&sc->sc_geom->consumer); + pp = cp->provider; + error = g_eli_read_metadata(mp, pp, &md); + if (error != 0) { + gctl_error(req, "Cannot read metadata from %s (error=%d).", + name, error); + return; + } + if (md.md_keys == 0x00) { + bzero(&md, sizeof(md)); + gctl_error(req, "No valid keys on %s.", pp->name); + return; + } + + key = gctl_get_param(req, "key", &keysize); + if (key == NULL || keysize != G_ELI_USERKEYLEN) { + bzero(&md, sizeof(md)); + gctl_error(req, "No '%s' argument.", "key"); + return; + } + + error = g_eli_mkey_decrypt(&md, key, mkey, &nkey); + bzero(key, keysize); + if (error == -1) { + bzero(&md, sizeof(md)); + gctl_error(req, "Wrong key for %s.", pp->name); + return; + } else if (error > 0) { + bzero(&md, sizeof(md)); + gctl_error(req, "Cannot decrypt Master Key for %s (error=%d).", + pp->name, error); + return; + } + G_ELI_DEBUG(1, "Using Master Key %u for %s.", nkey, pp->name); + + mtx_lock(&sc->sc_queue_mtx); + if (!(sc->sc_flags & G_ELI_FLAG_SUSPEND)) + gctl_error(req, "Device %s is not suspended.", name); + else { + /* Restore sc_mkey, sc_ekeys, sc_akey and sc_ivkey. */ + g_eli_mkey_propagate(sc, mkey); + sc->sc_flags &= ~G_ELI_FLAG_SUSPEND; + G_ELI_DEBUG(1, "Resumed %s.", pp->name); + wakeup(sc); + } + mtx_unlock(&sc->sc_queue_mtx); + bzero(mkey, sizeof(mkey)); + bzero(&md, sizeof(md)); +} + static int g_eli_kill_one(struct g_eli_softc *sc) { @@ -739,12 +934,17 @@ g_eli_kill_one(struct g_eli_softc *sc) if (error == 0) error = err; } + /* + * Flush write cache so we don't overwrite data N times + * in cache and only once on disk. + */ + (void)g_io_flush(cp); } free(sector, M_ELI); } if (error == 0) G_ELI_DEBUG(0, "%s has been killed.", pp->name); - g_eli_destroy(sc, 1); + g_eli_destroy(sc, TRUE); return (error); } @@ -834,6 +1034,10 @@ g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb) g_eli_ctl_setkey(req, mp); else if (strcmp(verb, "delkey") == 0) g_eli_ctl_delkey(req, mp); + else if (strcmp(verb, "suspend") == 0) + g_eli_ctl_suspend(req, mp); + else if (strcmp(verb, "resume") == 0) + g_eli_ctl_resume(req, mp); else if (strcmp(verb, "kill") == 0) g_eli_ctl_kill(req, mp); else diff --git a/sys/geom/eli/g_eli_integrity.c b/sys/geom/eli/g_eli_integrity.c index b9a3f31359a..24586bd786c 100644 --- a/sys/geom/eli/g_eli_integrity.c +++ b/sys/geom/eli/g_eli_integrity.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -129,6 +129,7 @@ g_eli_auth_keygen(struct g_eli_softc *sc, off_t offset, u_char *key) static int g_eli_auth_read_done(struct cryptop *crp) { + struct g_eli_softc *sc; struct bio *bp; if (crp->crp_etype == EAGAIN) { @@ -152,8 +153,8 @@ g_eli_auth_read_done(struct cryptop *crp) */ if (bp->bio_inbed < bp->bio_children) return (0); + sc = bp->bio_to->geom->softc; if (bp->bio_error == 0) { - struct g_eli_softc *sc; u_int i, lsec, nsec, data_secsize, decr_secsize, encr_secsize; u_char *srcdata, *dstdata, *auth; off_t coroff, corsize; @@ -161,7 +162,6 @@ g_eli_auth_read_done(struct cryptop *crp) /* * Verify data integrity based on calculated and read HMACs. */ - sc = bp->bio_to->geom->softc; /* Sectorsize of decrypted provider eg. 4096. */ decr_secsize = bp->bio_to->sectorsize; /* The real sectorsize of encrypted provider, eg. 512. */ @@ -240,6 +240,7 @@ g_eli_auth_read_done(struct cryptop *crp) * Read is finished, send it up. */ g_io_deliver(bp, bp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); return (0); } @@ -276,6 +277,7 @@ g_eli_auth_write_done(struct cryptop *crp) */ if (bp->bio_inbed < bp->bio_children) return (0); + sc = bp->bio_to->geom->softc; if (bp->bio_error != 0) { G_ELI_LOGREQ(0, bp, "Crypto WRITE request failed (error=%d).", bp->bio_error); @@ -285,9 +287,9 @@ g_eli_auth_write_done(struct cryptop *crp) bp->bio_driver1 = NULL; g_destroy_bio(cbp); g_io_deliver(bp, bp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); return (0); } - sc = bp->bio_to->geom->softc; cp = LIST_FIRST(&sc->sc_geom->consumer); cbp = bp->bio_driver1; bp->bio_driver1 = NULL; @@ -392,6 +394,11 @@ g_eli_auth_read(struct g_eli_softc *sc, struct bio *bp) /* * This is the main function responsible for cryptography (ie. communication * with crypto(9) subsystem). + * + * BIO_READ: + * g_eli_start -> g_eli_auth_read -> g_io_request -> g_eli_read_done -> G_ELI_AUTH_RUN -> g_eli_auth_read_done -> g_io_deliver + * BIO_WRITE: + * g_eli_start -> G_ELI_AUTH_RUN -> g_eli_auth_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver */ void g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp) @@ -507,8 +514,10 @@ g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp) if (bp->bio_cmd == BIO_WRITE) crde->crd_flags |= CRD_F_ENCRYPT; crde->crd_alg = sc->sc_ealgo; - crde->crd_key = sc->sc_ekey; + crde->crd_key = g_eli_crypto_key(sc, dstoff, encr_secsize); crde->crd_klen = sc->sc_ekeylen; + if (sc->sc_ealgo == CRYPTO_AES_XTS) + crde->crd_klen <<= 1; g_eli_crypto_ivgen(sc, dstoff, crde->crd_iv, sizeof(crde->crd_iv)); diff --git a/sys/geom/eli/g_eli_key.c b/sys/geom/eli/g_eli_key.c index 5b024d787cc..37b2ad3b627 100644 --- a/sys/geom/eli/g_eli_key.c +++ b/sys/geom/eli/g_eli_key.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,9 @@ __FBSDID("$FreeBSD$"); #include +#ifdef _KERNEL +MALLOC_DECLARE(M_ELI); +#endif /* * Verify if the given 'key' is correct. @@ -178,6 +181,46 @@ g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen, } #ifdef _KERNEL +static void +g_eli_ekeys_generate(struct g_eli_softc *sc) +{ + uint8_t *keys; + u_int kno; + off_t mediasize; + size_t blocksize; + struct { + char magic[4]; + uint8_t keyno[8]; + } __packed hmacdata; + + KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0, + ("%s: G_ELI_FLAG_SINGLE_KEY flag present", __func__)); + + if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { + struct g_provider *pp; + + pp = LIST_FIRST(&sc->sc_geom->consumer)->provider; + mediasize = pp->mediasize; + blocksize = pp->sectorsize; + } else { + mediasize = sc->sc_mediasize; + blocksize = sc->sc_sectorsize; + } + sc->sc_nekeys = ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1; + sc->sc_ekeys = + malloc(sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN), + M_ELI, M_WAITOK); + keys = (uint8_t *)(sc->sc_ekeys + sc->sc_nekeys); + bcopy("ekey", hmacdata.magic, 4); + for (kno = 0; kno < sc->sc_nekeys; kno++, keys += G_ELI_DATAKEYLEN) { + sc->sc_ekeys[kno] = keys; + le64enc(hmacdata.keyno, (uint64_t)kno); + g_eli_crypto_hmac(sc->sc_mkey, G_ELI_MAXKEYLEN, + (uint8_t *)&hmacdata, sizeof(hmacdata), + sc->sc_ekeys[kno], 0); + } +} + /* * When doing encryption only, copy IV key and encryption key. * When doing encryption and authentication, copy IV key, generate encryption @@ -193,16 +236,58 @@ g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey) bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey)); mkey += sizeof(sc->sc_ivkey); - if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) { - bcopy(mkey, sc->sc_ekey, sizeof(sc->sc_ekey)); + /* + * The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11) + */ + if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) { + g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1, + sc->sc_akey, 0); } else { - /* - * The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10) - * The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11) - */ - g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, sc->sc_ekey, 0); - g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1, sc->sc_akey, 0); + arc4rand(sc->sc_akey, sizeof(sc->sc_akey), 0); } + if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) { + sc->sc_nekeys = 1; + sc->sc_ekeys = malloc(sc->sc_nekeys * + (sizeof(uint8_t *) + G_ELI_DATAKEYLEN), M_ELI, M_WAITOK); + sc->sc_ekeys[0] = (uint8_t *)(sc->sc_ekeys + sc->sc_nekeys); + if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0) + bcopy(mkey, sc->sc_ekeys[0], G_ELI_DATAKEYLEN); + else { + /* + * The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10) + */ + g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, + sc->sc_ekeys[0], 0); + } + } else { + /* Generate all encryption keys. */ + g_eli_ekeys_generate(sc); + } + + if (sc->sc_flags & G_ELI_FLAG_AUTH) { + /* + * Precalculate SHA256 for HMAC key generation. + * This is expensive operation and we can do it only once now or + * for every access to sector, so now will be much better. + */ + SHA256_Init(&sc->sc_akeyctx); + SHA256_Update(&sc->sc_akeyctx, sc->sc_akey, + sizeof(sc->sc_akey)); + } + /* + * Precalculate SHA256 for IV generation. + * This is expensive operation and we can do it only once now or for + * every access to sector, so now will be much better. + */ + switch (sc->sc_ealgo) { + case CRYPTO_AES_XTS: + break; + default: + SHA256_Init(&sc->sc_ivctx); + SHA256_Update(&sc->sc_ivctx, sc->sc_ivkey, + sizeof(sc->sc_ivkey)); + break; + } } #endif diff --git a/sys/geom/eli/g_eli_privacy.c b/sys/geom/eli/g_eli_privacy.c index 94cc4fca564..ee133c6a200 100644 --- a/sys/geom/eli/g_eli_privacy.c +++ b/sys/geom/eli/g_eli_privacy.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * Copyright (c) 2005-2010 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ __FBSDID("$FreeBSD$"); /* * Code paths: * BIO_READ: - * g_eli_start -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver + * g_eli_start -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver * BIO_WRITE: * g_eli_start -> g_eli_crypto_run -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver */ @@ -63,11 +63,12 @@ MALLOC_DECLARE(M_ELI); /* * The function is called after we read and decrypt data. * - * g_eli_start -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> G_ELI_CRYPTO_READ_DONE -> g_io_deliver + * g_eli_start -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> G_ELI_CRYPTO_READ_DONE -> g_io_deliver */ static int g_eli_crypto_read_done(struct cryptop *crp) { + struct g_eli_softc *sc; struct bio *bp; if (crp->crp_etype == EAGAIN) { @@ -101,7 +102,9 @@ g_eli_crypto_read_done(struct cryptop *crp) /* * Read is finished, send it up. */ + sc = bp->bio_to->geom->softc; g_io_deliver(bp, bp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); return (0); } @@ -113,6 +116,7 @@ g_eli_crypto_read_done(struct cryptop *crp) static int g_eli_crypto_write_done(struct cryptop *crp) { + struct g_eli_softc *sc; struct g_geom *gp; struct g_consumer *cp; struct bio *bp, *cbp; @@ -141,18 +145,20 @@ g_eli_crypto_write_done(struct cryptop *crp) bp->bio_children = 1; cbp = bp->bio_driver1; bp->bio_driver1 = NULL; + gp = bp->bio_to->geom; if (bp->bio_error != 0) { G_ELI_LOGREQ(0, bp, "Crypto WRITE request failed (error=%d).", bp->bio_error); free(bp->bio_driver2, M_ELI); bp->bio_driver2 = NULL; g_destroy_bio(cbp); + sc = gp->softc; g_io_deliver(bp, bp->bio_error); + atomic_subtract_int(&sc->sc_inflight, 1); return (0); } cbp->bio_data = bp->bio_driver2; cbp->bio_done = g_eli_write_done; - gp = bp->bio_to->geom; cp = LIST_FIRST(&gp->consumer); cbp->bio_to = cp->provider; G_ELI_LOGREQ(2, cbp, "Sending request."); @@ -163,9 +169,58 @@ g_eli_crypto_write_done(struct cryptop *crp) return (0); } +/* + * The function is called to read encrypted data. + * + * g_eli_start -> G_ELI_CRYPTO_READ -> g_io_request -> g_eli_read_done -> g_eli_crypto_run -> g_eli_crypto_read_done -> g_io_deliver + */ +void +g_eli_crypto_read(struct g_eli_softc *sc, struct bio *bp, boolean_t fromworker) +{ + struct g_consumer *cp; + struct bio *cbp; + + if (!fromworker) { + /* + * We are not called from the worker thread, so check if + * device is suspended. + */ + mtx_lock(&sc->sc_queue_mtx); + if (sc->sc_flags & G_ELI_FLAG_SUSPEND) { + /* + * If device is suspended, we place the request onto + * the queue, so it can be handled after resume. + */ + G_ELI_DEBUG(0, "device suspended, move onto queue"); + bioq_insert_tail(&sc->sc_queue, bp); + mtx_unlock(&sc->sc_queue_mtx); + wakeup(sc); + return; + } + atomic_add_int(&sc->sc_inflight, 1); + mtx_unlock(&sc->sc_queue_mtx); + } + bp->bio_pflags = 0; + bp->bio_driver2 = NULL; + cbp = bp->bio_driver1; + cbp->bio_done = g_eli_read_done; + cp = LIST_FIRST(&sc->sc_geom->consumer); + cbp->bio_to = cp->provider; + G_ELI_LOGREQ(2, cbp, "Sending request."); + /* + * Read encrypted data from provider. + */ + g_io_request(cbp, cp); +} + /* * This is the main function responsible for cryptography (ie. communication * with crypto(9) subsystem). + * + * BIO_READ: + * g_eli_start -> g_eli_crypto_read -> g_io_request -> g_eli_read_done -> G_ELI_CRYPTO_RUN -> g_eli_crypto_read_done -> g_io_deliver + * BIO_WRITE: + * g_eli_start -> G_ELI_CRYPTO_RUN -> g_eli_crypto_write_done -> g_io_request -> g_eli_write_done -> g_io_deliver */ void g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) @@ -175,8 +230,9 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) struct cryptodesc *crd; struct uio *uio; struct iovec *iov; - u_int i, nsec, add, secsize; + u_int i, nsec, secsize; int err, error; + off_t dstoff; size_t size; u_char *p, *data; @@ -219,7 +275,7 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) } error = 0; - for (i = 0, add = 0; i < nsec; i++, add += secsize) { + for (i = 0, dstoff = bp->bio_offset; i < nsec; i++, dstoff += secsize) { crp = (struct cryptop *)p; p += sizeof(*crp); crd = (struct cryptodesc *)p; p += sizeof(*crd); uio = (struct uio *)p; p += sizeof(*uio); @@ -251,12 +307,16 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp) crd->crd_skip = 0; crd->crd_len = secsize; crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; + if (sc->sc_nekeys > 1) + crd->crd_flags |= CRD_F_KEY_EXPLICIT; if (bp->bio_cmd == BIO_WRITE) crd->crd_flags |= CRD_F_ENCRYPT; crd->crd_alg = sc->sc_ealgo; - crd->crd_key = sc->sc_ekey; + crd->crd_key = g_eli_crypto_key(sc, dstoff, secsize); crd->crd_klen = sc->sc_ekeylen; - g_eli_crypto_ivgen(sc, bp->bio_offset + add, crd->crd_iv, + if (sc->sc_ealgo == CRYPTO_AES_XTS) + crd->crd_klen <<= 1; + g_eli_crypto_ivgen(sc, dstoff, crd->crd_iv, sizeof(crd->crd_iv)); crd->crd_next = NULL; diff --git a/sys/geom/geom_dev.c b/sys/geom/geom_dev.c index 173e32672cb..e4cbbe38721 100644 --- a/sys/geom/geom_dev.c +++ b/sys/geom/geom_dev.c @@ -126,8 +126,16 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) error = g_attach(cp, pp); KASSERT(error == 0, ("g_dev_taste(%s) failed to g_attach, err=%d", pp->name, error)); - dev = make_dev(&g_dev_cdevsw, 0, - UID_ROOT, GID_OPERATOR, 0640, "%s", gp->name); + error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev, + &g_dev_cdevsw, NULL, UID_ROOT, GID_OPERATOR, 0640, "%s", gp->name); + if (error != 0) { + printf("%s: make_dev_p() failed (gp->name=%s, error=%d)\n", + __func__, gp->name, error); + g_detach(cp); + g_destroy_consumer(cp); + g_destroy_geom(gp); + return (NULL); + } if (pp->flags & G_PF_CANDELETE) dev->si_flags |= SI_CANDELETE; dev->si_iosize_max = MAXPHYS; diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index b145441cad7..b4044a75e33 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -265,6 +265,7 @@ g_io_flush(struct g_consumer *cp) g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name); bp = g_alloc_bio(); bp->bio_cmd = BIO_FLUSH; + bp->bio_flags |= BIO_ORDERED; bp->bio_done = NULL; bp->bio_attribute = NULL; bp->bio_offset = cp->provider->mediasize; diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index 404ab986b35..41d35e45d34 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -844,21 +844,6 @@ g_mirror_unidle(struct g_mirror_softc *sc) } } -static __inline int -bintime_cmp(struct bintime *bt1, struct bintime *bt2) -{ - - if (bt1->sec < bt2->sec) - return (-1); - else if (bt1->sec > bt2->sec) - return (1); - if (bt1->frac < bt2->frac) - return (-1); - else if (bt1->frac > bt2->frac) - return (1); - return (0); -} - static void g_mirror_done(struct bio *bp) { diff --git a/sys/geom/mirror/g_mirror_ctl.c b/sys/geom/mirror/g_mirror_ctl.c index 4524a90d8dd..dc59e185133 100644 --- a/sys/geom/mirror/g_mirror_ctl.c +++ b/sys/geom/mirror/g_mirror_ctl.c @@ -192,7 +192,7 @@ g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) gctl_error(req, "No such device: %s.", name); return; } - if (strcmp(balancep, "none") == 0) + if (*balancep == '\0') balance = sc->sc_balance; else { if (balance_id(balancep) == -1) { @@ -215,7 +215,7 @@ g_mirror_ctl_configure(struct gctl_req *req, struct g_class *mp) /* Enforce usage() of -p not allowing any other options. */ if (do_priority && (*autosync || *noautosync || *failsync || *nofailsync || *hardcode || *dynamic || *slicep != -1 || - strcmp(balancep, "none") != 0)) { + *balancep != '\0')) { sx_xunlock(&sc->sc_lock); gctl_error(req, "only -p accepted when setting priority"); return; diff --git a/sys/geom/part/g_part.c b/sys/geom/part/g_part.c index b9fca082dad..d88213b1d65 100644 --- a/sys/geom/part/g_part.c +++ b/sys/geom/part/g_part.c @@ -297,90 +297,155 @@ g_part_new_provider(struct g_geom *gp, struct g_part_table *table, } static int -g_part_parm_geom(const char *rawname, struct g_geom **v) +g_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v) { struct g_geom *gp; - const char *pname; + const char *gname; - if (strncmp(rawname, _PATH_DEV, strlen(_PATH_DEV)) == 0) - pname = rawname + strlen(_PATH_DEV); - else - pname = rawname; + gname = gctl_get_asciiparam(req, name); + if (gname == NULL) + return (ENOATTR); + if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + gname += sizeof(_PATH_DEV) - 1; LIST_FOREACH(gp, &g_part_class.geom, geom) { - if (!strcmp(pname, gp->name)) + if (!strcmp(gname, gp->name)) break; } - if (gp == NULL) + if (gp == NULL) { + gctl_error(req, "%d %s '%s'", EINVAL, name, gname); return (EINVAL); + } *v = gp; return (0); } static int -g_part_parm_provider(const char *pname, struct g_provider **v) +g_part_parm_provider(struct gctl_req *req, const char *name, + struct g_provider **v) { struct g_provider *pp; + const char *pname; - if (strncmp(pname, _PATH_DEV, strlen(_PATH_DEV)) == 0) - pp = g_provider_by_name(pname + strlen(_PATH_DEV)); - else - pp = g_provider_by_name(pname); - if (pp == NULL) + pname = gctl_get_asciiparam(req, name); + if (pname == NULL) + return (ENOATTR); + if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + pname += sizeof(_PATH_DEV) - 1; + pp = g_provider_by_name(pname); + if (pp == NULL) { + gctl_error(req, "%d %s '%s'", EINVAL, name, pname); return (EINVAL); + } *v = pp; return (0); } static int -g_part_parm_quad(const char *p, quad_t *v) +g_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v) { + const char *p; char *x; quad_t q; + p = gctl_get_asciiparam(req, name); + if (p == NULL) + return (ENOATTR); q = strtoq(p, &x, 0); - if (*x != '\0' || q < 0) + if (*x != '\0' || q < 0) { + gctl_error(req, "%d %s '%s'", EINVAL, name, p); return (EINVAL); + } *v = q; return (0); } static int -g_part_parm_scheme(const char *p, struct g_part_scheme **v) +g_part_parm_scheme(struct gctl_req *req, const char *name, + struct g_part_scheme **v) { struct g_part_scheme *s; + const char *p; + p = gctl_get_asciiparam(req, name); + if (p == NULL) + return (ENOATTR); TAILQ_FOREACH(s, &g_part_schemes, scheme_list) { if (s == &g_part_null_scheme) continue; if (!strcasecmp(s->name, p)) break; } - if (s == NULL) + if (s == NULL) { + gctl_error(req, "%d %s '%s'", EINVAL, name, p); return (EINVAL); + } *v = s; return (0); } static int -g_part_parm_str(const char *p, const char **v) +g_part_parm_str(struct gctl_req *req, const char *name, const char **v) { + const char *p; - if (p[0] == '\0') + p = gctl_get_asciiparam(req, name); + if (p == NULL) + return (ENOATTR); + /* An empty label is always valid. */ + if (strcmp(name, "label") != 0 && p[0] == '\0') { + gctl_error(req, "%d %s '%s'", EINVAL, name, p); return (EINVAL); + } *v = p; return (0); } static int -g_part_parm_uint(const char *p, u_int *v) +g_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v) { - char *x; - long l; + const intmax_t *p; + int size; - l = strtol(p, &x, 0); - if (*x != '\0' || l < 0 || l > INT_MAX) + p = gctl_get_param(req, name, &size); + if (p == NULL) + return (ENOATTR); + if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) { + gctl_error(req, "%d %s '%jd'", EINVAL, name, *p); return (EINVAL); - *v = (unsigned int)l; + } + *v = (u_int)*p; + return (0); +} + +static int +g_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v) +{ + const uint32_t *p; + int size; + + p = gctl_get_param(req, name, &size); + if (p == NULL) + return (ENOATTR); + if (size != sizeof(*p) || *p > INT_MAX) { + gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p); + return (EINVAL); + } + *v = (u_int)*p; + return (0); +} + +static int +g_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v, + unsigned int *s) +{ + const void *p; + int size; + + p = gctl_get_param(req, name, &size); + if (p == NULL) + return (ENOATTR); + *v = p; + *s = size; return (0); } @@ -571,7 +636,7 @@ g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp) /* Provide feedback if so requested. */ if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { sb = sbuf_new_auto(); - sbuf_printf(sb, "%s has bootcode\n", gp->name); + sbuf_printf(sb, "bootcode written to %s\n", gp->name); sbuf_finish(sb); gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); @@ -683,7 +748,7 @@ g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp) g_topology_assert(); /* Check that there isn't already a g_part geom on the provider. */ - error = g_part_parm_geom(pp->name, &gp); + error = g_part_parm_geom(req, "provider", &gp); if (!error) { null = gp->softc; if (null->gpt_scheme != &g_part_null_scheme) { @@ -967,7 +1032,7 @@ g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp) { gctl_error(req, "%d verb 'move'", ENOSYS); return (ENOSYS); -} +} static int g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) @@ -1095,9 +1160,10 @@ g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, /* Provide feedback if so requested. */ if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { sb = sbuf_new_auto(); - G_PART_FULLNAME(table, entry, sb, gp->name); - sbuf_printf(sb, " has %s %sset\n", gpp->gpp_attrib, + sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib, (set) ? "" : "un"); + G_PART_FULLNAME(table, entry, sb, gp->name); + sbuf_printf(sb, "\n"); sbuf_finish(sb); gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); sbuf_delete(sb); @@ -1207,6 +1273,7 @@ g_part_wither(struct g_geom *gp, int error) table = gp->softc; if (table != NULL) { + G_PART_DESTROY(table, NULL); while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) { LIST_REMOVE(entry, gpe_entry); g_free(entry); @@ -1229,11 +1296,10 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) struct g_part_parms gpp; struct g_part_table *table; struct gctl_req_arg *ap; - const char *p; enum g_part_ctl ctlreq; unsigned int i, mparms, oparms, parm; int auto_commit, close_on_error; - int error, len, modifies; + int error, modifies; G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb)); g_topology_assert(); @@ -1327,6 +1393,10 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) parm = 0; switch (ap->name[0]) { case 'a': + if (!strcmp(ap->name, "arg0")) { + parm = mparms & + (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER); + } if (!strcmp(ap->name, "attrib")) parm = G_PART_PARM_ATTRIB; break; @@ -1346,10 +1416,6 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) if (!strcmp(ap->name, "flags")) parm = G_PART_PARM_FLAGS; break; - case 'g': - if (!strcmp(ap->name, "geom")) - parm = G_PART_PARM_GEOM; - break; case 'i': if (!strcmp(ap->name, "index")) parm = G_PART_PARM_INDEX; @@ -1362,10 +1428,6 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) if (!strcmp(ap->name, "output")) parm = G_PART_PARM_OUTPUT; break; - case 'p': - if (!strcmp(ap->name, "provider")) - parm = G_PART_PARM_PROVIDER; - break; case 's': if (!strcmp(ap->name, "scheme")) parm = G_PART_PARM_SCHEME; @@ -1389,69 +1451,64 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) gctl_error(req, "%d param '%s'", EINVAL, ap->name); return; } - if (parm == G_PART_PARM_BOOTCODE) - p = gctl_get_param(req, ap->name, &len); - else - p = gctl_get_asciiparam(req, ap->name); - if (p == NULL) { - gctl_error(req, "%d param '%s'", ENOATTR, ap->name); - return; - } switch (parm) { case G_PART_PARM_ATTRIB: - error = g_part_parm_str(p, &gpp.gpp_attrib); + error = g_part_parm_str(req, ap->name, &gpp.gpp_attrib); break; case G_PART_PARM_BOOTCODE: - gpp.gpp_codeptr = p; - gpp.gpp_codesize = len; - error = 0; + error = g_part_parm_bootcode(req, ap->name, + &gpp.gpp_codeptr, &gpp.gpp_codesize); break; case G_PART_PARM_ENTRIES: - error = g_part_parm_uint(p, &gpp.gpp_entries); + error = g_part_parm_intmax(req, ap->name, + &gpp.gpp_entries); break; case G_PART_PARM_FLAGS: - if (p[0] == '\0') - continue; - error = g_part_parm_str(p, &gpp.gpp_flags); + error = g_part_parm_str(req, ap->name, &gpp.gpp_flags); break; case G_PART_PARM_GEOM: - error = g_part_parm_geom(p, &gpp.gpp_geom); + error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom); break; case G_PART_PARM_INDEX: - error = g_part_parm_uint(p, &gpp.gpp_index); + error = g_part_parm_intmax(req, ap->name, &gpp.gpp_index); break; case G_PART_PARM_LABEL: - /* An empty label is always valid. */ - gpp.gpp_label = p; - error = 0; + error = g_part_parm_str(req, ap->name, &gpp.gpp_label); break; case G_PART_PARM_OUTPUT: error = 0; /* Write-only parameter */ break; case G_PART_PARM_PROVIDER: - error = g_part_parm_provider(p, &gpp.gpp_provider); + error = g_part_parm_provider(req, ap->name, + &gpp.gpp_provider); break; case G_PART_PARM_SCHEME: - error = g_part_parm_scheme(p, &gpp.gpp_scheme); + error = g_part_parm_scheme(req, ap->name, + &gpp.gpp_scheme); break; case G_PART_PARM_SIZE: - error = g_part_parm_quad(p, &gpp.gpp_size); + error = g_part_parm_quad(req, ap->name, &gpp.gpp_size); break; case G_PART_PARM_START: - error = g_part_parm_quad(p, &gpp.gpp_start); + error = g_part_parm_quad(req, ap->name, &gpp.gpp_start); break; case G_PART_PARM_TYPE: - error = g_part_parm_str(p, &gpp.gpp_type); + error = g_part_parm_str(req, ap->name, &gpp.gpp_type); break; case G_PART_PARM_VERSION: - error = g_part_parm_uint(p, &gpp.gpp_version); + error = g_part_parm_uint32(req, ap->name, + &gpp.gpp_version); break; default: error = EDOOFUS; + gctl_error(req, "%d %s", error, ap->name); break; } - if (error) { - gctl_error(req, "%d %s '%s'", error, ap->name, p); + if (error != 0) { + if (error == ENOATTR) { + gctl_error(req, "%d param '%s'", error, + ap->name); + } return; } gpp.gpp_parms |= parm; @@ -1540,7 +1597,8 @@ g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb) (gpp.gpp_parms & G_PART_PARM_FLAGS) && strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0; if (auto_commit) { - KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__)); + KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s", + __func__)); error = g_part_ctl_commit(req, &gpp); } } @@ -1680,11 +1738,11 @@ g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_part_entry *entry; struct g_part_table *table; - KASSERT(sb != NULL && gp != NULL, (__func__)); + KASSERT(sb != NULL && gp != NULL, ("%s", __func__)); table = gp->softc; if (indent == NULL) { - KASSERT(cp == NULL && pp != NULL, (__func__)); + KASSERT(cp == NULL && pp != NULL, ("%s", __func__)); entry = pp->private; if (entry == NULL) return; @@ -1699,7 +1757,7 @@ g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, */ G_PART_DUMPCONF(table, entry, sb, indent); } else if (cp != NULL) { /* Consumer configuration. */ - KASSERT(pp == NULL, (__func__)); + KASSERT(pp == NULL, ("%s", __func__)); /* none */ } else if (pp != NULL) { /* Provider configuration. */ entry = pp->private; @@ -1742,11 +1800,11 @@ g_part_orphan(struct g_consumer *cp) struct g_part_table *table; pp = cp->provider; - KASSERT(pp != NULL, (__func__)); + KASSERT(pp != NULL, ("%s", __func__)); G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name)); g_topology_assert(); - KASSERT(pp->error != 0, (__func__)); + KASSERT(pp->error != 0, ("%s", __func__)); table = cp->geom->softc; if (table != NULL && table->gpt_opened) g_access(cp, -1, -1, -1); diff --git a/sys/geom/part/g_part_ebr.c b/sys/geom/part/g_part_ebr.c index b107e6120c0..f16f42a6f68 100644 --- a/sys/geom/part/g_part_ebr.c +++ b/sys/geom/part/g_part_ebr.c @@ -221,8 +221,8 @@ g_part_ebr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, if (baseentry->gpe_deleted) bzero(&entry->ent, sizeof(entry->ent)); - KASSERT(baseentry->gpe_start <= start, (__func__)); - KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); + KASSERT(baseentry->gpe_start <= start, ("%s", __func__)); + KASSERT(baseentry->gpe_end >= start + size - 1, ("%s", __func__)); baseentry->gpe_index = (start / sectors) + 1; baseentry->gpe_offset = (off_t)(start + sectors) * pp->sectorsize; baseentry->gpe_start = start; diff --git a/sys/geom/part/g_part_gpt.c b/sys/geom/part/g_part_gpt.c index 46a92abaa0d..ee319cf1f49 100644 --- a/sys/geom/part/g_part_gpt.c +++ b/sys/geom/part/g_part_gpt.c @@ -100,6 +100,8 @@ static const char *g_part_gpt_name(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *); static int g_part_gpt_read(struct g_part_table *, struct g_consumer *); +static int g_part_gpt_setunset(struct g_part_table *table, + struct g_part_entry *baseentry, const char *attrib, unsigned int set); static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_gpt_write(struct g_part_table *, struct g_consumer *); @@ -118,6 +120,7 @@ static kobj_method_t g_part_gpt_methods[] = { KOBJMETHOD(g_part_name, g_part_gpt_name), KOBJMETHOD(g_part_probe, g_part_gpt_probe), KOBJMETHOD(g_part_read, g_part_gpt_read), + KOBJMETHOD(g_part_setunset, g_part_gpt_setunset), KOBJMETHOD(g_part_type, g_part_gpt_type), KOBJMETHOD(g_part_write, g_part_gpt_write), { 0, 0 } @@ -519,6 +522,16 @@ g_part_gpt_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, g_gpt_printf_utf16(sb, entry->ent.ent_name, sizeof(entry->ent.ent_name) >> 1); sbuf_printf(sb, "\n"); + if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME) + sbuf_printf(sb, "%sbootme\n", indent); + if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE) { + sbuf_printf(sb, "%sbootonce\n", + indent); + } + if (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED) { + sbuf_printf(sb, "%sbootfailed\n", + indent); + } sbuf_printf(sb, "%s", indent); sbuf_printf_uuid(sb, &entry->ent.ent_type); sbuf_printf(sb, "\n"); @@ -755,6 +768,78 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp) return (0); } +static int +g_part_gpt_setunset(struct g_part_table *table, struct g_part_entry *baseentry, + const char *attrib, unsigned int set) +{ + struct g_part_entry *iter; + struct g_part_gpt_entry *entry; + int changed, bootme, bootonce, bootfailed; + + bootme = bootonce = bootfailed = 0; + if (strcasecmp(attrib, "bootme") == 0) { + bootme = 1; + } else if (strcasecmp(attrib, "bootonce") == 0) { + /* BOOTME is set automatically with BOOTONCE, but not unset. */ + bootonce = 1; + if (set) + bootme = 1; + } else if (strcasecmp(attrib, "bootfailed") == 0) { + /* + * It should only be possible to unset BOOTFAILED, but it might + * be useful for test purposes to also be able to set it. + */ + bootfailed = 1; + } + if (!bootme && !bootonce && !bootfailed) + return (EINVAL); + + LIST_FOREACH(iter, &table->gpt_entry, gpe_entry) { + if (iter->gpe_deleted) + continue; + if (iter != baseentry) + continue; + changed = 0; + entry = (struct g_part_gpt_entry *)iter; + if (set) { + if (bootme && + !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) { + entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTME; + changed = 1; + } + if (bootonce && + !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) { + entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTONCE; + changed = 1; + } + if (bootfailed && + !(entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) { + entry->ent.ent_attr |= GPT_ENT_ATTR_BOOTFAILED; + changed = 1; + } + } else { + if (bootme && + (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTME)) { + entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTME; + changed = 1; + } + if (bootonce && + (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTONCE)) { + entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTONCE; + changed = 1; + } + if (bootfailed && + (entry->ent.ent_attr & GPT_ENT_ATTR_BOOTFAILED)) { + entry->ent.ent_attr &= ~GPT_ENT_ATTR_BOOTFAILED; + changed = 1; + } + } + if (changed && !iter->gpe_created) + iter->gpe_modified = 1; + } + return (0); +} + static const char * g_part_gpt_type(struct g_part_table *basetable, struct g_part_entry *baseentry, char *buf, size_t bufsz) diff --git a/sys/geom/part/g_part_mbr.c b/sys/geom/part/g_part_mbr.c index 6cc6245ca74..454c7597389 100644 --- a/sys/geom/part/g_part_mbr.c +++ b/sys/geom/part/g_part_mbr.c @@ -204,8 +204,8 @@ g_part_mbr_add(struct g_part_table *basetable, struct g_part_entry *baseentry, if (baseentry->gpe_deleted) bzero(&entry->ent, sizeof(entry->ent)); - KASSERT(baseentry->gpe_start <= start, (__func__)); - KASSERT(baseentry->gpe_end >= start + size - 1, (__func__)); + KASSERT(baseentry->gpe_start <= start, ("%s", __func__)); + KASSERT(baseentry->gpe_end >= start + size - 1, ("%s", __func__)); baseentry->gpe_start = start; baseentry->gpe_end = start + size - 1; entry->ent.dp_start = start; @@ -465,6 +465,7 @@ g_part_mbr_read(struct g_part_table *basetable, struct g_consumer *cp) basetable->gpt_first = basetable->gpt_sectors; basetable->gpt_last = msize - (msize % basetable->gpt_sectors) - 1; + g_free(buf); return (0); } diff --git a/sys/geom/part/g_part_pc98.c b/sys/geom/part/g_part_pc98.c index ab83662a4f9..a4235d6a776 100644 --- a/sys/geom/part/g_part_pc98.c +++ b/sys/geom/part/g_part_pc98.c @@ -458,6 +458,7 @@ g_part_pc98_read(struct g_part_table *basetable, struct g_consumer *cp) basetable->gpt_first = cyl; basetable->gpt_last = msize - (msize % cyl) - 1; + g_free(buf); return (0); } diff --git a/sys/geom/sched/subr_disk.c b/sys/geom/sched/subr_disk.c index 008eaab1c94..db2a9ef11f8 100644 --- a/sys/geom/sched/subr_disk.c +++ b/sys/geom/sched/subr_disk.c @@ -86,7 +86,7 @@ __FBSDID("$FreeBSD$"); * bioq_remove() remove a generic element from the queue, act as * bioq_takefirst() if invoked on the head of the queue. * - * The semantic of these methods is the same of the operations + * The semantic of these methods is the same as the operations * on the underlying TAILQ, but with additional guarantees on * subsequent bioq_disksort() calls. E.g. bioq_insert_tail() * can be useful for making sure that all previous ops are flushed @@ -115,10 +115,10 @@ void gs_bioq_remove(struct bio_queue_head *head, struct bio *bp) { - if (bp == TAILQ_FIRST(&head->queue)) - head->last_offset = bp->bio_offset + bp->bio_length; - - if (bp == head->insert_point) + if (head->insert_point == NULL) { + if (bp == TAILQ_FIRST(&head->queue)) + head->last_offset = bp->bio_offset + bp->bio_length; + } else if (bp == head->insert_point) head->insert_point = NULL; TAILQ_REMOVE(&head->queue, bp, bio_queue); @@ -137,7 +137,8 @@ void gs_bioq_insert_head(struct bio_queue_head *head, struct bio *bp) { - head->last_offset = bp->bio_offset; + if (head->insert_point == NULL) + head->last_offset = bp->bio_offset; TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue); } @@ -147,6 +148,7 @@ gs_bioq_insert_tail(struct bio_queue_head *head, struct bio *bp) TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue); head->insert_point = bp; + head->last_offset = bp->bio_offset; } struct bio * @@ -189,13 +191,28 @@ gs_bioq_bio_key(struct bio_queue_head *head, struct bio *bp) void gs_bioq_disksort(struct bio_queue_head *head, struct bio *bp) { - struct bio *cur, *prev = NULL; - uoff_t key = gs_bioq_bio_key(head, bp); + struct bio *cur, *prev; + uoff_t key; + if ((bp->bio_flags & BIO_ORDERED) != 0) { + /* + * Ordered transactions can only be dispatched + * after any currently queued transactions. They + * also have barrier semantics - no transactions + * queued in the future can pass them. + */ + gs_bioq_insert_tail(head, bp); + return; + } + + prev = NULL; + key = gs_bioq_bio_key(head, bp); cur = TAILQ_FIRST(&head->queue); - if (head->insert_point) - cur = head->insert_point; + if (head->insert_point) { + prev = head->insert_point; + cur = TAILQ_NEXT(head->insert_point, bio_queue); + } while (cur != NULL && key >= gs_bioq_bio_key(head, cur)) { prev = cur; diff --git a/sys/geom/vinum/geom_vinum_move.c b/sys/geom/vinum/geom_vinum_move.c index 8c295f60821..1fe480caebe 100644 --- a/sys/geom/vinum/geom_vinum_move.c +++ b/sys/geom/vinum/geom_vinum_move.c @@ -115,13 +115,13 @@ gv_move_sd(struct gv_softc *sc, struct gv_sd *cursd, if ((gv_consumer_is_open(d->consumer) || gv_consumer_is_open(destination->consumer)) && - !(flags && GV_FLAG_F)) { + !(flags & GV_FLAG_F)) { G_VINUM_DEBUG(0, "consumers on current and destination drive " " still open"); return (GV_ERR_ISBUSY); } - if (!(flags && GV_FLAG_F)) { + if (!(flags & GV_FLAG_F)) { G_VINUM_DEBUG(1, "-f flag not passed; move would be " "destructive"); return (GV_ERR_INVFLAG); diff --git a/sys/geom/vinum/geom_vinum_rename.c b/sys/geom/vinum/geom_vinum_rename.c index 7764c8541aa..d4e76c21a92 100644 --- a/sys/geom/vinum/geom_vinum_rename.c +++ b/sys/geom/vinum/geom_vinum_rename.c @@ -173,7 +173,7 @@ gv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags) /* Fix up references and potentially rename subdisks. */ LIST_FOREACH(s, &p->subdisks, in_plex) { strlcpy(s->plex, p->name, sizeof(s->plex)); - if (flags && GV_FLAG_R) { + if (flags & GV_FLAG_R) { /* * Look for the two last dots in the string, and assume * that the old value was ok. @@ -243,7 +243,7 @@ gv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname, /* Fix up references and potentially rename plexes. */ LIST_FOREACH(p, &v->plexes, in_volume) { strlcpy(p->volume, v->name, sizeof(p->volume)); - if (flags && GV_FLAG_R) { + if (flags & GV_FLAG_R) { /* * Look for the last dot in the string, and assume that * the old value was ok. diff --git a/sys/geom/virstor/g_virstor.c b/sys/geom/virstor/g_virstor.c index efdba4ba3ff..38ce78283c8 100644 --- a/sys/geom/virstor/g_virstor.c +++ b/sys/geom/virstor/g_virstor.c @@ -316,8 +316,8 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp) g_topology_unlock(); return; } - if (strncmp(prov_name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - prov_name += strlen(_PATH_DEV); + if (strncmp(prov_name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + prov_name += sizeof(_PATH_DEV) - 1; pp = g_provider_by_name(prov_name); if (pp == NULL) { @@ -574,8 +574,8 @@ virstor_ctl_remove(struct gctl_req *req, struct g_class *cp) gctl_error(req, "Error fetching argument '%s'", param); return; } - if (strncmp(prov_name, _PATH_DEV, strlen(_PATH_DEV)) == 0) - prov_name += strlen(_PATH_DEV); + if (strncmp(prov_name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + prov_name += sizeof(_PATH_DEV) - 1; found = -1; for (j = 0; j < sc->n_components; j++) { diff --git a/sys/gnu/fs/reiserfs/reiserfs_mount.h b/sys/gnu/fs/reiserfs/reiserfs_mount.h index f47c97610fc..fbb0b50a0ec 100644 --- a/sys/gnu/fs/reiserfs/reiserfs_mount.h +++ b/sys/gnu/fs/reiserfs/reiserfs_mount.h @@ -39,7 +39,7 @@ struct reiserfs_mount { /* Arguments to mount ReiserFS filesystems. */ struct reiserfs_args { char *fspec; /* blocks special holding the fs to mount */ - struct export_args export; /* network export information */ + struct oexport_args export; /* network export information */ }; #endif /* !defined _GNU_REISERFS_REISERFS_MOUNT_H */ diff --git a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c index 6b4272e9660..1b5ce88eef9 100644 --- a/sys/gnu/fs/reiserfs/reiserfs_vfsops.c +++ b/sys/gnu/fs/reiserfs/reiserfs_vfsops.c @@ -52,14 +52,16 @@ static int reiserfs_cmount(struct mntarg *ma, void *data, int flags) { struct reiserfs_args args; + struct export_args exp; int error; error = copyin(data, &args, sizeof(args)); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); error = kernel_mount(ma, flags); diff --git a/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c index 49cfb5d51c1..e4e1e8d57a3 100644 --- a/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c +++ b/sys/gnu/fs/xfs/FreeBSD/xfs_freebsd_iget.c @@ -389,8 +389,8 @@ xfs_vn_allocate(xfs_mount_t *mp, xfs_inode_t *ip, struct xfs_vnode **vpp) return (error); } - VN_LOCK_AREC(vp); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + VN_LOCK_AREC(vp); error = insmntque(vp, XVFSTOMNT(XFS_MTOVFS(mp))); if (error != 0) { kmem_free(vdata, sizeof(*vdata)); diff --git a/sys/i386/acpica/Makefile b/sys/i386/acpica/Makefile index 48d65eaa1aa..87061d67247 100644 --- a/sys/i386/acpica/Makefile +++ b/sys/i386/acpica/Makefile @@ -9,7 +9,7 @@ DEPENDFILE= MAKESRCPATH= ${.CURDIR} CLEANFILES= acpi_wakecode.h acpi_wakecode.bin acpi_wakecode.o .endif -.if ${CC} == "icc" +.if ${CC:T:Micc} == "icc" CFLAGS+= -restrict NOSTDINC= -X .else diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index 76cb963f27a..85f4697a400 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -56,7 +56,6 @@ options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options KBD_INSTALL_CDEV # install a CDEV entry in /dev diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index b4f8ee80bc8..a68037bb2f6 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -751,6 +751,7 @@ device glxsb # AMD Geode LX Security Block # spic: Sony Programmable I/O controller (VAIO notebooks) # asmc: Apple System Management Controller # si: Specialix International SI/XIO or SX intelligent serial card driver +# tpm: Trusted Platform Module # Notes on APM # The flags takes the following meaning for apm0: @@ -789,6 +790,7 @@ hint.spic.0.at="isa" hint.spic.0.port="0x10a0" device asmc #device si +device tpm # # Laptop/Notebook options: diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s index 575b98dcc7a..13562fa6e99 100644 --- a/sys/i386/i386/exception.s +++ b/sys/i386/i386/exception.s @@ -108,6 +108,8 @@ IDTVEC(nmi) pushl $0; TRAP(T_NMI) IDTVEC(bpt) pushl $0; TRAP(T_BPTFLT) +IDTVEC(dtrace_ret) + pushl $0; TRAP(T_DTRACE_RET) IDTVEC(ofl) pushl $0; TRAP(T_OFLOW) IDTVEC(bnd) diff --git a/sys/i386/i386/identcpu.c b/sys/i386/i386/identcpu.c index 486824e72d9..010a29fa036 100644 --- a/sys/i386/i386/identcpu.c +++ b/sys/i386/i386/identcpu.c @@ -742,7 +742,7 @@ printcpuinfo(void) "\017xTPR" /* Send Task Priority Messages*/ "\020PDCM" /* Perf/Debug Capability MSR */ "\021" - "\022" + "\022PCID" /* Process-context Identifiers */ "\023DCA" /* Direct Cache Access */ "\024SSE4.1" "\025SSE4.2" diff --git a/sys/i386/i386/legacy.c b/sys/i386/i386/legacy.c index 39f3e229a1a..fe9b403efaa 100644 --- a/sys/i386/i386/legacy.c +++ b/sys/i386/i386/legacy.c @@ -65,7 +65,7 @@ struct legacy_device { static int legacy_probe(device_t); static int legacy_attach(device_t); static int legacy_print_child(device_t, device_t); -static device_t legacy_add_child(device_t bus, int order, const char *name, +static device_t legacy_add_child(device_t bus, u_int order, const char *name, int unit); static int legacy_read_ivar(device_t, device_t, int, uintptr_t *); static int legacy_write_ivar(device_t, device_t, int, uintptr_t); @@ -170,7 +170,7 @@ legacy_print_child(device_t bus, device_t child) } static device_t -legacy_add_child(device_t bus, int order, const char *name, int unit) +legacy_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct legacy_device *atdev; @@ -234,7 +234,7 @@ legacy_write_ivar(device_t dev, device_t child, int which, uintptr_t value) static void cpu_identify(driver_t *driver, device_t parent); static int cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result); -static device_t cpu_add_child(device_t bus, int order, const char *name, +static device_t cpu_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource_list *cpu_get_rlist(device_t dev, device_t child); @@ -298,7 +298,7 @@ cpu_identify(driver_t *driver, device_t parent) } static device_t -cpu_add_child(device_t bus, int order, const char *name, int unit) +cpu_add_child(device_t bus, u_int order, const char *name, int unit) { struct cpu_device *cd; device_t child; diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index 170aaf13999..107cbcf0ada 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -104,6 +104,9 @@ IdlePTD: .long 0 /* phys addr of kernel PTD */ IdlePDPT: .long 0 /* phys addr of kernel PDPT */ #endif + .globl KPTmap +KPTmap: .long 0 /* address of kernel page tables */ + .globl KPTphys KPTphys: .long 0 /* phys addr of kernel page tables */ @@ -715,6 +718,8 @@ no_kernend: /* Allocate Kernel Page Tables */ ALLOCPAGES(NKPT) movl %esi,R(KPTphys) + addl $(KERNBASE-(KPTDI<<(PDRSHIFT-PAGE_SHIFT+PTESHIFT))),%esi + movl %esi,R(KPTmap) /* Allocate Page Table Directory */ #ifdef PAE @@ -778,6 +783,11 @@ no_kernend: shrl $PAGE_SHIFT,%ecx fillkptphys($PG_RW) +/* Map page table pages. */ + movl R(KPTphys),%eax + movl $NKPT,%ecx + fillkptphys($PG_RW) + /* Map page directory. */ #ifdef PAE movl R(IdlePDPT), %eax diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 872d09b3609..5c0b7ff81a3 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include "opt_npx.h" #include "opt_perfmon.h" #include "opt_xbox.h" +#include "opt_kdtrace.h" #include #include @@ -1174,9 +1175,6 @@ cpu_est_clockrate(int cpu_id, uint64_t *rate) return (0); } - -void (*cpu_idle_hook)(void) = NULL; /* ACPI idle hook. */ - #ifdef XEN void @@ -1207,60 +1205,94 @@ cpu_halt(void) __asm__ ("hlt"); } -static void -cpu_idle_hlt(int busy) -{ - /* - * we must absolutely guarentee that hlt is the next instruction - * after sti or we introduce a timing window. - */ - disable_intr(); - if (sched_runnable()) - enable_intr(); - else - __asm __volatile("sti; hlt"); -} #endif +void (*cpu_idle_hook)(void) = NULL; /* ACPI idle hook. */ +static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ +static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ +TUNABLE_INT("machdep.idle_mwait", &idle_mwait); +SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, + 0, "Use MONITOR/MWAIT for short idle"); + +#define STATE_RUNNING 0x0 +#define STATE_MWAIT 0x1 +#define STATE_SLEEPING 0x2 + static void cpu_idle_acpi(int busy) { + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_SLEEPING; disable_intr(); - if (sched_runnable()) + if (sched_runnable()) enable_intr(); else if (cpu_idle_hook) cpu_idle_hook(); else __asm __volatile("sti; hlt"); + *state = STATE_RUNNING; } -static int cpu_ident_amdc1e = 0; +#ifndef XEN +static void +cpu_idle_hlt(int busy) +{ + int *state; -static int -cpu_probe_amdc1e(void) -{ -#ifdef DEV_APIC + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_SLEEPING; + /* + * We must absolutely guarentee that hlt is the next instruction + * after sti or we introduce a timing window. + */ + disable_intr(); + if (sched_runnable()) + enable_intr(); + else + __asm __volatile("sti; hlt"); + *state = STATE_RUNNING; +} +#endif + +/* + * MWAIT cpu power states. Lower 4 bits are sub-states. + */ +#define MWAIT_C0 0xf0 +#define MWAIT_C1 0x00 +#define MWAIT_C2 0x10 +#define MWAIT_C3 0x20 +#define MWAIT_C4 0x30 + +static void +cpu_idle_mwait(int busy) +{ + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_MWAIT; + if (!sched_runnable()) { + cpu_monitor(state, 0, 0); + if (*state == STATE_MWAIT) + cpu_mwait(0, MWAIT_C1); + } + *state = STATE_RUNNING; +} + +static void +cpu_idle_spin(int busy) +{ + int *state; int i; - /* - * Forget it, if we're not using local APIC timer. - */ - if (resource_disabled("apic", 0) || - (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0)) - return (0); - - /* - * Detect the presence of C1E capability mostly on latest - * dual-cores (or future) k8 family. - */ - if (cpu_vendor_id == CPU_VENDOR_AMD && - (cpu_id & 0x00000f00) == 0x00000f00 && - (cpu_id & 0x0fff0000) >= 0x00040000) { - cpu_ident_amdc1e = 1; - return (1); + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_RUNNING; + for (i = 0; i < 1000; i++) { + if (sched_runnable()) + return; + cpu_spinwait(); } -#endif - return (0); } /* @@ -1278,32 +1310,20 @@ cpu_probe_amdc1e(void) #define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT) static void -cpu_idle_amdc1e(int busy) +cpu_probe_amdc1e(void) { - disable_intr(); - if (sched_runnable()) - enable_intr(); - else { - uint64_t msr; - - msr = rdmsr(MSR_AMDK8_IPM); - if (msr & AMDK8_CMPHALT) - wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); - - if (cpu_idle_hook) - cpu_idle_hook(); - else - __asm __volatile("sti; hlt"); + /* + * Detect the presence of C1E capability mostly on latest + * dual-cores (or future) k8 family. + */ + if (cpu_vendor_id == CPU_VENDOR_AMD && + (cpu_id & 0x00000f00) == 0x00000f00 && + (cpu_id & 0x0fff0000) >= 0x00040000) { + cpu_ident_amdc1e = 1; } } -static void -cpu_idle_spin(int busy) -{ - return; -} - #ifdef XEN void (*cpu_idle_fn)(int) = cpu_idle_hlt; #else @@ -1313,79 +1333,72 @@ void (*cpu_idle_fn)(int) = cpu_idle_acpi; void cpu_idle(int busy) { + uint64_t msr; + + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", + busy, curcpu); #if defined(SMP) && !defined(XEN) if (mp_grab_cpu_hlt()) return; #endif - cpu_idle_fn(busy); -} - -/* - * mwait cpu power states. Lower 4 bits are sub-states. - */ -#define MWAIT_C0 0xf0 -#define MWAIT_C1 0x00 -#define MWAIT_C2 0x10 -#define MWAIT_C3 0x20 -#define MWAIT_C4 0x30 - -#define MWAIT_DISABLED 0x0 -#define MWAIT_WOKEN 0x1 -#define MWAIT_WAITING 0x2 - -static void -cpu_idle_mwait(int busy) -{ - int *mwait; - - mwait = (int *)PCPU_PTR(monitorbuf); - *mwait = MWAIT_WAITING; - if (sched_runnable()) - return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); -} - -static void -cpu_idle_mwait_hlt(int busy) -{ - int *mwait; - - mwait = (int *)PCPU_PTR(monitorbuf); - if (busy == 0) { - *mwait = MWAIT_DISABLED; - cpu_idle_hlt(busy); - return; + /* If we are busy - try to use fast methods. */ + if (busy) { + if ((cpu_feature2 & CPUID2_MON) && idle_mwait) { + cpu_idle_mwait(busy); + goto out; + } } - *mwait = MWAIT_WAITING; - if (sched_runnable()) - return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); + +#ifndef XEN + /* If we have time - switch timers into idle mode. */ + if (!busy) { + critical_enter(); + cpu_idleclock(); + } +#endif + + /* Apply AMD APIC timer C1E workaround. */ + if (cpu_ident_amdc1e +#ifndef XEN + && cpu_disable_deep_sleep +#endif + ) { + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + } + + /* Call main idle method. */ + cpu_idle_fn(busy); + +#ifndef XEN + /* Switch timers mack into active mode. */ + if (!busy) { + cpu_activeclock(); + critical_exit(); + } +#endif +out: + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", + busy, curcpu); } int cpu_idle_wakeup(int cpu) { struct pcpu *pcpu; - int *mwait; + int *state; - if (cpu_idle_fn == cpu_idle_spin) - return (1); - if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt) - return (0); pcpu = pcpu_find(cpu); - mwait = (int *)pcpu->pc_monitorbuf; + state = (int *)pcpu->pc_monitorbuf; /* * This doesn't need to be atomic since missing the race will * simply result in unnecessary IPIs. */ - if (cpu_idle_fn == cpu_idle_mwait_hlt && *mwait == MWAIT_DISABLED) + if (*state == STATE_SLEEPING) return (0); - *mwait = MWAIT_WOKEN; - + if (*state == STATE_MWAIT) + *state = STATE_RUNNING; return (1); } @@ -1398,8 +1411,6 @@ struct { } idle_tbl[] = { { cpu_idle_spin, "spin" }, { cpu_idle_mwait, "mwait" }, - { cpu_idle_mwait_hlt, "mwait_hlt" }, - { cpu_idle_amdc1e, "amdc1e" }, { cpu_idle_hlt, "hlt" }, { cpu_idle_acpi, "acpi" }, { NULL, NULL } @@ -1418,16 +1429,20 @@ idle_sysctl_available(SYSCTL_HANDLER_ARGS) if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; - if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 && - cpu_ident_amdc1e == 0) + if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && + cpu_idle_hook == NULL) continue; - p += sprintf(p, "%s, ", idle_tbl[i].id_name); + p += sprintf(p, "%s%s", p != avail ? ", " : "", + idle_tbl[i].id_name); } error = sysctl_handle_string(oidp, avail, 0, req); free(avail, M_TEMP); return (error); } +SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, idle_sysctl_available, "A", "list of available idle functions"); + static int idle_sysctl(SYSCTL_HANDLER_ARGS) { @@ -1451,8 +1466,8 @@ idle_sysctl(SYSCTL_HANDLER_ARGS) if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; - if (strcmp(idle_tbl[i].id_name, "amdc1e") == 0 && - cpu_ident_amdc1e == 0) + if (strcmp(idle_tbl[i].id_name, "acpi") == 0 && + cpu_idle_hook == NULL) continue; if (strcmp(idle_tbl[i].id_name, buf)) continue; @@ -1462,9 +1477,6 @@ idle_sysctl(SYSCTL_HANDLER_ARGS) return (EINVAL); } -SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, - 0, 0, idle_sysctl_available, "A", "list of available idle functions"); - SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, idle_sysctl, "A", "currently selected idle function"); @@ -1876,7 +1888,11 @@ extern inthand_t IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), - IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); + IDTVEC(xmm), +#ifdef KDTRACE_HOOKS + IDTVEC(dtrace_ret), +#endif + IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); #ifdef DDB /* @@ -1935,6 +1951,7 @@ sdtossd(sd, ssd) ssd->ssd_gran = sd->sd_gran; } +#ifndef XEN static int add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) { @@ -2014,78 +2031,13 @@ add_smap_entry(struct bios_smap *smap, vm_paddr_t *physmap, int *physmap_idxp) return (1); } -/* - * Populate the (physmap) array with base/bound pairs describing the - * available physical memory in the system, then test this memory and - * build the phys_avail array describing the actually-available memory. - * - * If we cannot accurately determine the physical memory map, then use - * value from the 0xE801 call, and failing that, the RTC. - * - * Total memory size may be set by the kernel environment variable - * hw.physmem or the compile-time define MAXMEM. - * - * XXX first should be vm_paddr_t. - */ static void -getmemsize(int first) +basemem_setup(void) { - int i, off, physmap_idx, pa_indx, da_indx; - int hasbrokenint12, has_smap; - u_long physmem_tunable; - u_int extmem; - struct vm86frame vmf; - struct vm86context vmc; - vm_paddr_t pa, physmap[PHYSMAP_SIZE]; + vm_paddr_t pa; pt_entry_t *pte; - struct bios_smap *smap, *smapbase, *smapend; - u_int32_t smapsize; - quad_t dcons_addr, dcons_size; - caddr_t kmdp; + int i; - has_smap = 0; -#ifdef XBOX - if (arch_i386_is_xbox) { - /* - * We queried the memory size before, so chop off 4MB for - * the framebuffer and inform the OS of this. - */ - physmap[0] = 0; - physmap[1] = (arch_i386_xbox_memsize * 1024 * 1024) - XBOX_FB_SIZE; - physmap_idx = 0; - goto physmap_done; - } -#endif -#if defined(XEN) - has_smap = 0; - Maxmem = xen_start_info->nr_pages - init_first; - physmem = Maxmem; - basemem = 0; - physmap[0] = init_first << PAGE_SHIFT; - physmap[1] = ptoa(Maxmem) - round_page(MSGBUF_SIZE); - physmap_idx = 0; - goto physmap_done; -#endif - hasbrokenint12 = 0; - TUNABLE_INT_FETCH("hw.hasbrokenint12", &hasbrokenint12); - bzero(&vmf, sizeof(vmf)); - bzero(physmap, sizeof(physmap)); - basemem = 0; - - /* - * Some newer BIOSes has broken INT 12H implementation which cause - * kernel panic immediately. In this case, we need to scan SMAP - * with INT 15:E820 first, then determine base memory size. - */ - if (hasbrokenint12) { - goto int15e820; - } - - /* - * Perform "base memory" related probes & setup - */ - vm86_intcall(0x12, &vmf); - basemem = vmf.vmf_ax; if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); @@ -2125,12 +2077,69 @@ getmemsize(int first) pte = (pt_entry_t *)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; +} +#endif + +/* + * Populate the (physmap) array with base/bound pairs describing the + * available physical memory in the system, then test this memory and + * build the phys_avail array describing the actually-available memory. + * + * If we cannot accurately determine the physical memory map, then use + * value from the 0xE801 call, and failing that, the RTC. + * + * Total memory size may be set by the kernel environment variable + * hw.physmem or the compile-time define MAXMEM. + * + * XXX first should be vm_paddr_t. + */ +static void +getmemsize(int first) +{ + int has_smap, off, physmap_idx, pa_indx, da_indx; + u_long physmem_tunable; + vm_paddr_t physmap[PHYSMAP_SIZE]; + pt_entry_t *pte; + quad_t dcons_addr, dcons_size; +#ifndef XEN + int hasbrokenint12, i; + u_int extmem; + struct vm86frame vmf; + struct vm86context vmc; + vm_paddr_t pa; + struct bios_smap *smap, *smapbase, *smapend; + u_int32_t smapsize; + caddr_t kmdp; +#endif + + has_smap = 0; +#if defined(XEN) + Maxmem = xen_start_info->nr_pages - init_first; + physmem = Maxmem; + basemem = 0; + physmap[0] = init_first << PAGE_SHIFT; + physmap[1] = ptoa(Maxmem) - round_page(MSGBUF_SIZE); + physmap_idx = 0; +#else +#ifdef XBOX + if (arch_i386_is_xbox) { + /* + * We queried the memory size before, so chop off 4MB for + * the framebuffer and inform the OS of this. + */ + physmap[0] = 0; + physmap[1] = (arch_i386_xbox_memsize * 1024 * 1024) - XBOX_FB_SIZE; + physmap_idx = 0; + goto physmap_done; + } +#endif + bzero(&vmf, sizeof(vmf)); + bzero(physmap, sizeof(physmap)); + basemem = 0; -int15e820: /* - * Fetch the memory map with INT 15:E820. First, check to see - * if the loader supplied it and use that if so. Otherwise, - * use vm86 to invoke the BIOS call directly. + * Check if the loader supplied an SMAP memory map. If so, + * use that and do not make any VM86 calls. */ physmap_idx = 0; smapbase = NULL; @@ -2141,9 +2150,10 @@ int15e820: smapbase = (struct bios_smap *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_SMAP); if (smapbase != NULL) { - /* subr_module.c says: + /* + * subr_module.c says: * "Consumer may safely assume that size value precedes data." - * ie: an int32_t immediately precedes smap. + * ie: an int32_t immediately precedes SMAP. */ smapsize = *((u_int32_t *)smapbase - 1); smapend = (struct bios_smap *)((uintptr_t)smapbase + smapsize); @@ -2152,33 +2162,50 @@ int15e820: for (smap = smapbase; smap < smapend; smap++) if (!add_smap_entry(smap, physmap, &physmap_idx)) break; - } else { - /* - * map page 1 R/W into the kernel page table so we can use it - * as a buffer. The kernel will unmap this page later. - */ - pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT); - vmc.npages = 0; - smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + - (1 << PAGE_SHIFT)); - vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); - - vmf.vmf_ebx = 0; - do { - vmf.vmf_eax = 0xE820; - vmf.vmf_edx = SMAP_SIG; - vmf.vmf_ecx = sizeof(struct bios_smap); - i = vm86_datacall(0x15, &vmf, &vmc); - if (i || vmf.vmf_eax != SMAP_SIG) - break; - has_smap = 1; - if (!add_smap_entry(smap, physmap, &physmap_idx)) - break; - } while (vmf.vmf_ebx != 0); + goto have_smap; } /* - * Perform "base memory" related probes & setup based on SMAP + * Some newer BIOSes have a broken INT 12H implementation + * which causes a kernel panic immediately. In this case, we + * need use the SMAP to determine the base memory size. + */ + hasbrokenint12 = 0; + TUNABLE_INT_FETCH("hw.hasbrokenint12", &hasbrokenint12); + if (hasbrokenint12 == 0) { + /* Use INT12 to determine base memory size. */ + vm86_intcall(0x12, &vmf); + basemem = vmf.vmf_ax; + basemem_setup(); + } + + /* + * Fetch the memory map with INT 15:E820. Map page 1 R/W into + * the kernel page table so we can use it as a buffer. The + * kernel will unmap this page later. + */ + pmap_kenter(KERNBASE + (1 << PAGE_SHIFT), 1 << PAGE_SHIFT); + vmc.npages = 0; + smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); + vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); + + vmf.vmf_ebx = 0; + do { + vmf.vmf_eax = 0xE820; + vmf.vmf_edx = SMAP_SIG; + vmf.vmf_ecx = sizeof(struct bios_smap); + i = vm86_datacall(0x15, &vmf, &vmc); + if (i || vmf.vmf_eax != SMAP_SIG) + break; + has_smap = 1; + if (!add_smap_entry(smap, physmap, &physmap_idx)) + break; + } while (vmf.vmf_ebx != 0); + +have_smap: + /* + * If we didn't fetch the "base memory" size from INT12, + * figure it out from the SMAP (or just guess). */ if (basemem == 0) { for (i = 0; i <= physmap_idx; i += 2) { @@ -2188,49 +2215,39 @@ int15e820: } } - /* - * XXX this function is horribly organized and has to the same - * things that it does above here. - */ + /* XXX: If we couldn't find basemem from SMAP, just guess. */ if (basemem == 0) basemem = 640; - if (basemem > 640) { - printf( - "Preposterous BIOS basemem of %uK, truncating to 640K\n", - basemem); - basemem = 640; - } - - /* - * Let vm86 scribble on pages between basemem and - * ISA_HOLE_START, as above. - */ - for (pa = trunc_page(basemem * 1024); - pa < ISA_HOLE_START; pa += PAGE_SIZE) - pmap_kenter(KERNBASE + pa, pa); - pte = (pt_entry_t *)vm86paddr; - for (i = basemem / 4; i < 160; i++) - pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; + basemem_setup(); } if (physmap[1] != 0) goto physmap_done; /* - * If we failed above, try memory map with INT 15:E801 + * If we failed to find an SMAP, figure out the extended + * memory size. We will then build a simple memory map with + * two segments, one for "base memory" and the second for + * "extended memory". Note that "extended memory" starts at a + * physical address of 1MB and that both basemem and extmem + * are in units of 1KB. + * + * First, try to fetch the extended memory size via INT 15:E801. */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { + /* + * If INT15:E801 fails, this is our last ditch effort + * to determine the extended memory size. Currently + * we prefer the RTC value over INT15:88. + */ #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; -#elif !defined(XEN) - /* - * Prefer the RTC value for extended memory. - */ +#else extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif } @@ -2255,6 +2272,7 @@ int15e820: physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024; physmap_done: +#endif /* * Now, physmap contains a map of physical memory. */ @@ -2690,8 +2708,7 @@ init386(first) thread0.td_pcb->pcb_fsd = PCPU_GET(fsgs_gdt)[0]; thread0.td_pcb->pcb_gsd = PCPU_GET(fsgs_gdt)[1]; - if (cpu_probe_amdc1e()) - cpu_idle_fn = cpu_idle_amdc1e; + cpu_probe_amdc1e(); } #else @@ -2825,6 +2842,10 @@ init386(first) GSEL(GCODE_SEL, SEL_KPL)); setidt(IDT_SYSCALL, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); +#ifdef KDTRACE_HOOKS + setidt(IDT_DTRACE_RET, &IDTVEC(dtrace_ret), SDT_SYS386TGT, SEL_UPL, + GSEL(GCODE_SEL, SEL_KPL)); +#endif r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (int) idt; @@ -2961,8 +2982,7 @@ init386(first) thread0.td_pcb->pcb_ext = 0; thread0.td_frame = &proc0_tf; - if (cpu_probe_amdc1e()) - cpu_idle_fn = cpu_idle_amdc1e; + cpu_probe_amdc1e(); } #endif diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index ddbb6318cb8..c69f6f974d0 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -167,14 +167,12 @@ u_long *ipi_invlcache_counts[MAXCPU]; u_long *ipi_rendezvous_counts[MAXCPU]; u_long *ipi_lazypmap_counts[MAXCPU]; static u_long *ipi_hardclock_counts[MAXCPU]; -static u_long *ipi_statclock_counts[MAXCPU]; #endif /* * Local data and functions. */ -static cpumask_t logical_cpus; static volatile cpumask_t ipi_nmi_pending; /* used to hold the AP's until we are ready to release them */ @@ -200,8 +198,8 @@ int apic_cpuids[MAX_APIC_ID + 1]; static volatile u_int cpu_ipi_pending[MAXCPU]; static u_int boot_address; -static int cpu_logical; -static int cpu_cores; +static int cpu_logical; /* logical cpus per core */ +static int cpu_cores; /* cores per package */ static void assign_cpu_ids(void); static void install_ap_tramp(void); @@ -210,8 +208,8 @@ static int start_all_aps(void); static int start_ap(int apic_id); static void release_aps(void *dummy); -static cpumask_t hlt_logical_cpus; -static cpumask_t hyperthreading_cpus; +static int hlt_logical_cpus; +static u_int hyperthreading_cpus; /* logical cpus sharing L1 cache */ static cpumask_t hyperthreading_cpus_mask; static int hyperthreading_allowed = 1; static struct sysctl_ctx_list logical_cpu_clist; @@ -223,25 +221,106 @@ mem_range_AP_init(void) mem_range_softc.mr_op->initAP(&mem_range_softc); } +static void +topo_probe_amd(void) +{ + + /* AMD processors do not support HTT. */ + cpu_cores = (amd_feature2 & AMDID2_CMP) != 0 ? + (cpu_procinfo2 & AMDID_CMP_CORES) + 1 : 1; + cpu_logical = 1; +} + +/* + * Round up to the next power of two, if necessary, and then + * take log2. + * Returns -1 if argument is zero. + */ +static __inline int +mask_width(u_int x) +{ + + return (fls(x << (1 - powerof2(x))) - 1); +} + +static void +topo_probe_0x4(void) +{ + u_int p[4]; + int pkg_id_bits; + int core_id_bits; + int max_cores; + int max_logical; + int id; + + /* Both zero and one here mean one logical processor per package. */ + max_logical = (cpu_feature & CPUID_HTT) != 0 ? + (cpu_procinfo & CPUID_HTT_CORES) >> 16 : 1; + if (max_logical <= 1) + return; + + /* + * Because of uniformity assumption we examine only + * those logical processors that belong to the same + * package as BSP. Further, we count number of + * logical processors that belong to the same core + * as BSP thus deducing number of threads per core. + */ + cpuid_count(0x04, 0, p); + max_cores = ((p[0] >> 26) & 0x3f) + 1; + core_id_bits = mask_width(max_logical/max_cores); + if (core_id_bits < 0) + return; + pkg_id_bits = core_id_bits + mask_width(max_cores); + + for (id = 0; id <= MAX_APIC_ID; id++) { + /* Check logical CPU availability. */ + if (!cpu_info[id].cpu_present || cpu_info[id].cpu_disabled) + continue; + /* Check if logical CPU has the same package ID. */ + if ((id >> pkg_id_bits) != (boot_cpu_id >> pkg_id_bits)) + continue; + cpu_cores++; + /* Check if logical CPU has the same package and core IDs. */ + if ((id >> core_id_bits) == (boot_cpu_id >> core_id_bits)) + cpu_logical++; + } + + cpu_cores /= cpu_logical; + hyperthreading_cpus = cpu_logical; +} + static void topo_probe_0xb(void) { - int logical; - int p[4]; + u_int p[4]; int bits; - int type; int cnt; int i; + int logical; + int type; int x; - /* We only support two levels for now. */ + /* We only support three levels for now. */ for (i = 0; i < 3; i++) { - cpuid_count(0x0B, i, p); + cpuid_count(0x0b, i, p); + + /* Fall back if CPU leaf 11 doesn't really exist. */ + if (i == 0 && p[1] == 0) { + topo_probe_0x4(); + return; + } + bits = p[0] & 0x1f; logical = p[1] &= 0xffff; type = (p[2] >> 8) & 0xff; if (type == 0 || logical == 0) break; + /* + * Because of uniformity assumption we examine only + * those logical processors that belong to the same + * package as BSP. + */ for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) { if (!cpu_info[x].cpu_present || cpu_info[x].cpu_disabled) @@ -259,76 +338,16 @@ topo_probe_0xb(void) cpu_cores /= cpu_logical; } -static void -topo_probe_0x4(void) -{ - u_int threads_per_cache, p[4]; - u_int htt, cmp; - int i; - - htt = cmp = 1; - /* - * If this CPU supports HTT or CMP then mention the - * number of physical/logical cores it contains. - */ - if (cpu_feature & CPUID_HTT) - htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - if (cpu_vendor_id == CPU_VENDOR_AMD && (amd_feature2 & AMDID2_CMP)) - cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; - else if (cpu_vendor_id == CPU_VENDOR_INTEL && (cpu_high >= 4)) { - cpuid_count(4, 0, p); - if ((p[0] & 0x1f) != 0) - cmp = ((p[0] >> 26) & 0x3f) + 1; - } - cpu_cores = cmp; - cpu_logical = htt / cmp; - - /* Setup the initial logical CPUs info. */ - if (cpu_feature & CPUID_HTT) - logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - - /* - * Work out if hyperthreading is *really* enabled. This - * is made really ugly by the fact that processors lie: Dual - * core processors claim to be hyperthreaded even when they're - * not, presumably because they want to be treated the same - * way as HTT with respect to per-cpu software licensing. - * At the time of writing (May 12, 2005) the only hyperthreaded - * cpus are from Intel, and Intel's dual-core processors can be - * identified via the "deterministic cache parameters" cpuid - * calls. - */ - /* - * First determine if this is an Intel processor which claims - * to have hyperthreading support. - */ - if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) { - /* - * If the "deterministic cache parameters" cpuid calls - * are available, use them. - */ - if (cpu_high >= 4) { - /* Ask the processor about the L1 cache. */ - for (i = 0; i < 1; i++) { - cpuid_count(4, i, p); - threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1; - if (hyperthreading_cpus < threads_per_cache) - hyperthreading_cpus = threads_per_cache; - if ((p[0] & 0x1f) == 0) - break; - } - } - - /* - * If the deterministic cache parameters are not - * available, or if no caches were reported to exist, - * just accept what the HTT flag indicated. - */ - if (hyperthreading_cpus == 0) - hyperthreading_cpus = logical_cpus; - } -} - +/* + * Both topology discovery code and code that consumes topology + * information assume top-down uniformity of the topology. + * That is, all physical packages must be identical and each + * core in a package must have the same number of threads. + * Topology information is queried only on BSP, on which this + * code runs and for which it can query CPUID information. + * Then topology is extrapolated on all packages using the + * uniformity assumption. + */ static void topo_probe(void) { @@ -337,13 +356,31 @@ topo_probe(void) if (cpu_topo_probed) return; - logical_cpus = logical_cpus_mask = 0; - if (cpu_high >= 0xb) - topo_probe_0xb(); - else if (cpu_high) - topo_probe_0x4(); + logical_cpus_mask = 0; + if (cpu_vendor_id == CPU_VENDOR_AMD) + topo_probe_amd(); + else if (cpu_vendor_id == CPU_VENDOR_INTEL) { + /* + * See Intel(R) 64 Architecture Processor + * Topology Enumeration article for details. + * + * Note that 0x1 <= cpu_high < 4 case should be + * compatible with topo_probe_0x4() logic when + * CPUID.1:EBX[23:16] > 0 (cpu_cores will be 1) + * or it should trigger the fallback otherwise. + */ + if (cpu_high >= 0xb) + topo_probe_0xb(); + else if (cpu_high >= 0x1) + topo_probe_0x4(); + } + + /* + * Fallback: assume each logical CPU is in separate + * physical package. That is, no multi-core, no SMT. + */ if (cpu_cores == 0) - cpu_cores = mp_ncpus > 0 ? mp_ncpus : 1; + cpu_cores = 1; if (cpu_logical == 0) cpu_logical = 1; cpu_topo_probed = 1; @@ -707,7 +744,8 @@ init_secondary(void) printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid)); /* Determine if we are a logical CPU. */ - if (logical_cpus > 1 && PCPU_GET(apic_id) % logical_cpus != 0) + /* XXX Calculation depends on cpu_logical being a power of 2, e.g. 2 */ + if (cpu_logical > 1 && PCPU_GET(apic_id) % cpu_logical != 0) logical_cpus_mask |= PCPU_GET(cpumask); /* Determine if we are a hyperthread. */ @@ -1284,16 +1322,22 @@ smp_masked_invlpg_range(cpumask_t mask, vm_offset_t addr1, vm_offset_t addr2) void ipi_bitmap_handler(struct trapframe frame) { + struct trapframe *oldframe; + struct thread *td; int cpu = PCPU_GET(cpuid); u_int ipi_bitmap; + critical_enter(); + td = curthread; + td->td_intr_nesting_level++; + oldframe = td->td_intr_frame; + td->td_intr_frame = &frame; ipi_bitmap = atomic_readandclear_int(&cpu_ipi_pending[cpu]); - if (ipi_bitmap & (1 << IPI_PREEMPT)) { #ifdef COUNT_IPIS (*ipi_preempt_counts[cpu])++; #endif - sched_preempt(curthread); + sched_preempt(td); } if (ipi_bitmap & (1 << IPI_AST)) { #ifdef COUNT_IPIS @@ -1305,14 +1349,11 @@ ipi_bitmap_handler(struct trapframe frame) #ifdef COUNT_IPIS (*ipi_hardclock_counts[cpu])++; #endif - hardclockintr(&frame); - } - if (ipi_bitmap & (1 << IPI_STATCLOCK)) { -#ifdef COUNT_IPIS - (*ipi_statclock_counts[cpu])++; -#endif - statclockintr(&frame); + hardclockintr(); } + td->td_intr_frame = oldframe; + td->td_intr_nesting_level--; + critical_exit(); } /* @@ -1627,8 +1668,6 @@ mp_ipi_intrcnt(void *dummy) intrcnt_add(buf, &ipi_lazypmap_counts[i]); snprintf(buf, sizeof(buf), "cpu%d:hardclock", i); intrcnt_add(buf, &ipi_hardclock_counts[i]); - snprintf(buf, sizeof(buf), "cpu%d:statclock", i); - intrcnt_add(buf, &ipi_statclock_counts[i]); } } SYSINIT(mp_ipi_intrcnt, SI_SUB_INTR, SI_ORDER_MIDDLE, mp_ipi_intrcnt, NULL); diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c index 04dd464ce77..ec87528934d 100644 --- a/sys/i386/i386/nexus.c +++ b/sys/i386/i386/nexus.c @@ -87,7 +87,7 @@ static int nexus_probe(device_t); static int nexus_attach(device_t); static int nexus_print_all_resources(device_t dev); static int nexus_print_child(device_t, device_t); -static device_t nexus_add_child(device_t bus, int order, const char *name, +static device_t nexus_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -305,7 +305,7 @@ nexus_print_child(device_t bus, device_t child) } static device_t -nexus_add_child(device_t bus, int order, const char *name, int unit) +nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index f8c52a0e0b3..80444e60024 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -247,7 +247,7 @@ struct sysmaps { caddr_t CADDR2; }; static struct sysmaps sysmaps_pcpu[MAXCPU]; -pt_entry_t *CMAP1 = 0, *KPTmap; +pt_entry_t *CMAP1 = 0; static pt_entry_t *CMAP3; static pd_entry_t *KPTD; caddr_t CADDR1 = 0, ptvmmap = 0; @@ -362,12 +362,11 @@ pmap_bootstrap(vm_paddr_t firstaddr) int i; /* - * XXX The calculation of virtual_avail is wrong. It's NKPT*PAGE_SIZE too - * large. It should instead be correctly calculated in locore.s and - * not based on 'first' (which is a physical address, not a virtual - * address, for the start of unused physical memory). The kernel - * page tables are NOT double mapped and thus should not be included - * in this calculation. + * Initialize the first available kernel virtual address. However, + * using "firstaddr" may waste a few pages of the kernel virtual + * address space, because locore may not have mapped every physical + * page that it allocated. Preferably, locore would provide a first + * unused virtual address in addition to "firstaddr". */ virtual_avail = (vm_offset_t) KERNBASE + firstaddr; @@ -437,6 +436,10 @@ pmap_bootstrap(vm_paddr_t firstaddr) /* * KPTmap is used by pmap_kextract(). + * + * KPTmap is first initialized by locore. However, that initial + * KPTmap can only support NKPT page table pages. Here, a larger + * KPTmap is created that can support KVA_PAGES page table pages. */ SYSMAP(pt_entry_t *, KPTD, KPTmap, KVA_PAGES) @@ -518,7 +521,8 @@ pmap_init_pat(void) if (sysenv != NULL) { if (strncmp(sysenv, "MacBook5,1", 10) == 0 || strncmp(sysenv, "MacBookPro5,5", 13) == 0 || - strncmp(sysenv, "Macmini3,1", 10) == 0) + strncmp(sysenv, "Macmini3,1", 10) == 0 || + strncmp(sysenv, "iMac9,1", 7) == 0) pat_works = 0; freeenv(sysenv); } @@ -1385,6 +1389,8 @@ retry: /* * Add a wired page to the kva. * Note: not SMP coherent. + * + * This function may be used before pmap_bootstrap() is called. */ PMAP_INLINE void pmap_kenter(vm_offset_t va, vm_paddr_t pa) @@ -1407,6 +1413,8 @@ pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int mode) /* * Remove a page from the kernel pagetables. * Note: not SMP coherent. + * + * This function may be used before pmap_bootstrap() is called. */ PMAP_INLINE void pmap_kremove(vm_offset_t va) diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s index 4927b50e6f5..29f1f407fbe 100644 --- a/sys/i386/i386/support.s +++ b/sys/i386/i386/support.s @@ -423,7 +423,6 @@ ENTRY(casuword) */ movl PCPU(CURPCB),%ecx - movl $fusufault,PCB_ONFAULT(%ecx) movl $0,PCB_ONFAULT(%ecx) ret END(casuword32) diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 9c93319369f..7b7bdc498ca 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include "opt_isa.h" #include "opt_kdb.h" #include "opt_kdtrace.h" -#include "opt_ktrace.h" #include "opt_npx.h" #include "opt_trap.h" @@ -72,9 +71,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#endif #ifdef HWPMC_HOOKS #include #endif @@ -122,6 +118,13 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func; * implementation opaque. */ systrace_probe_func_t systrace_probe_func; + +/* + * These hooks are necessary for the pid, usdt and fasttrap providers. + */ +dtrace_fasttrap_probe_ptr_t dtrace_fasttrap_probe_ptr; +dtrace_pid_probe_ptr_t dtrace_pid_probe_ptr; +dtrace_return_probe_ptr_t dtrace_return_probe_ptr; #endif extern void trap(struct trapframe *frame); @@ -264,6 +267,38 @@ trap(struct trapframe *frame) dtrace_trap_func != NULL) if ((*dtrace_trap_func)(frame, type)) goto out; + if (type == T_DTRACE_PROBE || type == T_DTRACE_RET || + type == T_BPTFLT) { + struct reg regs; + + regs.r_fs = frame->tf_fs; + regs.r_es = frame->tf_es; + regs.r_ds = frame->tf_ds; + regs.r_edi = frame->tf_edi; + regs.r_esi = frame->tf_esi; + regs.r_ebp = frame->tf_ebp; + regs.r_ebx = frame->tf_ebx; + regs.r_edx = frame->tf_edx; + regs.r_ecx = frame->tf_ecx; + regs.r_eax = frame->tf_eax; + regs.r_eip = frame->tf_eip; + regs.r_cs = frame->tf_cs; + regs.r_eflags = frame->tf_eflags; + regs.r_esp = frame->tf_esp; + regs.r_ss = frame->tf_ss; + if (type == T_DTRACE_PROBE && + dtrace_fasttrap_probe_ptr != NULL && + dtrace_fasttrap_probe_ptr(®s) == 0) + goto out; + if (type == T_BPTFLT && + dtrace_pid_probe_ptr != NULL && + dtrace_pid_probe_ptr(®s) == 0) + goto out; + if (type == T_DTRACE_RET && + dtrace_return_probe_ptr != NULL && + dtrace_return_probe_ptr(®s) == 0) + goto out; + } #endif if ((frame->tf_eflags & PSL_I) == 0) { diff --git a/sys/i386/ibcs2/ibcs2_sysvec.c b/sys/i386/ibcs2/ibcs2_sysvec.c index 71d48a3dbc0..d69a24464f8 100644 --- a/sys/i386/ibcs2/ibcs2_sysvec.c +++ b/sys/i386/ibcs2/ibcs2_sysvec.c @@ -134,4 +134,4 @@ static moduledata_t ibcs2_mod = { ibcs2_modevent, 0 }; -DECLARE_MODULE(ibcs2, ibcs2_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +DECLARE_MODULE_TIED(ibcs2, ibcs2_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h index cada0173f75..ff1f6577272 100644 --- a/sys/i386/include/apicvar.h +++ b/sys/i386/include/apicvar.h @@ -124,8 +124,7 @@ #define IPI_AST 0 /* Generate software trap. */ #define IPI_PREEMPT 1 #define IPI_HARDCLOCK 2 -#define IPI_STATCLOCK 3 -#define IPI_BITMAP_LAST IPI_STATCLOCK +#define IPI_BITMAP_LAST IPI_HARDCLOCK #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST) #define IPI_STOP (APIC_IPI_INTS + 7) /* Stop CPU until restarted. */ @@ -152,8 +151,7 @@ #define IPI_AST 0 /* Generate software trap. */ #define IPI_PREEMPT 1 #define IPI_HARDCLOCK 2 -#define IPI_STATCLOCK 3 -#define IPI_BITMAP_LAST IPI_STATCLOCK +#define IPI_BITMAP_LAST IPI_HARDCLOCK #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST) #define IPI_STOP (APIC_IPI_INTS + 7) /* Stop CPU until restarted. */ diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h index 2de6f448c9a..3c7251f4024 100644 --- a/sys/i386/include/cpufunc.h +++ b/sys/i386/include/cpufunc.h @@ -444,11 +444,11 @@ invlpg(u_int addr) #endif } -static __inline u_int +static __inline u_short rfs(void) { - u_int sel; - __asm __volatile("mov %%fs,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%fs,%0" : "=rm" (sel)); return (sel); } @@ -460,11 +460,11 @@ rgdt(void) return (gdtr); } -static __inline u_int +static __inline u_short rgs(void) { - u_int sel; - __asm __volatile("mov %%gs,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%gs,%0" : "=rm" (sel)); return (sel); } @@ -484,11 +484,11 @@ rldt(void) return (ldtr); } -static __inline u_int +static __inline u_short rss(void) { - u_int sel; - __asm __volatile("mov %%ss,%0" : "=rm" (sel)); + u_short sel; + __asm __volatile("movw %%ss,%0" : "=rm" (sel)); return (sel); } @@ -501,15 +501,15 @@ rtr(void) } static __inline void -load_fs(u_int sel) +load_fs(u_short sel) { - __asm __volatile("mov %0,%%fs" : : "rm" (sel)); + __asm __volatile("movw %0,%%fs" : : "rm" (sel)); } static __inline void -load_gs(u_int sel) +load_gs(u_short sel) { - __asm __volatile("mov %0,%%gs" : : "rm" (sel)); + __asm __volatile("movw %0,%%gs" : : "rm" (sel)); } static __inline void @@ -706,8 +706,8 @@ void load_dr4(u_int dr4); void load_dr5(u_int dr5); void load_dr6(u_int dr6); void load_dr7(u_int dr7); -void load_fs(u_int sel); -void load_gs(u_int sel); +void load_fs(u_short sel); +void load_gs(u_short sel); void ltr(u_short sel); void outb(u_int port, u_char data); void outl(u_int port, u_int data); diff --git a/sys/i386/include/elf.h b/sys/i386/include/elf.h index 37ee279c167..6490f2af631 100644 --- a/sys/i386/include/elf.h +++ b/sys/i386/include/elf.h @@ -90,8 +90,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP. */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ /* * Relocation types. diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h index 440735be430..e62e9896a63 100644 --- a/sys/i386/include/pmap.h +++ b/sys/i386/include/pmap.h @@ -191,12 +191,21 @@ extern pdpt_entry_t *IdlePDPT; extern pd_entry_t *IdlePTD; /* physical address of "Idle" state directory */ /* - * virtual address to page table entry and - * to physical address. - * Note: these work recursively, thus vtopte of a pte will give - * the corresponding pde that in turn maps it. + * Translate a virtual address to the kernel virtual address of its page table + * entry (PTE). This can be used recursively. If the address of a PTE as + * previously returned by this macro is itself given as the argument, then the + * address of the page directory entry (PDE) that maps the PTE will be + * returned. + * + * This macro may be used before pmap_bootstrap() is called. */ #define vtopte(va) (PTmap + i386_btop(va)) + +/* + * Translate a virtual address to its physical address. + * + * This macro may be used before pmap_bootstrap() is called. + */ #define vtophys(va) pmap_kextract((vm_offset_t)(va)) #ifdef XEN @@ -272,14 +281,18 @@ pte_load_store_ma(pt_entry_t *ptep, pt_entry_t v) * table pages, and not user page table pages, and (2) it provides access to * a kernel page table page after the corresponding virtual addresses have * been promoted to a 2/4MB page mapping. + * + * KPTmap is first initialized by locore to support just NPKT page table + * pages. Later, it is reinitialized by pmap_bootstrap() to allow for + * expansion of the kernel page table. */ extern pt_entry_t *KPTmap; /* - * Routine: pmap_kextract - * Function: - * Extract the physical page address associated - * kernel virtual address. + * Extract from the kernel page table the physical address that is mapped by + * the given virtual address "va". + * + * This function may be used before pmap_bootstrap() is called. */ static __inline vm_paddr_t pmap_kextract(vm_offset_t va) @@ -486,6 +499,11 @@ extern vm_offset_t virtual_end; #define pmap_page_get_memattr(m) ((vm_memattr_t)(m)->md.pat_mode) #define pmap_unmapbios(va, sz) pmap_unmapdev((va), (sz)) +/* + * Only the following functions or macros may be used before pmap_bootstrap() + * is called: pmap_kenter(), pmap_kextract(), pmap_kremove(), vtophys(), and + * vtopte(). + */ void pmap_bootstrap(vm_paddr_t); int pmap_cache_bits(int mode, boolean_t is_pde); int pmap_change_attr(vm_offset_t, vm_size_t, int); diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h index 0b12f622c31..deeaf76ccbc 100644 --- a/sys/i386/include/segments.h +++ b/sys/i386/include/segments.h @@ -207,6 +207,7 @@ struct region_descriptor { #define IDT_XF 19 /* #XF: SIMD Floating-Point Exception */ #define IDT_IO_INTS NRSVIDT /* Base of IDT entries for I/O interrupts. */ #define IDT_SYSCALL 0x80 /* System Call Interrupt Vector */ +#define IDT_DTRACE_RET 0x92 /* DTrace pid provider Interrupt Vector */ /* * Entries in the Global Descriptor Table (GDT) diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h index 3dd71385f88..823f2ec31f3 100644 --- a/sys/i386/include/specialreg.h +++ b/sys/i386/include/specialreg.h @@ -123,6 +123,7 @@ #define CPUID2_CX16 0x00002000 #define CPUID2_XTPR 0x00004000 #define CPUID2_PDCM 0x00008000 +#define CPUID2_PCID 0x00020000 #define CPUID2_DCA 0x00040000 #define CPUID2_SSE41 0x00080000 #define CPUID2_SSE42 0x00100000 diff --git a/sys/i386/include/trap.h b/sys/i386/include/trap.h index f0176b2c97e..d8e36b5aaf3 100644 --- a/sys/i386/include/trap.h +++ b/sys/i386/include/trap.h @@ -62,6 +62,8 @@ #define T_MCHK 28 /* machine check trap */ #define T_XMMFLT 29 /* SIMD floating-point exception */ #define T_RESERVED 30 /* reserved (unknown) */ +#define T_DTRACE_RET 31 /* DTrace pid return */ +#define T_DTRACE_PROBE 32 /* DTrace fasttrap probe */ /* XXX most of the following codes aren't used, but could be. */ diff --git a/sys/i386/include/vm86.h b/sys/i386/include/vm86.h index b574e58e23e..e33d72008f2 100644 --- a/sys/i386/include/vm86.h +++ b/sys/i386/include/vm86.h @@ -100,7 +100,7 @@ struct vm86frame { #define vmf_eflags eflags.r_ex }; -#define VM86_PMAPSIZE 8 +#define VM86_PMAPSIZE 24 #define VMAP_MALLOC 1 /* page was malloced by us */ struct vm86context { diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 56582119e77..61e5ccef95a 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -1179,4 +1179,4 @@ static moduledata_t linux_elf_mod = { 0 }; -DECLARE_MODULE(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); +DECLARE_MODULE_TIED(linuxelf, linux_elf_mod, SI_SUB_EXEC, SI_ORDER_ANY); diff --git a/sys/i386/xen/xen_machdep.c b/sys/i386/xen/xen_machdep.c index 060fad5e72a..542f4df0931 100644 --- a/sys/i386/xen/xen_machdep.c +++ b/sys/i386/xen/xen_machdep.c @@ -722,7 +722,9 @@ char *bootmem_start, *bootmem_current, *bootmem_end; pteinfo_t *pteinfo_list; void initvalues(start_info_t *startinfo); -struct ringbuf_head *xen_store; /* XXX move me */ +struct xenstore_domain_interface; +extern struct xenstore_domain_interface *xen_store; + char *console_page; void * @@ -1082,7 +1084,7 @@ initvalues(start_info_t *startinfo) HYPERVISOR_shared_info = (shared_info_t *)cur_space; cur_space += PAGE_SIZE; - xen_store = (struct ringbuf_head *)cur_space; + xen_store = (struct xenstore_domain_interface *)cur_space; cur_space += PAGE_SIZE; console_page = (char *)cur_space; diff --git a/sys/ia64/ia64/nexus.c b/sys/ia64/ia64/nexus.c index 9885b747aa2..43d06323b31 100644 --- a/sys/ia64/ia64/nexus.c +++ b/sys/ia64/ia64/nexus.c @@ -82,7 +82,7 @@ static struct rman irq_rman, port_rman, mem_rman; static int nexus_probe(device_t); static int nexus_attach(device_t); static int nexus_print_child(device_t, device_t); -static device_t nexus_add_child(device_t bus, int order, const char *name, +static device_t nexus_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource *nexus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -220,7 +220,7 @@ nexus_print_child(device_t bus, device_t child) } static device_t -nexus_add_child(device_t bus, int order, const char *name, int unit) +nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c index f6db8c943ce..60b00c4988e 100644 --- a/sys/ia64/ia64/trap.c +++ b/sys/ia64/ia64/trap.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" -#include "opt_ktrace.h" #include #include @@ -67,11 +66,6 @@ __FBSDID("$FreeBSD$"); #include #endif -#ifdef KTRACE -#include -#include -#endif - #include #include diff --git a/sys/ia64/include/_stdint.h b/sys/ia64/include/_stdint.h index 1aed3e3b4ef..2e8552bf7d3 100644 --- a/sys/ia64/include/_stdint.h +++ b/sys/ia64/include/_stdint.h @@ -14,13 +14,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED diff --git a/sys/ia64/include/bus.h b/sys/ia64/include/bus.h index bad4f85ac15..966a75d349e 100644 --- a/sys/ia64/include/bus.h +++ b/sys/ia64/include/bus.h @@ -42,13 +42,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED diff --git a/sys/ia64/include/elf.h b/sys/ia64/include/elf.h index 27182dbcae9..ab7706bb299 100644 --- a/sys/ia64/include/elf.h +++ b/sys/ia64/include/elf.h @@ -89,8 +89,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ /* * Values for e_flags. diff --git a/sys/isa/isa_common.c b/sys/isa/isa_common.c index bcf77299244..1d1a13af647 100644 --- a/sys/isa/isa_common.c +++ b/sys/isa/isa_common.c @@ -597,7 +597,7 @@ isa_probe_children(device_t dev) * Add a new child with default ivars. */ static device_t -isa_add_child(device_t dev, int order, const char *name, int unit) +isa_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct isa_device *idev; diff --git a/sys/kern/Makefile b/sys/kern/Makefile index 07c2d570fc0..ab05c8abc70 100644 --- a/sys/kern/Makefile +++ b/sys/kern/Makefile @@ -1,12 +1,10 @@ # @(#)Makefile 8.2 (Berkeley) 3/21/94 # $FreeBSD$ -# Makefile for kernel tags files, init_sysent, etc. - -ARCH= i386 # luna68k news3400 pmax sparc tahoe vax +# Makefile for init_sysent all: - @echo "make tags, make links or make sysent only" + @echo "make sysent only" sysent: init_sysent.c syscalls.c ../sys/syscall.h ../sys/syscall.mk \ ../sys/sysproto.h @@ -20,39 +18,3 @@ init_sysent.c syscalls.c systrace_args.c ../sys/syscall.h \ -mv -f ../sys/syscall.mk ../sys/syscall.mk.bak -mv -f ../sys/sysproto.h ../sys/sysproto.h.bak sh makesyscalls.sh syscalls.master - -# Kernel tags: -# Tags files are built in the top-level directory for each architecture, -# with a makefile listing the architecture-dependent files, etc. The list -# of common files is in ./Make.tags.inc. Links to the correct tags file -# are placed in each source directory. We need to have links to tags files -# from the generic directories that are relative to the machine type, even -# via remote mounts; therefore we use symlinks to $SYSTAGS, which points at -# ${SYSDIR}/${MACHINE_ARCH}/tags. - -SYSTAGS=/var/db/sys_tags -SYSDIR=/sys - -# Directories in which to place tags links (other than machine-dependent) -DGEN= conf \ - dev dev/scsi \ - fs fs/deadfs fs/fdescfs fs/fifofs \ - fs/lofs fs/nullfs fs/portalfs fs/procfs \ - fs/specfs fs/unionfs \ - hp hp/dev hp/hpux \ - kern libkern \ - net netinet nfs scripts sys \ - ufs ufs/ffs ufs/lfs ufs/ufs \ - vm - -tags:: - -for i in ${ARCH}; do \ - (cd ../$$i && make ${MFLAGS} tags); done - -links:: - rm -f ${SYSTAGS} - ln -s ${SYSDIR}/${MACHINE_ARCH}/tags ${SYSTAGS} - -for i in ${DGEN}; do \ - (cd ../$$i && { rm -f tags; ln -s ${SYSTAGS} tags; }) done - -for i in ${ARCH}; do \ - (cd ../$$i && make ${MFLAGS} SYSTAGS=${SYSTAGS} links); done diff --git a/sys/kern/bus_if.m b/sys/kern/bus_if.m index 326156eb49d..de808ded638 100644 --- a/sys/kern/bus_if.m +++ b/sys/kern/bus_if.m @@ -26,6 +26,8 @@ # $FreeBSD$ # +#include +#include #include /** @@ -56,6 +58,14 @@ CODE { return (BUS_REMAP_INTR(dev, NULL, irq)); return (ENXIO); } + + static device_t + null_add_child(device_t bus, int order, const char *name, + int unit) + { + + panic("bus_add_child is not implemented"); + } }; /** @@ -200,10 +210,10 @@ METHOD void driver_added { */ METHOD device_t add_child { device_t _dev; - int _order; + u_int _order; const char *_name; int _unit; -}; +} DEFAULT null_add_child; /** * @brief Allocate a system resource diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index c48e0f5f471..e29ddfa0ee5 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -972,6 +973,16 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct image_params *imgp) AUXARGS_ENTRY(pos, AT_BASE, args->base); if (imgp->execpathp != 0) AUXARGS_ENTRY(pos, AT_EXECPATH, imgp->execpathp); + AUXARGS_ENTRY(pos, AT_OSRELDATE, osreldate); + if (imgp->canary != 0) { + AUXARGS_ENTRY(pos, AT_CANARY, imgp->canary); + AUXARGS_ENTRY(pos, AT_CANARYLEN, imgp->canarylen); + } + AUXARGS_ENTRY(pos, AT_NCPUS, mp_ncpus); + if (imgp->pagesizes != 0) { + AUXARGS_ENTRY(pos, AT_PAGESIZES, imgp->pagesizes); + AUXARGS_ENTRY(pos, AT_PAGESIZESLEN, imgp->pagesizeslen); + } AUXARGS_ENTRY(pos, AT_NULL, 0); free(imgp->auxargs, M_TEMP); diff --git a/sys/kern/imgact_shell.c b/sys/kern/imgact_shell.c index d0ef87c1e23..0dc9299f543 100644 --- a/sys/kern/imgact_shell.c +++ b/sys/kern/imgact_shell.c @@ -46,13 +46,18 @@ __FBSDID("$FreeBSD$"); /* * At the time of this writing, MAXSHELLCMDLEN == PAGE_SIZE. This is * significant because the caller has only mapped in one page of the - * file we're reading. This code should be changed to know how to - * read in the second page, but I'm not doing that just yet... + * file we're reading. */ #if MAXSHELLCMDLEN > PAGE_SIZE #error "MAXSHELLCMDLEN is larger than a single page!" #endif +/* + * MAXSHELLCMDLEN must be at least MAXINTERP plus the size of the `#!' + * prefix and terminating newline. + */ +CTASSERT(MAXSHELLCMDLEN >= MAXINTERP + 3); + /** * Shell interpreter image activator. An interpreter name beginning at * imgp->args->begin_argv is the minimal successful exit requirement. @@ -98,20 +103,20 @@ exec_shell_imgact(imgp) const char *image_header = imgp->image_header; const char *ihp, *interpb, *interpe, *maxp, *optb, *opte, *fname; int error, offset; - size_t length, clength; + size_t length; struct vattr vattr; struct sbuf *sname; /* a shell script? */ - if (((const short *) image_header)[0] != SHELLMAGIC) - return(-1); + if (((const short *)image_header)[0] != SHELLMAGIC) + return (-1); /* * Don't allow a shell script to be the shell for a shell * script. :-) */ if (imgp->interpreted) - return(ENOEXEC); + return (ENOEXEC); imgp->interpreted = 1; @@ -127,12 +132,9 @@ exec_shell_imgact(imgp) /* * Copy shell name and arguments from image_header into a string - * buffer. Remember that the caller has mapped only the - * first page of the file into memory. + * buffer. */ - clength = (vattr.va_size > PAGE_SIZE) ? PAGE_SIZE : vattr.va_size; - - maxp = &image_header[clength]; + maxp = &image_header[MIN(vattr.va_size, MAXSHELLCMDLEN)]; ihp = &image_header[2]; /* @@ -149,7 +151,7 @@ exec_shell_imgact(imgp) interpe = ihp; if (interpb == interpe) return (ENOEXEC); - if ((interpe - interpb) >= MAXSHELLCMDLEN) + if (interpe - interpb >= MAXINTERP) return (ENAMETOOLONG); /* @@ -163,6 +165,8 @@ exec_shell_imgact(imgp) while (ihp < maxp && ((*ihp != '\n') && (*ihp != '\0'))) ihp++; opte = ihp; + if (opte == maxp) + return (ENOEXEC); while (--ihp > optb && ((*ihp == ' ') || (*ihp == '\t'))) opte = ihp; diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index de35a52d71e..d6976890e3c 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -461,6 +461,7 @@ proc0_init(void *dummy __unused) STAILQ_INIT(&p->p_ktr); p->p_nice = NZERO; td->td_tid = PID_MAX + 1; + LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); td->td_state = TDS_RUNNING; td->td_pri_class = PRI_TIMESHARE; td->td_user_pri = PUSER; diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index ae10abeb474..706c966e3af 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 209579 2010-06-28 18:06:46Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 211998 2010-08-30 14:24:44Z kib */ #include "opt_compat.h" @@ -373,7 +373,7 @@ struct sysent sysent[] = { { compat4(AS(freebsd4_sendfile_args),sendfile), AUE_SENDFILE, NULL, 0, 0, 0, SY_THR_STATIC }, /* 336 = freebsd4 sendfile */ { AS(kldsym_args), (sy_call_t *)kldsym, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 337 = kldsym */ { AS(jail_args), (sy_call_t *)jail, AUE_JAIL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 338 = jail */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 339 = pioctl */ + { AS(nnpfs_syscall_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 339 = nnpfs_syscall */ { AS(sigprocmask_args), (sy_call_t *)sigprocmask, AUE_SIGPROCMASK, NULL, 0, 0, 0, SY_THR_STATIC }, /* 340 = sigprocmask */ { AS(sigsuspend_args), (sy_call_t *)sigsuspend, AUE_SIGSUSPEND, NULL, 0, 0, 0, SY_THR_STATIC }, /* 341 = sigsuspend */ { compat4(AS(freebsd4_sigaction_args),sigaction), AUE_SIGACTION, NULL, 0, 0, 0, SY_THR_STATIC }, /* 342 = freebsd4 sigaction */ @@ -411,7 +411,7 @@ struct sysent sysent[] = { { AS(__setugid_args), (sy_call_t *)__setugid, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 374 = __setugid */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 375 = nfsclnt */ { AS(eaccess_args), (sy_call_t *)eaccess, AUE_EACCESS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 376 = eaccess */ - { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 377 = afs_syscall */ + { AS(afs3_syscall_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 377 = afs3_syscall */ { AS(nmount_args), (sy_call_t *)nmount, AUE_NMOUNT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 378 = nmount */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 379 = kse_exit */ { 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 380 = kse_wakeup */ diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index c283b6b1e6a..192ec602150 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -373,11 +373,8 @@ int profprocs; int ticks; int psratio; -int timer1hz; -int timer2hz; -static DPCPU_DEFINE(u_int, hard_cnt); -static DPCPU_DEFINE(u_int, stat_cnt); -static DPCPU_DEFINE(u_int, prof_cnt); +static DPCPU_DEFINE(int, pcputicks); /* Per-CPU version of ticks. */ +static int global_hardclock_run = 0; /* * Initialize clock frequencies and start both clocks running. @@ -408,52 +405,6 @@ initclocks(dummy) #endif } -void -timer1clock(int usermode, uintfptr_t pc) -{ - u_int *cnt; - - cnt = DPCPU_PTR(hard_cnt); - *cnt += hz; - if (*cnt >= timer1hz) { - *cnt -= timer1hz; - if (*cnt >= timer1hz) - *cnt = 0; - if (PCPU_GET(cpuid) == 0) - hardclock(usermode, pc); - else - hardclock_cpu(usermode); - } - if (timer2hz == 0) - timer2clock(usermode, pc); -} - -void -timer2clock(int usermode, uintfptr_t pc) -{ - u_int *cnt; - int t2hz = timer2hz ? timer2hz : timer1hz; - - cnt = DPCPU_PTR(stat_cnt); - *cnt += stathz; - if (*cnt >= t2hz) { - *cnt -= t2hz; - if (*cnt >= t2hz) - *cnt = 0; - statclock(usermode); - } - if (profprocs == 0) - return; - cnt = DPCPU_PTR(prof_cnt); - *cnt += profhz; - if (*cnt >= t2hz) { - *cnt -= t2hz; - if (*cnt >= t2hz) - *cnt = 0; - profclock(usermode, pc); - } -} - /* * Each time the real-time timer fires, this function is called on all CPUs. * Note that hardclock() calls hardclock_cpu() for the boot CPU, so only @@ -486,7 +437,7 @@ hardclock_cpu(int usermode) PROC_SUNLOCK(p); } thread_lock(td); - sched_tick(); + sched_tick(1); td->td_flags |= flags; thread_unlock(td); @@ -506,7 +457,8 @@ hardclock(int usermode, uintfptr_t pc) atomic_add_int((volatile int *)&ticks, 1); hardclock_cpu(usermode); - tc_ticktock(); + tc_ticktock(1); + cpu_tick_calibration(); /* * If no separate statistics clock is available, run it from here. * @@ -525,6 +477,94 @@ hardclock(int usermode, uintfptr_t pc) #endif /* SW_WATCHDOG */ } +void +hardclock_anycpu(int cnt, int usermode) +{ + struct pstats *pstats; + struct thread *td = curthread; + struct proc *p = td->td_proc; + int *t = DPCPU_PTR(pcputicks); + int flags, global, newticks; +#ifdef SW_WATCHDOG + int i; +#endif /* SW_WATCHDOG */ + + /* + * Update per-CPU and possibly global ticks values. + */ + *t += cnt; + do { + global = ticks; + newticks = *t - global; + if (newticks <= 0) { + if (newticks < -1) + *t = global - 1; + newticks = 0; + break; + } + } while (!atomic_cmpset_int(&ticks, global, *t)); + + /* + * Run current process's virtual and profile time, as needed. + */ + pstats = p->p_stats; + flags = 0; + if (usermode && + timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value)) { + PROC_SLOCK(p); + if (itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], + tick * cnt) == 0) + flags |= TDF_ALRMPEND | TDF_ASTPENDING; + PROC_SUNLOCK(p); + } + if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value)) { + PROC_SLOCK(p); + if (itimerdecr(&pstats->p_timer[ITIMER_PROF], + tick * cnt) == 0) + flags |= TDF_PROFPEND | TDF_ASTPENDING; + PROC_SUNLOCK(p); + } + thread_lock(td); + sched_tick(cnt); + td->td_flags |= flags; + thread_unlock(td); + +#ifdef HWPMC_HOOKS + if (PMC_CPU_HAS_SAMPLES(PCPU_GET(cpuid))) + PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL); +#endif + callout_tick(); + /* We are in charge to handle this tick duty. */ + if (newticks > 0) { + /* Dangerous and no need to call these things concurrently. */ + if (atomic_cmpset_acq_int(&global_hardclock_run, 0, 1)) { + tc_ticktock(newticks); +#ifdef DEVICE_POLLING + /* This is very short and quick. */ + hardclock_device_poll(); +#endif /* DEVICE_POLLING */ + atomic_store_rel_int(&global_hardclock_run, 0); + } +#ifdef SW_WATCHDOG + if (watchdog_enabled > 0) { + i = atomic_fetchadd_int(&watchdog_ticks, -newticks); + if (i > 0 && i <= newticks) + watchdog_fire(); + } +#endif /* SW_WATCHDOG */ + } + if (curcpu == CPU_FIRST()) + cpu_tick_calibration(); +} + +void +hardclock_sync(int cpu) +{ + int *t = DPCPU_ID_PTR(cpu, pcputicks); + + *t = ticks; +} + /* * Compute number of ticks in the specified amount of time. */ diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c index 6b005de8c5e..e654659d463 100644 --- a/sys/kern/kern_clocksource.c +++ b/sys/kern/kern_clocksource.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); /* XEN has own timer routines now. */ #ifndef XEN +#include "opt_device_polling.h" #include "opt_kdtrace.h" #include @@ -41,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -48,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -59,28 +62,80 @@ __FBSDID("$FreeBSD$"); cyclic_clock_func_t cyclic_clock_func[MAXCPU]; #endif -static void cpu_restartclocks(void); -static void timercheck(void); -inline static int doconfigtimer(int i); -static void configtimer(int i); +int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ -static struct eventtimer *timer[2] = { NULL, NULL }; -static int timertest = 0; -static int timerticks[2] = { 0, 0 }; -static int profiling_on = 0; -static struct bintime timerperiod[2]; +static void setuptimer(void); +static void loadtimer(struct bintime *now, int first); +static int doconfigtimer(void); +static void configtimer(int start); +static int round_freq(struct eventtimer *et, int freq); -static char timername[2][32]; -TUNABLE_STR("kern.eventtimer.timer1", timername[0], sizeof(*timername)); -TUNABLE_STR("kern.eventtimer.timer2", timername[1], sizeof(*timername)); +static void getnextcpuevent(struct bintime *event, int idle); +static void getnextevent(struct bintime *event); +static int handleevents(struct bintime *now, int fake); +#ifdef SMP +static void cpu_new_callout(int cpu, int ticks); +#endif -static u_int singlemul = 0; +static struct mtx et_hw_mtx; + +#define ET_HW_LOCK(state) \ + { \ + if (timer->et_flags & ET_FLAGS_PERCPU) \ + mtx_lock_spin(&(state)->et_hw_mtx); \ + else \ + mtx_lock_spin(&et_hw_mtx); \ + } + +#define ET_HW_UNLOCK(state) \ + { \ + if (timer->et_flags & ET_FLAGS_PERCPU) \ + mtx_unlock_spin(&(state)->et_hw_mtx); \ + else \ + mtx_unlock_spin(&et_hw_mtx); \ + } + +static struct eventtimer *timer = NULL; +static struct bintime timerperiod; /* Timer period for periodic mode. */ +static struct bintime hardperiod; /* hardclock() events period. */ +static struct bintime statperiod; /* statclock() events period. */ +static struct bintime profperiod; /* profclock() events period. */ +static struct bintime nexttick; /* Next global timer tick time. */ +static u_int busy = 0; /* Reconfiguration is in progress. */ +static int profiling = 0; /* Profiling events enabled. */ + +static char timername[32]; /* Wanted timer. */ +TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername)); + +static int singlemul = 0; /* Multiplier for periodic mode. */ TUNABLE_INT("kern.eventtimer.singlemul", &singlemul); SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul, - 0, "Multiplier, used in single timer mode"); + 0, "Multiplier for periodic mode"); -typedef u_int tc[2]; -static DPCPU_DEFINE(tc, configtimer); +static u_int idletick = 0; /* Idle mode allowed. */ +TUNABLE_INT("kern.eventtimer.idletick", &idletick); +SYSCTL_INT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick, + 0, "Run periodic events when idle"); + +static int periodic = 0; /* Periodic or one-shot mode. */ +static int want_periodic = 0; /* What mode to prefer. */ +TUNABLE_INT("kern.eventtimer.periodic", &want_periodic); + +struct pcpu_state { + struct mtx et_hw_mtx; /* Per-CPU timer mutex. */ + u_int action; /* Reconfiguration requests. */ + u_int handle; /* Immediate handle resuests. */ + struct bintime now; /* Last tick time. */ + struct bintime nextevent; /* Next scheduled event on this CPU. */ + struct bintime nexttick; /* Next timer tick time. */ + struct bintime nexthard; /* Next hardlock() event. */ + struct bintime nextstat; /* Next statclock() event. */ + struct bintime nextprof; /* Next profclock() event. */ + int ipi; /* This CPU needs IPI. */ + int idle; /* This CPU is in idle mode. */ +}; + +static DPCPU_DEFINE(struct pcpu_state, timerstate); #define FREQ2BT(freq, bt) \ { \ @@ -91,159 +146,329 @@ static DPCPU_DEFINE(tc, configtimer); (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \ ((bt)->frac >> 1)) -/* Per-CPU timer1 handler. */ -static int -hardclockhandler(struct trapframe *frame) +/* + * Timer broadcast IPI handler. + */ +int +hardclockintr(void) { + struct bintime now; + struct pcpu_state *state; + int done; + if (doconfigtimer() || busy) + return (FILTER_HANDLED); + state = DPCPU_PTR(timerstate); + now = state->now; + CTR4(KTR_SPARE2, "ipi at %d: now %d.%08x%08x", + curcpu, now.sec, (unsigned int)(now.frac >> 32), + (unsigned int)(now.frac & 0xffffffff)); + done = handleevents(&now, 0); + return (done ? FILTER_HANDLED : FILTER_STRAY); +} + +/* + * Handle all events for specified time on this CPU + */ +static int +handleevents(struct bintime *now, int fake) +{ + struct bintime t; + struct trapframe *frame; + struct pcpu_state *state; + uintfptr_t pc; + int usermode; + int done, runs; + + CTR4(KTR_SPARE2, "handle at %d: now %d.%08x%08x", + curcpu, now->sec, (unsigned int)(now->frac >> 32), + (unsigned int)(now->frac & 0xffffffff)); + done = 0; + if (fake) { + frame = NULL; + usermode = 0; + pc = 0; + } else { + frame = curthread->td_intr_frame; + usermode = TRAPF_USERMODE(frame); + pc = TRAPF_PC(frame); + } #ifdef KDTRACE_HOOKS /* * If the DTrace hooks are configured and a callback function * has been registered, then call it to process the high speed * timers. */ - int cpu = curcpu; - if (cyclic_clock_func[cpu] != NULL) - (*cyclic_clock_func[cpu])(frame); + if (!fake && cyclic_clock_func[curcpu] != NULL) + (*cyclic_clock_func[curcpu])(frame); #endif - - timer1clock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); - return (FILTER_HANDLED); -} - -/* Per-CPU timer2 handler. */ -static int -statclockhandler(struct trapframe *frame) -{ - - timer2clock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); - return (FILTER_HANDLED); -} - -/* timer1 broadcast IPI handler. */ -int -hardclockintr(struct trapframe *frame) -{ - - if (doconfigtimer(0)) - return (FILTER_HANDLED); - return (hardclockhandler(frame)); -} - -/* timer2 broadcast IPI handler. */ -int -statclockintr(struct trapframe *frame) -{ - - if (doconfigtimer(1)) - return (FILTER_HANDLED); - return (statclockhandler(frame)); -} - -/* timer1 callback. */ -static void -timer1cb(struct eventtimer *et, void *arg) -{ - -#ifdef SMP - /* Broadcast interrupt to other CPUs for non-per-CPU timers */ - if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0) - ipi_all_but_self(IPI_HARDCLOCK); -#endif - if (timertest) { - if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) { - timerticks[0]++; - if (timerticks[0] >= timer1hz) { - ET_LOCK(); - timercheck(); - ET_UNLOCK(); - } - } + runs = 0; + state = DPCPU_PTR(timerstate); + while (bintime_cmp(now, &state->nexthard, >=)) { + bintime_add(&state->nexthard, &hardperiod); + runs++; } - hardclockhandler(curthread->td_intr_frame); -} - -/* timer2 callback. */ -static void -timer2cb(struct eventtimer *et, void *arg) -{ - -#ifdef SMP - /* Broadcast interrupt to other CPUs for non-per-CPU timers */ - if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0) - ipi_all_but_self(IPI_STATCLOCK); -#endif - if (timertest) { - if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) { - timerticks[1]++; - if (timerticks[1] >= timer2hz * 2) { - ET_LOCK(); - timercheck(); - ET_UNLOCK(); - } - } + if (runs) { + hardclock_anycpu(runs, usermode); + done = 1; } - statclockhandler(curthread->td_intr_frame); + while (bintime_cmp(now, &state->nextstat, >=)) { + statclock(usermode); + bintime_add(&state->nextstat, &statperiod); + done = 1; + } + if (profiling) { + while (bintime_cmp(now, &state->nextprof, >=)) { + if (!fake) + profclock(usermode, pc); + bintime_add(&state->nextprof, &profperiod); + done = 1; + } + } else + state->nextprof = state->nextstat; + getnextcpuevent(&t, 0); + ET_HW_LOCK(state); + if (!busy) { + state->idle = 0; + state->nextevent = t; + loadtimer(now, 0); + } + ET_HW_UNLOCK(state); + return (done); } /* - * Check that both timers are running with at least 1/4 of configured rate. - * If not - replace the broken one. + * Schedule binuptime of the next event on current CPU. */ static void -timercheck(void) +getnextcpuevent(struct bintime *event, int idle) { + struct bintime tmp; + struct pcpu_state *state; + int skip; - if (!timertest) - return; - timertest = 0; - if (timerticks[0] * 4 < timer1hz) { - printf("Event timer \"%s\" is dead.\n", timer[0]->et_name); - timer1hz = 0; - configtimer(0); - et_ban(timer[0]); - et_free(timer[0]); - timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (timer[0] == NULL) { - timer2hz = 0; - configtimer(1); - et_free(timer[1]); - timer[1] = NULL; - timer[0] = timer[1]; + state = DPCPU_PTR(timerstate); + *event = state->nexthard; + if (idle) { /* If CPU is idle - ask callouts for how long. */ + skip = 4; + if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip) + skip = tc_min_ticktock_freq; + skip = callout_tickstofirst(hz / skip) - 1; + CTR2(KTR_SPARE2, "skip at %d: %d", curcpu, skip); + tmp = hardperiod; + bintime_mul(&tmp, skip); + bintime_add(event, &tmp); + } else { /* If CPU is active - handle all types of events. */ + if (bintime_cmp(event, &state->nextstat, >)) + *event = state->nextstat; + if (profiling && + bintime_cmp(event, &state->nextprof, >)) + *event = state->nextprof; + } +} + +/* + * Schedule binuptime of the next event on all CPUs. + */ +static void +getnextevent(struct bintime *event) +{ + struct pcpu_state *state; +#ifdef SMP + int cpu; +#endif + int c; + + state = DPCPU_PTR(timerstate); + *event = state->nextevent; + c = curcpu; +#ifdef SMP + if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) { + CPU_FOREACH(cpu) { + if (curcpu == cpu) + continue; + state = DPCPU_ID_PTR(cpu, timerstate); + if (bintime_cmp(event, &state->nextevent, >)) { + *event = state->nextevent; + c = cpu; + } } - et_init(timer[0], timer1cb, NULL, NULL); - cpu_restartclocks(); - return; } - if (timerticks[1] * 4 < timer2hz) { - printf("Event timer \"%s\" is dead.\n", timer[1]->et_name); - timer2hz = 0; - configtimer(1); - et_ban(timer[1]); - et_free(timer[1]); - timer[1] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (timer[1] != NULL) - et_init(timer[1], timer2cb, NULL, NULL); - cpu_restartclocks(); +#endif + CTR5(KTR_SPARE2, "next at %d: next %d.%08x%08x by %d", + curcpu, event->sec, (unsigned int)(event->frac >> 32), + (unsigned int)(event->frac & 0xffffffff), c); +} + +/* Hardware timer callback function. */ +static void +timercb(struct eventtimer *et, void *arg) +{ + struct bintime now; + struct bintime *next; + struct pcpu_state *state; +#ifdef SMP + int cpu, bcast; +#endif + + /* Do not touch anything if somebody reconfiguring timers. */ + if (busy) return; + /* Update present and next tick times. */ + state = DPCPU_PTR(timerstate); + if (et->et_flags & ET_FLAGS_PERCPU) { + next = &state->nexttick; + } else + next = &nexttick; + if (periodic) { + now = *next; /* Ex-next tick time becomes present time. */ + bintime_add(next, &timerperiod); /* Next tick in 1 period. */ + } else { + binuptime(&now); /* Get present time from hardware. */ + next->sec = -1; /* Next tick is not scheduled yet. */ } + state->now = now; + CTR4(KTR_SPARE2, "intr at %d: now %d.%08x%08x", + curcpu, now.sec, (unsigned int)(now.frac >> 32), + (unsigned int)(now.frac & 0xffffffff)); + +#ifdef SMP + /* Prepare broadcasting to other CPUs for non-per-CPU timers. */ + bcast = 0; + if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) { + CPU_FOREACH(cpu) { + state = DPCPU_ID_PTR(cpu, timerstate); + ET_HW_LOCK(state); + state->now = now; + if (bintime_cmp(&now, &state->nextevent, >=)) { + state->nextevent.sec++; + if (curcpu != cpu) { + state->ipi = 1; + bcast = 1; + } + } + ET_HW_UNLOCK(state); + } + } +#endif + + /* Handle events for this time on this CPU. */ + handleevents(&now, 0); + +#ifdef SMP + /* Broadcast interrupt to other CPUs for non-per-CPU timers. */ + if (bcast) { + CPU_FOREACH(cpu) { + if (curcpu == cpu) + continue; + state = DPCPU_ID_PTR(cpu, timerstate); + if (state->ipi) { + state->ipi = 0; + ipi_cpu(cpu, IPI_HARDCLOCK); + } + } + } +#endif +} + +/* + * Load new value into hardware timer. + */ +static void +loadtimer(struct bintime *now, int start) +{ + struct pcpu_state *state; + struct bintime new; + struct bintime *next; + uint64_t tmp; + int eq; + + if (periodic) { + if (start) { + /* + * Try to start all periodic timers aligned + * to period to make events synchronous. + */ + tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28); + tmp = (tmp % (timerperiod.frac >> 28)) << 28; + tmp = timerperiod.frac - tmp; + new = timerperiod; + bintime_addx(&new, tmp); + CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x", + curcpu, now->sec, (unsigned int)(now->frac >> 32), + new.sec, (unsigned int)(new.frac >> 32)); + et_start(timer, &new, &timerperiod); + } + } else { + if (timer->et_flags & ET_FLAGS_PERCPU) { + state = DPCPU_PTR(timerstate); + next = &state->nexttick; + } else + next = &nexttick; + getnextevent(&new); + eq = bintime_cmp(&new, next, ==); + CTR5(KTR_SPARE2, "load at %d: next %d.%08x%08x eq %d", + curcpu, new.sec, (unsigned int)(new.frac >> 32), + (unsigned int)(new.frac & 0xffffffff), + eq); + if (!eq) { + *next = new; + bintime_sub(&new, now); + et_start(timer, &new, NULL); + } + } +} + +/* + * Prepare event timer parameters after configuration changes. + */ +static void +setuptimer(void) +{ + int freq; + + if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) + periodic = 0; + else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) + periodic = 1; + singlemul = MIN(MAX(singlemul, 1), 20); + freq = hz * singlemul; + while (freq < (profiling ? profhz : stathz)) + freq += hz; + freq = round_freq(timer, freq); + FREQ2BT(freq, &timerperiod); } /* * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler. */ -inline static int -doconfigtimer(int i) +static int +doconfigtimer(void) { - tc *conf; + struct bintime now; + struct pcpu_state *state; - conf = DPCPU_PTR(configtimer); - if (atomic_load_acq_int(*conf + i)) { - if (i == 0 ? timer1hz : timer2hz) - et_start(timer[i], NULL, &timerperiod[i]); - else - et_stop(timer[i]); - atomic_store_rel_int(*conf + i, 0); + state = DPCPU_PTR(timerstate); + switch (atomic_load_acq_int(&state->action)) { + case 1: + binuptime(&now); + ET_HW_LOCK(state); + loadtimer(&now, 1); + ET_HW_UNLOCK(state); + state->handle = 0; + atomic_store_rel_int(&state->action, 0); + return (1); + case 2: + ET_HW_LOCK(state); + et_stop(timer); + ET_HW_UNLOCK(state); + state->handle = 0; + atomic_store_rel_int(&state->action, 0); + return (1); + } + if (atomic_readandclear_int(&state->handle) && !busy) { + binuptime(&now); + handleevents(&now, 0); return (1); } return (0); @@ -254,45 +479,79 @@ doconfigtimer(int i) * For per-CPU timers use IPI to make other CPUs to reconfigure. */ static void -configtimer(int i) +configtimer(int start) { -#ifdef SMP - tc *conf; + struct bintime now, next; + struct pcpu_state *state; int cpu; + if (start) { + setuptimer(); + binuptime(&now); + } critical_enter(); -#endif - /* Start/stop global timer or per-CPU timer of this CPU. */ - if (i == 0 ? timer1hz : timer2hz) - et_start(timer[i], NULL, &timerperiod[i]); - else - et_stop(timer[i]); + ET_HW_LOCK(DPCPU_PTR(timerstate)); + if (start) { + /* Initialize time machine parameters. */ + next = now; + bintime_add(&next, &timerperiod); + if (periodic) + nexttick = next; + else + nexttick.sec = -1; + CPU_FOREACH(cpu) { + state = DPCPU_ID_PTR(cpu, timerstate); + state->now = now; + state->nextevent = next; + if (periodic) + state->nexttick = next; + else + state->nexttick.sec = -1; + state->nexthard = next; + state->nextstat = next; + state->nextprof = next; + hardclock_sync(cpu); + } + busy = 0; + /* Start global timer or per-CPU timer of this CPU. */ + loadtimer(&now, 1); + } else { + busy = 1; + /* Stop global timer or per-CPU timer of this CPU. */ + et_stop(timer); + } + ET_HW_UNLOCK(DPCPU_PTR(timerstate)); #ifdef SMP - if ((timer[i]->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { + /* If timer is global or there is no other CPUs yet - we are done. */ + if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) { critical_exit(); return; } /* Set reconfigure flags for other CPUs. */ CPU_FOREACH(cpu) { - conf = DPCPU_ID_PTR(cpu, configtimer); - atomic_store_rel_int(*conf + i, (cpu == curcpu) ? 0 : 1); + state = DPCPU_ID_PTR(cpu, timerstate); + atomic_store_rel_int(&state->action, + (cpu == curcpu) ? 0 : ( start ? 1 : 2)); } - /* Send reconfigure IPI. */ - ipi_all_but_self(i == 0 ? IPI_HARDCLOCK : IPI_STATCLOCK); + /* Broadcast reconfigure IPI. */ + ipi_all_but_self(IPI_HARDCLOCK); /* Wait for reconfiguration completed. */ restart: cpu_spinwait(); CPU_FOREACH(cpu) { if (cpu == curcpu) continue; - conf = DPCPU_ID_PTR(cpu, configtimer); - if (atomic_load_acq_int(*conf + i)) + state = DPCPU_ID_PTR(cpu, timerstate); + if (atomic_load_acq_int(&state->action)) goto restart; } - critical_exit(); #endif + critical_exit(); } +/* + * Calculate nearest frequency supported by hardware timer. + */ static int round_freq(struct eventtimer *et, int freq) { @@ -314,29 +573,56 @@ round_freq(struct eventtimer *et, int freq) } /* - * Configure and start event timers. + * Configure and start event timers (BSP part). */ void cpu_initclocks_bsp(void) { - int base, div; + struct pcpu_state *state; + int base, div, cpu; - timer[0] = et_find(timername[0], ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (timer[0] == NULL) - timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (timer[0] == NULL) + mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); + CPU_FOREACH(cpu) { + state = DPCPU_ID_PTR(cpu, timerstate); + mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN); + } +#ifdef SMP + callout_new_inserted = cpu_new_callout; +#endif + periodic = want_periodic; + /* Grab requested timer or the best of present. */ + if (timername[0]) + timer = et_find(timername, 0, 0); + if (timer == NULL && periodic) { + timer = et_find(NULL, + ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); + } + if (timer == NULL) { + timer = et_find(NULL, + ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT); + } + if (timer == NULL && !periodic) { + timer = et_find(NULL, + ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); + } + if (timer == NULL) panic("No usable event timer found!"); - et_init(timer[0], timer1cb, NULL, NULL); - timer[1] = et_find(timername[1][0] ? timername[1] : NULL, - ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (timer[1]) - et_init(timer[1], timer2cb, NULL, NULL); + et_init(timer, timercb, NULL, NULL); + + /* Adapt to timer capabilities. */ + if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0) + periodic = 0; + else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0) + periodic = 1; + if (timer->et_flags & ET_FLAGS_C3STOP) + cpu_disable_deep_sleep++; + /* * We honor the requested 'hz' value. * We want to run stathz in the neighborhood of 128hz. * We would like profhz to run as often as possible. */ - if (singlemul == 0) { + if (singlemul <= 0 || singlemul > 20) { if (hz >= 1500 || (hz % 128) == 0) singlemul = 1; else if (hz >= 750) @@ -344,8 +630,8 @@ cpu_initclocks_bsp(void) else singlemul = 4; } - if (timer[1] == NULL) { - base = round_freq(timer[0], hz * singlemul); + if (periodic) { + base = round_freq(timer, hz * singlemul); singlemul = max((base + hz / 2) / hz, 1); hz = (base + singlemul / 2) / singlemul; if (base <= 128) @@ -359,175 +645,245 @@ cpu_initclocks_bsp(void) profhz = stathz; while ((profhz + stathz) <= 128 * 64) profhz += stathz; - profhz = round_freq(timer[0], profhz); + profhz = round_freq(timer, profhz); } else { - hz = round_freq(timer[0], hz); - stathz = round_freq(timer[1], 127); - profhz = round_freq(timer[1], stathz * 64); + hz = round_freq(timer, hz); + stathz = round_freq(timer, 127); + profhz = round_freq(timer, stathz * 64); } tick = 1000000 / hz; + FREQ2BT(hz, &hardperiod); + FREQ2BT(stathz, &statperiod); + FREQ2BT(profhz, &profperiod); ET_LOCK(); - cpu_restartclocks(); + configtimer(1); ET_UNLOCK(); } -/* Start per-CPU event timers on APs. */ +/* + * Start per-CPU event timers on APs. + */ void cpu_initclocks_ap(void) { + struct bintime now; + struct pcpu_state *state; - ET_LOCK(); - if (timer[0]->et_flags & ET_FLAGS_PERCPU) - et_start(timer[0], NULL, &timerperiod[0]); - if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU) - et_start(timer[1], NULL, &timerperiod[1]); - ET_UNLOCK(); -} - -/* Reconfigure and restart event timers after configuration changes. */ -static void -cpu_restartclocks(void) -{ - - /* Stop all event timers. */ - timertest = 0; - if (timer1hz) { - timer1hz = 0; - configtimer(0); - } - if (timer[1] && timer2hz) { - timer2hz = 0; - configtimer(1); - } - /* Calculate new event timers parameters. */ - if (timer[1] == NULL) { - timer1hz = hz * singlemul; - while (timer1hz < (profiling_on ? profhz : stathz)) - timer1hz += hz; - timer2hz = 0; - } else { - timer1hz = hz; - timer2hz = profiling_on ? profhz : stathz; - timer2hz = round_freq(timer[1], timer2hz); - } - timer1hz = round_freq(timer[0], timer1hz); - printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n", - timer[0]->et_name, timer1hz, - timer[1] ? timer[1]->et_name : "NONE", timer2hz); - /* Restart event timers. */ - FREQ2BT(timer1hz, &timerperiod[0]); - configtimer(0); - if (timer[1]) { - timerticks[0] = 0; - timerticks[1] = 0; - FREQ2BT(timer2hz, &timerperiod[1]); - configtimer(1); - timertest = 1; + if (timer->et_flags & ET_FLAGS_PERCPU) { + state = DPCPU_PTR(timerstate); + binuptime(&now); + ET_HW_LOCK(state); + loadtimer(&now, 1); + ET_HW_UNLOCK(state); } } -/* Switch to profiling clock rates. */ +/* + * Switch to profiling clock rates. + */ void cpu_startprofclock(void) { ET_LOCK(); - profiling_on = 1; - cpu_restartclocks(); + if (periodic) { + configtimer(0); + profiling = 1; + configtimer(1); + } else + profiling = 1; ET_UNLOCK(); } -/* Switch to regular clock rates. */ +/* + * Switch to regular clock rates. + */ void cpu_stopprofclock(void) { ET_LOCK(); - profiling_on = 0; - cpu_restartclocks(); + if (periodic) { + configtimer(0); + profiling = 0; + configtimer(1); + } else + profiling = 0; ET_UNLOCK(); } -/* Report or change the active event timers hardware. */ +/* + * Switch to idle mode (all ticks handled). + */ +void +cpu_idleclock(void) +{ + struct bintime now, t; + struct pcpu_state *state; + + if (idletick || busy || + (periodic && (timer->et_flags & ET_FLAGS_PERCPU)) +#ifdef DEVICE_POLLING + || curcpu == CPU_FIRST() +#endif + ) + return; + state = DPCPU_PTR(timerstate); + if (periodic) + now = state->now; + else + binuptime(&now); + CTR4(KTR_SPARE2, "idle at %d: now %d.%08x%08x", + curcpu, now.sec, (unsigned int)(now.frac >> 32), + (unsigned int)(now.frac & 0xffffffff)); + getnextcpuevent(&t, 1); + ET_HW_LOCK(state); + state->idle = 1; + state->nextevent = t; + if (!periodic) + loadtimer(&now, 0); + ET_HW_UNLOCK(state); +} + +/* + * Switch to active mode (skip empty ticks). + */ +void +cpu_activeclock(void) +{ + struct bintime now; + struct pcpu_state *state; + struct thread *td; + + state = DPCPU_PTR(timerstate); + if (state->idle == 0 || busy) + return; + if (periodic) + now = state->now; + else + binuptime(&now); + CTR4(KTR_SPARE2, "active at %d: now %d.%08x%08x", + curcpu, now.sec, (unsigned int)(now.frac >> 32), + (unsigned int)(now.frac & 0xffffffff)); + spinlock_enter(); + td = curthread; + td->td_intr_nesting_level++; + handleevents(&now, 1); + td->td_intr_nesting_level--; + spinlock_exit(); +} + +#ifdef SMP +static void +cpu_new_callout(int cpu, int ticks) +{ + struct bintime tmp; + struct pcpu_state *state; + + CTR3(KTR_SPARE2, "new co at %d: on %d in %d", + curcpu, cpu, ticks); + state = DPCPU_ID_PTR(cpu, timerstate); + ET_HW_LOCK(state); + if (state->idle == 0 || busy) { + ET_HW_UNLOCK(state); + return; + } + /* + * If timer is periodic - just update next event time for target CPU. + * If timer is global - there is chance it is already programmed. + */ + if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) { + state->nextevent = state->nexthard; + tmp = hardperiod; + bintime_mul(&tmp, ticks - 1); + bintime_add(&state->nextevent, &tmp); + if (periodic || + bintime_cmp(&state->nextevent, &nexttick, >=)) { + ET_HW_UNLOCK(state); + return; + } + } + /* + * Otherwise we have to wake that CPU up, as we can't get present + * bintime to reprogram global timer from here. If timer is per-CPU, + * we by definition can't do it from here. + */ + ET_HW_UNLOCK(state); + if (timer->et_flags & ET_FLAGS_PERCPU) { + state->handle = 1; + ipi_cpu(cpu, IPI_HARDCLOCK); + } else { + if (!cpu_idle_wakeup(cpu)) + ipi_cpu(cpu, IPI_AST); + } +} +#endif + +/* + * Report or change the active event timers hardware. + */ static int -sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS) +sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS) { char buf[32]; struct eventtimer *et; int error; ET_LOCK(); - et = timer[0]; + et = timer; snprintf(buf, sizeof(buf), "%s", et->et_name); ET_UNLOCK(); error = sysctl_handle_string(oidp, buf, sizeof(buf), req); ET_LOCK(); - et = timer[0]; + et = timer; if (error != 0 || req->newptr == NULL || - strcmp(buf, et->et_name) == 0) { + strcasecmp(buf, et->et_name) == 0) { ET_UNLOCK(); return (error); } - et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); + et = et_find(buf, 0, 0); if (et == NULL) { ET_UNLOCK(); return (ENOENT); } - timer1hz = 0; configtimer(0); - et_free(timer[0]); - timer[0] = et; - et_init(timer[0], timer1cb, NULL, NULL); - cpu_restartclocks(); + et_free(timer); + if (et->et_flags & ET_FLAGS_C3STOP) + cpu_disable_deep_sleep++; + if (timer->et_flags & ET_FLAGS_C3STOP) + cpu_disable_deep_sleep--; + periodic = want_periodic; + timer = et; + et_init(timer, timercb, NULL, NULL); + configtimer(1); ET_UNLOCK(); return (error); } -SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer1, +SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - 0, 0, sysctl_kern_eventtimer_timer1, "A", "Primary event timer"); + 0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer"); +/* + * Report or change the active event timer periodicity. + */ static int -sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS) +sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS) { - char buf[32]; - struct eventtimer *et; - int error; + int error, val; - ET_LOCK(); - et = timer[1]; - if (et == NULL) - snprintf(buf, sizeof(buf), "NONE"); - else - snprintf(buf, sizeof(buf), "%s", et->et_name); - ET_UNLOCK(); - error = sysctl_handle_string(oidp, buf, sizeof(buf), req); - ET_LOCK(); - et = timer[1]; - if (error != 0 || req->newptr == NULL || - strcmp(buf, et ? et->et_name : "NONE") == 0) { - ET_UNLOCK(); + val = periodic; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || req->newptr == NULL) return (error); - } - et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC); - if (et == NULL && strcasecmp(buf, "NONE") != 0) { - ET_UNLOCK(); - return (ENOENT); - } - if (timer[1] != NULL) { - timer2hz = 0; - configtimer(1); - et_free(timer[1]); - } - timer[1] = et; - if (timer[1] != NULL) - et_init(timer[1], timer2cb, NULL, NULL); - cpu_restartclocks(); + ET_LOCK(); + configtimer(0); + periodic = want_periodic = val; + configtimer(1); ET_UNLOCK(); return (error); } -SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer2, - CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, - 0, 0, sysctl_kern_eventtimer_timer2, "A", "Secondary event timer"); +SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + 0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode"); #endif - diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c index 12d1a8d141e..509ce775fd6 100644 --- a/sys/kern/kern_conf.c +++ b/sys/kern/kern_conf.c @@ -681,27 +681,92 @@ prep_cdevsw(struct cdevsw *devsw, int flags) return (0); } +static int +prep_devname(struct cdev *dev, const char *fmt, va_list ap) +{ + int len; + char *from, *q, *s, *to; + + mtx_assert(&devmtx, MA_OWNED); + + len = vsnrprintf(dev->__si_namebuf, sizeof(dev->__si_namebuf), 32, + fmt, ap); + if (len > sizeof(dev->__si_namebuf) - 1) + return (ENAMETOOLONG); + + /* Strip leading slashes. */ + for (from = dev->__si_namebuf; *from == '/'; from++) + ; + + for (to = dev->__si_namebuf; *from != '\0'; from++, to++) { + /* Treat multiple sequential slashes as single. */ + while (from[0] == '/' && from[1] == '/') + from++; + /* Trailing slash is considered invalid. */ + if (from[0] == '/' && from[1] == '\0') + return (EINVAL); + *to = *from; + } + *to = '\0'; + + if (dev->__si_namebuf[0] == '\0') + return (EINVAL); + + /* Disallow "." and ".." components. */ + for (s = dev->__si_namebuf;;) { + for (q = s; *q != '/' && *q != '\0'; q++) + ; + if (q - s == 1 && s[0] == '.') + return (EINVAL); + if (q - s == 2 && s[0] == '.' && s[1] == '.') + return (EINVAL); + if (*q != '/') + break; + s = q + 1; + } + + if (devfs_dev_exists(dev->__si_namebuf) != 0) + return (EEXIST); + + return (0); +} + static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, va_list ap) { - struct cdev *dev; - int i, res; + struct cdev *dev, *dev_new; + int res; KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0, ("make_dev_credv: both WAITOK and NOWAIT specified")); - dev = devfs_alloc(flags); - if (dev == NULL) + dev_new = devfs_alloc(flags); + if (dev_new == NULL) return (ENOMEM); dev_lock(); res = prep_cdevsw(devsw, flags); if (res != 0) { dev_unlock(); - devfs_free(dev); + devfs_free(dev_new); return (res); } - dev = newdev(devsw, unit, dev); + dev = newdev(devsw, unit, dev_new); + if ((dev->si_flags & SI_NAMED) == 0) + res = prep_devname(dev, fmt, ap); + if (res != 0) { + if ((flags & MAKEDEV_CHECKNAME) == 0) { + panic( + "make_dev_credv: bad si_name (error=%d, si_name=%s)", + res, dev->si_name); + } + if (dev == dev_new) { + LIST_REMOVE(dev, si_list); + dev_unlock(); + devfs_free(dev); + } + return (res); + } if (flags & MAKEDEV_REF) dev_refl(dev); if (flags & MAKEDEV_ETERNAL) @@ -720,13 +785,6 @@ make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit, KASSERT(!(dev->si_flags & SI_NAMED), ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", devsw->d_name, dev2unit(dev), devtoname(dev))); - - i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); - if (i > (sizeof dev->__si_namebuf - 1)) { - printf("WARNING: Device name truncated! (%s)\n", - dev->__si_namebuf); - } - dev->si_flags |= SI_NAMED; if (cr != NULL) dev->si_cred = crhold(cr); @@ -756,7 +814,8 @@ make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode, res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt, ap); va_end(ap); - KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv")); + KASSERT(res == 0 && dev != NULL, + ("make_dev: failed make_dev_credv (error=%d)", res)); return (dev); } @@ -773,7 +832,7 @@ make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, va_end(ap); KASSERT(res == 0 && dev != NULL, - ("make_dev_cred: failed make_dev_credv")); + ("make_dev_cred: failed make_dev_credv (error=%d)", res)); return (dev); } @@ -790,8 +849,9 @@ make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, fmt, ap); va_end(ap); - KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, - ("make_dev_credf: failed make_dev_credv")); + KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || + ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, + ("make_dev_credf: failed make_dev_credv (error=%d)", res)); return (res == 0 ? dev : NULL); } @@ -807,8 +867,9 @@ make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw, fmt, ap); va_end(ap); - KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0, - ("make_dev_p: failed make_dev_credv")); + KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) || + ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0, + ("make_dev_p: failed make_dev_credv (error=%d)", res)); return (res); } @@ -836,21 +897,20 @@ make_dev_alias(struct cdev *pdev, const char *fmt, ...) { struct cdev *dev; va_list ap; - int i; + int error; KASSERT(pdev != NULL, ("NULL pdev")); dev = devfs_alloc(MAKEDEV_WAITOK); dev_lock(); dev->si_flags |= SI_ALIAS; - dev->si_flags |= SI_NAMED; va_start(ap, fmt); - i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); - if (i > (sizeof dev->__si_namebuf - 1)) { - printf("WARNING: Device name truncated! (%s)\n", - dev->__si_namebuf); - } + error = prep_devname(dev, fmt, ap); va_end(ap); - + if (error != 0) { + panic("make_dev_alias: bad si_name (error=%d, si_name=%s)", + error, dev->si_name); + } + dev->si_flags |= SI_NAMED; devfs_create(dev); dev_dependsl(pdev, dev); clean_unrhdrl(devfs_inos); diff --git a/sys/kern/kern_dtrace.c b/sys/kern/kern_dtrace.c index 145535201e2..603b4cf8c4e 100644 --- a/sys/kern/kern_dtrace.c +++ b/sys/kern/kern_dtrace.c @@ -39,9 +39,7 @@ __FBSDID("$FreeBSD$"); #include #define KDTRACE_PROC_SIZE 64 -#define KDTRACE_PROC_ZERO 8 #define KDTRACE_THREAD_SIZE 256 -#define KDTRACE_THREAD_ZERO 64 MALLOC_DEFINE(M_KDTRACE, "kdtrace", "DTrace hooks"); @@ -49,20 +47,21 @@ MALLOC_DEFINE(M_KDTRACE, "kdtrace", "DTrace hooks"); size_t kdtrace_proc_size() { - return(KDTRACE_PROC_SIZE); + + return (KDTRACE_PROC_SIZE); } static void kdtrace_proc_ctor(void *arg __unused, struct proc *p) { - p->p_dtrace = malloc(KDTRACE_PROC_SIZE, M_KDTRACE, M_WAITOK); - bzero(p->p_dtrace, KDTRACE_PROC_ZERO); + p->p_dtrace = malloc(KDTRACE_PROC_SIZE, M_KDTRACE, M_WAITOK|M_ZERO); } static void kdtrace_proc_dtor(void *arg __unused, struct proc *p) { + if (p->p_dtrace != NULL) { free(p->p_dtrace, M_KDTRACE); p->p_dtrace = NULL; @@ -73,20 +72,21 @@ kdtrace_proc_dtor(void *arg __unused, struct proc *p) size_t kdtrace_thread_size() { - return(KDTRACE_THREAD_SIZE); + + return (KDTRACE_THREAD_SIZE); } static void kdtrace_thread_ctor(void *arg __unused, struct thread *td) { - td->td_dtrace = malloc(KDTRACE_THREAD_SIZE, M_KDTRACE, M_WAITOK); - bzero(td->td_dtrace, KDTRACE_THREAD_ZERO); + td->td_dtrace = malloc(KDTRACE_THREAD_SIZE, M_KDTRACE, M_WAITOK|M_ZERO); } static void kdtrace_thread_dtor(void *arg __unused, struct thread *td) { + if (td->td_dtrace != NULL) { free(td->td_dtrace, M_KDTRACE); td->td_dtrace = NULL; @@ -99,10 +99,15 @@ kdtrace_thread_dtor(void *arg __unused, struct thread *td) static void init_dtrace(void *dummy __unused) { - EVENTHANDLER_REGISTER(process_ctor, kdtrace_proc_ctor, NULL, EVENTHANDLER_PRI_ANY); - EVENTHANDLER_REGISTER(process_dtor, kdtrace_proc_dtor, NULL, EVENTHANDLER_PRI_ANY); - EVENTHANDLER_REGISTER(thread_ctor, kdtrace_thread_ctor, NULL, EVENTHANDLER_PRI_ANY); - EVENTHANDLER_REGISTER(thread_dtor, kdtrace_thread_dtor, NULL, EVENTHANDLER_PRI_ANY); + + EVENTHANDLER_REGISTER(process_ctor, kdtrace_proc_ctor, NULL, + EVENTHANDLER_PRI_ANY); + EVENTHANDLER_REGISTER(process_dtor, kdtrace_proc_dtor, NULL, + EVENTHANDLER_PRI_ANY); + EVENTHANDLER_REGISTER(thread_ctor, kdtrace_thread_ctor, NULL, + EVENTHANDLER_PRI_ANY); + EVENTHANDLER_REGISTER(thread_dtor, kdtrace_thread_dtor, NULL, + EVENTHANDLER_PRI_ANY); } SYSINIT(kdtrace, SI_SUB_KDTRACE, SI_ORDER_FIRST, init_dtrace, NULL); diff --git a/sys/kern/kern_et.c b/sys/kern/kern_et.c index 72888aed76c..8c375561c42 100644 --- a/sys/kern/kern_et.c +++ b/sys/kern/kern_et.c @@ -38,7 +38,7 @@ SLIST_HEAD(et_eventtimers_list, eventtimer); static struct et_eventtimers_list eventtimers = SLIST_HEAD_INITIALIZER(et_eventtimers); struct mtx et_eventtimers_mtx; -MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_SPIN); +MTX_SYSINIT(et_eventtimers_init, &et_eventtimers_mtx, "et_mtx", MTX_DEF); SYSCTL_NODE(_kern, OID_AUTO, eventtimer, CTLFLAG_RW, 0, "Event timers"); SYSCTL_NODE(_kern_eventtimer, OID_AUTO, et, CTLFLAG_RW, 0, ""); @@ -52,9 +52,15 @@ et_register(struct eventtimer *et) struct eventtimer *tmp, *next; if (et->et_quality >= 0 || bootverbose) { - printf("Event timer \"%s\" frequency %ju Hz quality %d\n", - et->et_name, (uintmax_t)et->et_frequency, - et->et_quality); + if (et->et_frequency == 0) { + printf("Event timer \"%s\" quality %d\n", + et->et_name, et->et_quality); + } else { + printf("Event timer \"%s\" " + "frequency %ju Hz quality %d\n", + et->et_name, (uintmax_t)et->et_frequency, + et->et_quality); + } } et->et_sysctl = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(_kern_eventtimer_et), OID_AUTO, et->et_name, @@ -235,6 +241,7 @@ sysctl_kern_eventtimer_choice(SYSCTL_HANDLER_ARGS) spc = ""; error = 0; + buf[0] = 0; off = 0; ET_LOCK(); SLIST_FOREACH(et, &eventtimers, et_all) { diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c60e3294dd9..1e4d690b729 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -91,11 +91,11 @@ dtrace_execexit_func_t dtrace_fasttrap_exec; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE(proc, kernel, , exec); +SDT_PROBE_DEFINE(proc, kernel, , exec, exec); SDT_PROBE_ARGTYPE(proc, kernel, , exec, 0, "char *"); -SDT_PROBE_DEFINE(proc, kernel, , exec_failure); +SDT_PROBE_DEFINE(proc, kernel, , exec_failure, exec-failure); SDT_PROBE_ARGTYPE(proc, kernel, , exec_failure, 0, "int"); -SDT_PROBE_DEFINE(proc, kernel, , exec_success); +SDT_PROBE_DEFINE(proc, kernel, , exec_success, exec-success); SDT_PROBE_ARGTYPE(proc, kernel, , exec_success, 0, "char *"); MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments"); @@ -385,6 +385,10 @@ do_execve(td, args, mac_p) imgp->args = args; imgp->execpath = imgp->freepath = NULL; imgp->execpathp = 0; + imgp->canary = 0; + imgp->canarylen = 0; + imgp->pagesizes = 0; + imgp->pagesizeslen = 0; #ifdef MAC error = mac_execve_enter(imgp, mac_p); @@ -651,16 +655,8 @@ interpret: setsugid(p); #ifdef KTRACE - if (p->p_tracevp != NULL && - priv_check_cred(oldcred, PRIV_DEBUG_DIFFCRED, 0)) { - mtx_lock(&ktrace_mtx); - p->p_traceflag = 0; - tracevp = p->p_tracevp; - p->p_tracevp = NULL; - tracecred = p->p_tracecred; - p->p_tracecred = NULL; - mtx_unlock(&ktrace_mtx); - } + if (priv_check_cred(oldcred, PRIV_DEBUG_DIFFCRED, 0)) + ktrprocexec(p, &tracecred, &tracevp); #endif /* * Close any file descriptors 0..2 that reference procfs, @@ -1197,8 +1193,10 @@ exec_copyout_strings(imgp) struct ps_strings *arginfo; struct proc *p; size_t execpath_len; - int szsigcode; + int szsigcode, szps; + char canary[sizeof(long) * 8]; + szps = sizeof(pagesizes[0]) * MAXPAGESIZES; /* * Calculate string base and vector table pointers. * Also deal with signal trampoline code for this exec type. @@ -1214,6 +1212,8 @@ exec_copyout_strings(imgp) szsigcode = *(p->p_sysent->sv_szsigcode); destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE - roundup(execpath_len, sizeof(char *)) - + roundup(sizeof(canary), sizeof(char *)) - + roundup(szps, sizeof(char *)) - roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *)); /* @@ -1232,6 +1232,23 @@ exec_copyout_strings(imgp) execpath_len); } + /* + * Prepare the canary for SSP. + */ + arc4rand(canary, sizeof(canary), 0); + imgp->canary = (uintptr_t)arginfo - szsigcode - execpath_len - + sizeof(canary); + copyout(canary, (void *)imgp->canary, sizeof(canary)); + imgp->canarylen = sizeof(canary); + + /* + * Prepare the pagesizes array. + */ + imgp->pagesizes = (uintptr_t)arginfo - szsigcode - execpath_len - + roundup(sizeof(canary), sizeof(char *)) - szps; + copyout(pagesizes, (void *)imgp->pagesizes, szps); + imgp->pagesizeslen = szps; + /* * If we have a valid auxargs ptr, prepare some room * on the stack. @@ -1249,8 +1266,8 @@ exec_copyout_strings(imgp) * for argument of Runtime loader. */ vectp = (char **)(destp - (imgp->args->argc + - imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) * - sizeof(char *)); + imgp->args->envc + 2 + imgp->auxarg_size) + * sizeof(char *)); } else { /* * The '+ 2' is for the null pointers at the end of each of @@ -1338,17 +1355,17 @@ exec_check_permissions(imgp) if (error) return (error); #endif - + /* - * 1) Check if file execution is disabled for the filesystem that this - * file resides on. - * 2) Insure that at least one execute bit is on - otherwise root - * will always succeed, and we don't want to happen unless the - * file really is executable. - * 3) Insure that the file is a regular file. + * 1) Check if file execution is disabled for the filesystem that + * this file resides on. + * 2) Ensure that at least one execute bit is on. Otherwise, a + * privileged user will always succeed, and we don't want this + * to happen unless the file really is executable. + * 3) Ensure that the file is a regular file. */ if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || - ((attr->va_mode & 0111) == 0) || + (attr->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0 || (attr->va_type != VREG)) return (EACCES); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index a781f8bf87f..31389e13126 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -90,7 +90,7 @@ dtrace_execexit_func_t dtrace_fasttrap_exit; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE(proc, kernel, , exit); +SDT_PROBE_DEFINE(proc, kernel, , exit, exit); SDT_PROBE_ARGTYPE(proc, kernel, , exit, 0, "int"); /* Required to be non-static for SysVR4 emulator */ @@ -121,10 +121,6 @@ exit1(struct thread *td, int rv) struct proc *p, *nq, *q; struct vnode *vtmp; struct vnode *ttyvp = NULL; -#ifdef KTRACE - struct vnode *tracevp; - struct ucred *tracecred; -#endif struct plimit *plim; int locked; @@ -356,33 +352,7 @@ exit1(struct thread *td, int rv) if (ttyvp != NULL) vrele(ttyvp); #ifdef KTRACE - /* - * Disable tracing, then drain any pending records and release - * the trace file. - */ - if (p->p_traceflag != 0) { - PROC_LOCK(p); - mtx_lock(&ktrace_mtx); - p->p_traceflag = 0; - mtx_unlock(&ktrace_mtx); - PROC_UNLOCK(p); - ktrprocexit(td); - PROC_LOCK(p); - mtx_lock(&ktrace_mtx); - tracevp = p->p_tracevp; - p->p_tracevp = NULL; - tracecred = p->p_tracecred; - p->p_tracecred = NULL; - mtx_unlock(&ktrace_mtx); - PROC_UNLOCK(p); - if (tracevp != NULL) { - locked = VFS_LOCK_GIANT(tracevp->v_mount); - vrele(tracevp); - VFS_UNLOCK_GIANT(locked); - } - if (tracecred != NULL) - crfree(tracecred); - } + ktrprocexit(td); #endif /* * Release reference to text vnode @@ -403,6 +373,8 @@ exit1(struct thread *td, int rv) PROC_UNLOCK(p); lim_free(plim); + tidhash_remove(td); + /* * Remove proc from allproc queue and pidhash chain. * Place onto zombproc. Unlink from parent's child list. diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 03d8cbc6bc1..126c668f12c 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -84,7 +84,7 @@ dtrace_fork_func_t dtrace_fasttrap_fork; #endif SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE(proc, kernel, , create); +SDT_PROBE_DEFINE(proc, kernel, , create, create); SDT_PROBE_ARGTYPE(proc, kernel, , create, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, , create, 1, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, , create, 2, "int"); @@ -456,7 +456,7 @@ again: AUDIT_ARG_PID(p2->p_pid); LIST_INSERT_HEAD(&allproc, p2, p_list); LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); - + tidhash_add(td2); PROC_LOCK(p2); PROC_LOCK(p1); @@ -645,21 +645,7 @@ again: callout_init(&p2->p_itcallout, CALLOUT_MPSAFE); #ifdef KTRACE - /* - * Copy traceflag and tracefile if enabled. - */ - mtx_lock(&ktrace_mtx); - KASSERT(p2->p_tracevp == NULL, ("new process has a ktrace vnode")); - if (p1->p_traceflag & KTRFAC_INHERIT) { - p2->p_traceflag = p1->p_traceflag; - if ((p2->p_tracevp = p1->p_tracevp) != NULL) { - VREF(p2->p_tracevp); - KASSERT(p1->p_tracecred != NULL, - ("ktrace vnode with no cred")); - p2->p_tracecred = crhold(p1->p_tracecred); - } - } - mtx_unlock(&ktrace_mtx); + ktrprocfork(p1, p2); #endif /* @@ -671,15 +657,6 @@ again: p2->p_pfsflags = p1->p_pfsflags; } -#ifdef KDTRACE_HOOKS - /* - * Tell the DTrace fasttrap provider about the new process - * if it has registered an interest. - */ - if (dtrace_fasttrap_fork) - dtrace_fasttrap_fork(p1, p2); -#endif - /* * This begins the section where we must prevent the parent * from being swapped. @@ -744,6 +721,21 @@ again: PROC_SLOCK(p2); p2->p_state = PRS_NORMAL; PROC_SUNLOCK(p2); +#ifdef KDTRACE_HOOKS + /* + * Tell the DTrace fasttrap provider about the new process + * if it has registered an interest. We have to do this only after + * p_state is PRS_NORMAL since the fasttrap module will use pfind() + * later on. + */ + if (dtrace_fasttrap_fork) { + PROC_LOCK(p1); + PROC_LOCK(p2); + dtrace_fasttrap_fork(p1, p2); + PROC_UNLOCK(p2); + PROC_UNLOCK(p1); + } +#endif /* * If RFSTOPPED not requested, make child runnable and add to diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index ded2379acbf..4882e8e83eb 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -584,12 +584,15 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) gotchildmax = 1; error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); - gotenforce = (error == 0); - if (gotenforce) { - if (enforce < 0 || enforce > 2) - return (EINVAL); - } else if (error != ENOENT) + if (error == ENOENT) + gotenforce = 0; + else if (error != 0) goto done_free; + else if (enforce < 0 || enforce > 2) { + error = EINVAL; + goto done_free; + } else + gotenforce = 1; pr_flags = ch_flags = 0; for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]); diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c index 264fc4a9f65..be40c80e9a8 100644 --- a/sys/kern/kern_kthread.c +++ b/sys/kern/kern_kthread.c @@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -295,6 +296,7 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p, thread_unlock(oldtd); PROC_UNLOCK(p); + tidhash_add(newtd); /* Delay putting it on the run queue until now. */ if (!(flags & RFSTOPPED)) { @@ -314,15 +316,20 @@ kthread_exit(void) p = curthread->td_proc; + /* A module may be waiting for us to exit. */ wakeup(curthread); + rw_wlock(&tidhash_lock); PROC_LOCK(p); if (p->p_numthreads == 1) { PROC_UNLOCK(p); + rw_wunlock(&tidhash_lock); kproc_exit(0); /* NOTREACHED. */ } + LIST_REMOVE(curthread, td_hash); + rw_wunlock(&tidhash_lock); PROC_SLOCK(p); thread_exit(); } diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index d5eb4e1cb5a..6e2285b391c 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -107,7 +107,7 @@ static int data_lengths[] = { 0, /* KTR_NAMEI */ sizeof(struct ktr_genio), /* KTR_GENIO */ sizeof(struct ktr_psig), /* KTR_PSIG */ - sizeof(struct ktr_csw), /* KTR_CSW */ + sizeof(struct ktr_csw), /* KTR_CSW */ 0, /* KTR_USER */ 0, /* KTR_STRUCT */ 0, /* KTR_SYSCTL */ @@ -126,7 +126,7 @@ SYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RW, &ktr_geniosize, 0, "Maximum size of genio event payload"); static int print_message = 1; -struct mtx ktrace_mtx; +static struct mtx ktrace_mtx; static struct sx ktrace_sx; static void ktrace_init(void *dummy); @@ -134,7 +134,10 @@ static int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS); static u_int ktrace_resize_pool(u_int newsize); static struct ktr_request *ktr_getrequest(int type); static void ktr_submitrequest(struct thread *td, struct ktr_request *req); +static void ktr_freeproc(struct proc *p, struct ucred **uc, + struct vnode **vp); static void ktr_freerequest(struct ktr_request *req); +static void ktr_freerequest_locked(struct ktr_request *req); static void ktr_writerequest(struct thread *td, struct ktr_request *req); static int ktrcanset(struct thread *,struct proc *); static int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *); @@ -336,7 +339,7 @@ ktr_drain(struct thread *td) ktrace_assert(td); sx_assert(&ktrace_sx, SX_XLOCKED); - STAILQ_INIT(&local_queue); /* XXXRW: needed? */ + STAILQ_INIT(&local_queue); if (!STAILQ_EMPTY(&td->td_proc->p_ktr)) { mtx_lock(&ktrace_mtx); @@ -375,11 +378,43 @@ static void ktr_freerequest(struct ktr_request *req) { + mtx_lock(&ktrace_mtx); + ktr_freerequest_locked(req); + mtx_unlock(&ktrace_mtx); +} + +static void +ktr_freerequest_locked(struct ktr_request *req) +{ + + mtx_assert(&ktrace_mtx, MA_OWNED); if (req->ktr_buffer != NULL) free(req->ktr_buffer, M_KTRACE); - mtx_lock(&ktrace_mtx); STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list); - mtx_unlock(&ktrace_mtx); +} + +/* + * Disable tracing for a process and release all associated resources. + * The caller is responsible for releasing a reference on the returned + * vnode and credentials. + */ +static void +ktr_freeproc(struct proc *p, struct ucred **uc, struct vnode **vp) +{ + struct ktr_request *req; + + PROC_LOCK_ASSERT(p, MA_OWNED); + mtx_assert(&ktrace_mtx, MA_OWNED); + *uc = p->p_tracecred; + p->p_tracecred = NULL; + if (vp != NULL) + *vp = p->p_tracevp; + p->p_tracevp = NULL; + p->p_traceflag = 0; + while ((req = STAILQ_FIRST(&p->p_ktr)) != NULL) { + STAILQ_REMOVE_HEAD(&p->p_ktr, ktr_list); + ktr_freerequest_locked(req); + } } void @@ -432,19 +467,78 @@ ktrsysret(code, error, retval) } /* - * When a process exits, drain per-process asynchronous trace records. + * When a setuid process execs, disable tracing. + * + * XXX: We toss any pending asynchronous records. + */ +void +ktrprocexec(struct proc *p, struct ucred **uc, struct vnode **vp) +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + mtx_lock(&ktrace_mtx); + ktr_freeproc(p, uc, vp); + mtx_unlock(&ktrace_mtx); +} + +/* + * When a process exits, drain per-process asynchronous trace records + * and disable tracing. */ void ktrprocexit(struct thread *td) { + struct proc *p; + struct ucred *cred; + struct vnode *vp; + int vfslocked; + + p = td->td_proc; + if (p->p_traceflag == 0) + return; ktrace_enter(td); sx_xlock(&ktrace_sx); ktr_drain(td); sx_xunlock(&ktrace_sx); + PROC_LOCK(p); + mtx_lock(&ktrace_mtx); + ktr_freeproc(p, &cred, &vp); + mtx_unlock(&ktrace_mtx); + PROC_UNLOCK(p); + if (vp != NULL) { + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + vrele(vp); + VFS_UNLOCK_GIANT(vfslocked); + } + if (cred != NULL) + crfree(cred); ktrace_exit(td); } +/* + * When a process forks, enable tracing in the new process if needed. + */ +void +ktrprocfork(struct proc *p1, struct proc *p2) +{ + + PROC_LOCK_ASSERT(p1, MA_OWNED); + PROC_LOCK_ASSERT(p2, MA_OWNED); + mtx_lock(&ktrace_mtx); + KASSERT(p2->p_tracevp == NULL, ("new process has a ktrace vnode")); + if (p1->p_traceflag & KTRFAC_INHERIT) { + p2->p_traceflag = p1->p_traceflag; + if ((p2->p_tracevp = p1->p_tracevp) != NULL) { + VREF(p2->p_tracevp); + KASSERT(p1->p_tracecred != NULL, + ("ktrace vnode with no cred")); + p2->p_tracecred = crhold(p1->p_tracecred); + } + } + mtx_unlock(&ktrace_mtx); +} + /* * When a thread returns, drain any asynchronous records generated by the * system call. @@ -694,10 +788,7 @@ ktrace(td, uap) if (p->p_tracevp == vp) { if (ktrcanset(td, p)) { mtx_lock(&ktrace_mtx); - cred = p->p_tracecred; - p->p_tracecred = NULL; - p->p_tracevp = NULL; - p->p_traceflag = 0; + ktr_freeproc(p, &cred, NULL); mtx_unlock(&ktrace_mtx); vrele_count++; crfree(cred); @@ -741,7 +832,6 @@ ktrace(td, uap) PROC_UNLOCK(p); continue; } - PROC_UNLOCK(p); nfound++; if (descend) ret |= ktrsetchildren(td, p, ops, facs, vp); @@ -758,18 +848,13 @@ ktrace(td, uap) * by pid */ p = pfind(uap->pid); - if (p == NULL) { - sx_sunlock(&proctree_lock); + if (p == NULL) error = ESRCH; - goto done; - } - error = p_cansee(td, p); - /* - * The slock of the proctree lock will keep this process - * from going away, so unlocking the proc here is ok. - */ - PROC_UNLOCK(p); + else + error = p_cansee(td, p); if (error) { + if (p != NULL) + PROC_UNLOCK(p); sx_sunlock(&proctree_lock); goto done; } @@ -841,11 +926,16 @@ ktrops(td, p, ops, facs, vp) struct vnode *tracevp = NULL; struct ucred *tracecred = NULL; - PROC_LOCK(p); + PROC_LOCK_ASSERT(p, MA_OWNED); if (!ktrcanset(td, p)) { PROC_UNLOCK(p); return (0); } + if (p->p_flag & P_WEXIT) { + /* If the process is exiting, just ignore it. */ + PROC_UNLOCK(p); + return (1); + } mtx_lock(&ktrace_mtx); if (ops == KTROP_SET) { if (p->p_tracevp != vp) { @@ -865,14 +955,9 @@ ktrops(td, p, ops, facs, vp) p->p_traceflag |= KTRFAC_ROOT; } else { /* KTROP_CLEAR */ - if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { + if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) /* no more tracing */ - p->p_traceflag = 0; - tracevp = p->p_tracevp; - p->p_tracevp = NULL; - tracecred = p->p_tracecred; - p->p_tracecred = NULL; - } + ktr_freeproc(p, &tracecred, &tracevp); } mtx_unlock(&ktrace_mtx); PROC_UNLOCK(p); @@ -900,6 +985,7 @@ ktrsetchildren(td, top, ops, facs, vp) register int ret = 0; p = top; + PROC_LOCK_ASSERT(p, MA_OWNED); sx_assert(&proctree_lock, SX_LOCKED); for (;;) { ret |= ktrops(td, p, ops, facs, vp); @@ -919,6 +1005,7 @@ ktrsetchildren(td, top, ops, facs, vp) } p = p->p_pptr; } + PROC_LOCK(p); } /*NOTREACHED*/ } @@ -1035,10 +1122,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req) PROC_LOCK(p); if (p->p_tracevp == vp) { mtx_lock(&ktrace_mtx); - p->p_tracevp = NULL; - p->p_traceflag = 0; - cred = p->p_tracecred; - p->p_tracecred = NULL; + ktr_freeproc(p, &cred, NULL); mtx_unlock(&ktrace_mtx); vrele_count++; } @@ -1050,11 +1134,6 @@ ktr_writerequest(struct thread *td, struct ktr_request *req) } sx_sunlock(&allproc_lock); - /* - * We can't clear any pending requests in threads that have cached - * them but not yet committed them, as those are per-thread. The - * thread will have to clear it itself on system call return. - */ vfslocked = VFS_LOCK_GIANT(vp->v_mount); while (vrele_count-- > 0) vrele(vp); diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index dd293023494..43ccd74c31d 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -924,7 +924,6 @@ linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, return (0); } -#ifdef DDB /* * DDB Helpers. DDB has to look across multiple files with their own symbol * tables and string tables. @@ -933,12 +932,14 @@ linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, * DDB to hang because somebody's got the lock held. We'll take the chance * that the files list is inconsistant instead. */ +#ifdef DDB int linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) { return (linker_debug_lookup(symstr, sym)); } +#endif int linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) @@ -961,7 +962,6 @@ linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, return (linker_debug_search_symbol_name(value, buf, buflen, offset)); } -#endif /* * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index 18bbf9a46cf..c9829cdf5ca 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -396,6 +396,34 @@ lockinit(struct lock *lk, int pri, const char *wmesg, int timo, int flags) STACK_ZERO(lk); } +/* + * XXX: Gross hacks to manipulate external lock flags after + * initialization. Used for certain vnode and buf locks. + */ +void +lockallowshare(struct lock *lk) +{ + + lockmgr_assert(lk, KA_XLOCKED); + lk->lock_object.lo_flags &= ~LK_NOSHARE; +} + +void +lockallowrecurse(struct lock *lk) +{ + + lockmgr_assert(lk, KA_XLOCKED); + lk->lock_object.lo_flags |= LO_RECURSABLE; +} + +void +lockdisablerecurse(struct lock *lk) +{ + + lockmgr_assert(lk, KA_XLOCKED); + lk->lock_object.lo_flags &= ~LO_RECURSABLE; +} + void lockdestroy(struct lock *lk) { diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 00df9dd3ee4..9c7ff403e64 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -187,21 +187,31 @@ struct { static uma_zone_t mt_zone; u_long vm_kmem_size; -SYSCTL_ULONG(_vm, OID_AUTO, kmem_size, CTLFLAG_RD, &vm_kmem_size, 0, +SYSCTL_ULONG(_vm, OID_AUTO, kmem_size, CTLFLAG_RDTUN, &vm_kmem_size, 0, "Size of kernel memory"); static u_long vm_kmem_size_min; -SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_min, CTLFLAG_RD, &vm_kmem_size_min, 0, +SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_min, CTLFLAG_RDTUN, &vm_kmem_size_min, 0, "Minimum size of kernel memory"); static u_long vm_kmem_size_max; -SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_max, CTLFLAG_RD, &vm_kmem_size_max, 0, +SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_max, CTLFLAG_RDTUN, &vm_kmem_size_max, 0, "Maximum size of kernel memory"); static u_int vm_kmem_size_scale; -SYSCTL_UINT(_vm, OID_AUTO, kmem_size_scale, CTLFLAG_RD, &vm_kmem_size_scale, 0, +SYSCTL_UINT(_vm, OID_AUTO, kmem_size_scale, CTLFLAG_RDTUN, &vm_kmem_size_scale, 0, "Scale factor for kernel memory size"); +static int sysctl_kmem_map_size(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_vm, OID_AUTO, kmem_map_size, + CTLFLAG_RD | CTLTYPE_ULONG | CTLFLAG_MPSAFE, NULL, 0, + sysctl_kmem_map_size, "LU", "Current kmem_map allocation size"); + +static int sysctl_kmem_map_free(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_vm, OID_AUTO, kmem_map_free, + CTLFLAG_RD | CTLTYPE_ULONG | CTLFLAG_MPSAFE, NULL, 0, + sysctl_kmem_map_free, "LU", "Largest contiguous free range in kmem_map"); + /* * The malloc_mtx protects the kmemstatistics linked list. */ @@ -240,6 +250,27 @@ SYSCTL_INT(_debug_malloc, OID_AUTO, failure_count, CTLFLAG_RD, &malloc_failure_count, 0, "Number of imposed M_NOWAIT malloc failures"); #endif +static int +sysctl_kmem_map_size(SYSCTL_HANDLER_ARGS) +{ + u_long size; + + size = kmem_map->size; + return (sysctl_handle_long(oidp, &size, 0, req)); +} + +static int +sysctl_kmem_map_free(SYSCTL_HANDLER_ARGS) +{ + u_long size; + + vm_map_lock_read(kmem_map); + size = kmem_map->root != NULL ? + kmem_map->root->max_free : kmem_map->size; + vm_map_unlock_read(kmem_map); + return (sysctl_handle_long(oidp, &size, 0, req)); +} + /* * malloc(9) uma zone separation -- sub-page buffer overruns in one * malloc type will affect only a subset of other malloc types. @@ -566,11 +597,8 @@ realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags) */ #ifdef DEBUG_MEMGUARD - if (is_memguard_addr(addr)) { - slab = NULL; - alloc = size; - goto remalloc; - } + if (is_memguard_addr(addr)) + return (memguard_realloc(addr, size, mtp, flags)); #endif #ifdef DEBUG_REDZONE @@ -595,10 +623,6 @@ realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags) return (addr); #endif /* !DEBUG_REDZONE */ -#ifdef DEBUG_MEMGUARD -remalloc: -#endif - /* Allocate a new, bigger (or smaller) block */ if ((newaddr = malloc(size, mtp, flags)) == NULL) return (NULL); @@ -835,25 +859,11 @@ sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) struct malloc_type_internal *mtip; struct malloc_type_header mth; struct malloc_type *mtp; - int buflen, count, error, i; + int error, i; struct sbuf sbuf; - char *buffer; + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); mtx_lock(&malloc_mtx); -restart: - mtx_assert(&malloc_mtx, MA_OWNED); - count = kmemcount; - mtx_unlock(&malloc_mtx); - buflen = sizeof(mtsh) + count * (sizeof(mth) + - sizeof(struct malloc_type_stats) * MAXCPU) + 1; - buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - mtx_lock(&malloc_mtx); - if (count < kmemcount) { - free(buffer, M_TEMP); - goto restart; - } - - sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN); /* * Insert stream header. @@ -862,11 +872,7 @@ restart: mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION; mtsh.mtsh_maxcpus = MAXCPU; mtsh.mtsh_count = kmemcount; - if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)); /* * Insert alternating sequence of type headers and type statistics. @@ -879,30 +885,19 @@ restart: */ bzero(&mth, sizeof(mth)); strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME); - if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mth, sizeof(mth)); /* * Insert type statistics for each CPU. */ for (i = 0; i < MAXCPU; i++) { - if (sbuf_bcat(&sbuf, &mtip->mti_stats[i], - sizeof(mtip->mti_stats[i])) < 0) { - mtx_unlock(&malloc_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &mtip->mti_stats[i], + sizeof(mtip->mti_stats[i])); } } mtx_unlock(&malloc_mtx); - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); -out: + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(buffer, M_TEMP); return (error); } @@ -1012,26 +1007,19 @@ DB_SHOW_COMMAND(multizone_matches, db_show_multizone_matches) static int sysctl_kern_mprof(SYSCTL_HANDLER_ARGS) { - int linesize = 64; struct sbuf sbuf; uint64_t count; uint64_t waste; uint64_t mem; - int bufsize; int error; - char *buf; int rsize; int size; int i; - bufsize = linesize * (KMEM_ZSIZE + 1); - bufsize += 128; /* For the stats line */ - bufsize += 128; /* For the banner line */ waste = 0; mem = 0; - buf = malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO); - sbuf_new(&sbuf, buf, bufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); sbuf_printf(&sbuf, "\n Size Requests Real Size\n"); for (i = 0; i < KMEM_ZSIZE; i++) { @@ -1049,12 +1037,8 @@ sysctl_kern_mprof(SYSCTL_HANDLER_ARGS) sbuf_printf(&sbuf, "\nTotal memory used:\t%30llu\nTotal Memory wasted:\t%30llu\n", (unsigned long long)mem, (unsigned long long)waste); - sbuf_finish(&sbuf); - - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); - + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(buf, M_TEMP); return (error); } diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index c427ac45134..f817613014a 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -1035,5 +1035,5 @@ start_periodic_resettodr(void *arg __unused) periodic_resettodr, NULL); } -SYSINIT(periodic_resettodr, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY - 1, +SYSINIT(periodic_resettodr, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, start_periodic_resettodr, NULL); diff --git a/sys/kern/kern_priv.c b/sys/kern/kern_priv.c index 352e502338d..fd3a95c5759 100644 --- a/sys/kern/kern_priv.c +++ b/sys/kern/kern_priv.c @@ -60,8 +60,8 @@ SYSCTL_INT(_security_bsd, OID_AUTO, suser_enabled, CTLFLAG_RW, TUNABLE_INT("security.bsd.suser_enabled", &suser_enabled); SDT_PROVIDER_DEFINE(priv); -SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv_ok, "int"); -SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv_err, "int"); +SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv_ok, priv-ok, "int"); +SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv_err, priv-err, "int"); /* * Check a credential for privilege. Lots of good reasons to deny privilege; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index beab035fb88..286ba2e609f 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -64,10 +64,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#include -#endif #ifdef DDB #include @@ -86,30 +82,30 @@ __FBSDID("$FreeBSD$"); #endif SDT_PROVIDER_DEFINE(proc); -SDT_PROBE_DEFINE(proc, kernel, ctor, entry); +SDT_PROBE_DEFINE(proc, kernel, ctor, entry, entry); SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 2, "void *"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 3, "int"); -SDT_PROBE_DEFINE(proc, kernel, ctor, return); +SDT_PROBE_DEFINE(proc, kernel, ctor, return, return); SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 2, "void *"); SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 3, "int"); -SDT_PROBE_DEFINE(proc, kernel, dtor, entry); +SDT_PROBE_DEFINE(proc, kernel, dtor, entry, entry); SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 2, "void *"); SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 3, "struct thread *"); -SDT_PROBE_DEFINE(proc, kernel, dtor, return); +SDT_PROBE_DEFINE(proc, kernel, dtor, return, return); SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 2, "void *"); -SDT_PROBE_DEFINE(proc, kernel, init, entry); +SDT_PROBE_DEFINE(proc, kernel, init, entry, entry); SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 2, "int"); -SDT_PROBE_DEFINE(proc, kernel, init, return); +SDT_PROBE_DEFINE(proc, kernel, init, return, return); SDT_PROBE_ARGTYPE(proc, kernel, init, return, 0, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, init, return, 1, "int"); SDT_PROBE_ARGTYPE(proc, kernel, init, return, 2, "int"); @@ -717,9 +713,7 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp) kp->ki_textvp = p->p_textvp; #ifdef KTRACE kp->ki_tracep = p->p_tracevp; - mtx_lock(&ktrace_mtx); kp->ki_traceflag = p->p_traceflag; - mtx_unlock(&ktrace_mtx); #endif kp->ki_fd = p->p_fd; kp->ki_vmspace = p->p_vmspace; @@ -848,6 +842,7 @@ fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, int preferthread) struct proc *p; p = td->td_proc; + kp->ki_tdaddr = td; PROC_LOCK_ASSERT(p, MA_OWNED); thread_lock(td); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index ec2d6b61a73..0da0075e6b0 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -295,25 +295,23 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap) else cierror = 0; - /* - * Though lwpid is unique, only current process is supported - * since there is no efficient way to look up a LWP yet. - */ - p = td->td_proc; - PROC_LOCK(p); + if (uap->lwpid == 0 || uap->lwpid == td->td_tid) { + p = td->td_proc; + td1 = td; + PROC_LOCK(p); + } else { + /* Only look up thread in current process */ + td1 = tdfind(uap->lwpid, curproc->p_pid); + if (td1 == NULL) + return (ESRCH); + p = td1->td_proc; + } switch (uap->function) { case RTP_LOOKUP: if ((error = p_cansee(td, p))) break; - if (uap->lwpid == 0 || uap->lwpid == td->td_tid) - td1 = td; - else - td1 = thread_find(p, uap->lwpid); - if (td1 != NULL) - pri_to_rtp(td1, &rtp); - else - error = ESRCH; + pri_to_rtp(td1, &rtp); PROC_UNLOCK(p); return (copyout(&rtp, uap->rtp, sizeof(struct rtprio))); case RTP_SET: @@ -337,15 +335,7 @@ rtprio_thread(struct thread *td, struct rtprio_thread_args *uap) if (error) break; } - - if (uap->lwpid == 0 || uap->lwpid == td->td_tid) - td1 = td; - else - td1 = thread_find(p, uap->lwpid); - if (td1 != NULL) - error = rtp_to_pri(&rtp, td1); - else - error = ESRCH; + error = rtp_to_pri(&rtp, td1); break; default: error = EINVAL; @@ -709,8 +699,8 @@ kern_setrlimit(td, which, limp) if (limp->rlim_max > maxssiz) limp->rlim_max = maxssiz; oldssiz = *alimp; - if (td->td_proc->p_sysent->sv_fixlimit != NULL) - td->td_proc->p_sysent->sv_fixlimit(&oldssiz, + if (p->p_sysent->sv_fixlimit != NULL) + p->p_sysent->sv_fixlimit(&oldssiz, RLIMIT_STACK); break; @@ -732,8 +722,8 @@ kern_setrlimit(td, which, limp) limp->rlim_max = 1; break; } - if (td->td_proc->p_sysent->sv_fixlimit != NULL) - td->td_proc->p_sysent->sv_fixlimit(limp, which); + if (p->p_sysent->sv_fixlimit != NULL) + p->p_sysent->sv_fixlimit(limp, which); *alimp = *limp; p->p_limit = newlim; PROC_UNLOCK(p); diff --git a/sys/kern/kern_rmlock.c b/sys/kern/kern_rmlock.c index a6a622e141f..0ab5d744a5f 100644 --- a/sys/kern/kern_rmlock.c +++ b/sys/kern/kern_rmlock.c @@ -187,6 +187,8 @@ rm_cleanIPI(void *arg) } } +CTASSERT((RM_SLEEPABLE & LO_CLASSFLAGS) == RM_SLEEPABLE); + void rm_init_flags(struct rmlock *rm, const char *name, int opts) { @@ -197,9 +199,13 @@ rm_init_flags(struct rmlock *rm, const char *name, int opts) liflags |= LO_WITNESS; if (opts & RM_RECURSE) liflags |= LO_RECURSABLE; - rm->rm_noreadtoken = 1; + rm->rm_writecpus = all_cpus; LIST_INIT(&rm->rm_activeReaders); - mtx_init(&rm->rm_lock, name, "rmlock_mtx", MTX_NOWITNESS); + if (opts & RM_SLEEPABLE) { + liflags |= RM_SLEEPABLE; + sx_init_flags(&rm->rm_lock_sx, "rmlock_sx", SX_RECURSE); + } else + mtx_init(&rm->rm_lock_mtx, name, "rmlock_mtx", MTX_NOWITNESS); lock_init(&rm->lock_object, &lock_class_rm, name, NULL, liflags); } @@ -214,7 +220,10 @@ void rm_destroy(struct rmlock *rm) { - mtx_destroy(&rm->rm_lock); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + sx_destroy(&rm->rm_lock_sx); + else + mtx_destroy(&rm->rm_lock_mtx); lock_destroy(&rm->lock_object); } @@ -222,7 +231,10 @@ int rm_wowned(struct rmlock *rm) { - return (mtx_owned(&rm->rm_lock)); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + return (sx_xlocked(&rm->rm_lock_sx)); + else + return (mtx_owned(&rm->rm_lock_mtx)); } void @@ -241,8 +253,8 @@ rm_sysinit_flags(void *arg) rm_init_flags(args->ra_rm, args->ra_desc, args->ra_opts); } -static void -_rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker) +static int +_rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) { struct pcpu *pc; struct rm_queue *queue; @@ -252,9 +264,9 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker) pc = pcpu_find(curcpu); /* Check if we just need to do a proper critical_exit. */ - if (0 == rm->rm_noreadtoken) { + if (!(pc->pc_cpumask & rm->rm_writecpus)) { critical_exit(); - return; + return (1); } /* Remove our tracker from the per-cpu list. */ @@ -265,7 +277,7 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker) /* Just add back tracker - we hold the lock. */ rm_tracker_add(pc, tracker); critical_exit(); - return; + return (1); } /* @@ -289,7 +301,7 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker) mtx_unlock_spin(&rm_spinlock); rm_tracker_add(pc, tracker); critical_exit(); - return; + return (1); } } } @@ -297,20 +309,38 @@ _rm_rlock_hard(struct rmlock *rm, struct rm_priotracker *tracker) sched_unpin(); critical_exit(); - mtx_lock(&rm->rm_lock); - rm->rm_noreadtoken = 0; - critical_enter(); + if (trylock) { + if (rm->lock_object.lo_flags & RM_SLEEPABLE) { + if (!sx_try_xlock(&rm->rm_lock_sx)) + return (0); + } else { + if (!mtx_trylock(&rm->rm_lock_mtx)) + return (0); + } + } else { + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + sx_xlock(&rm->rm_lock_sx); + else + mtx_lock(&rm->rm_lock_mtx); + } + critical_enter(); pc = pcpu_find(curcpu); + rm->rm_writecpus &= ~pc->pc_cpumask; rm_tracker_add(pc, tracker); sched_pin(); critical_exit(); - mtx_unlock(&rm->rm_lock); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + sx_xunlock(&rm->rm_lock_sx); + else + mtx_unlock(&rm->rm_lock_mtx); + + return (1); } -void -_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker) +int +_rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker, int trylock) { struct thread *td = curthread; struct pcpu *pc; @@ -337,11 +367,11 @@ _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker) * Fast path to combine two common conditions into a single * conditional jump. */ - if (0 == (td->td_owepreempt | rm->rm_noreadtoken)) - return; + if (0 == (td->td_owepreempt | (rm->rm_writecpus & pc->pc_cpumask))) + return (1); /* We do not have a read token and need to acquire one. */ - _rm_rlock_hard(rm, tracker); + return _rm_rlock_hard(rm, tracker, trylock); } static void @@ -400,20 +430,26 @@ _rm_wlock(struct rmlock *rm) { struct rm_priotracker *prio; struct turnstile *ts; + cpumask_t readcpus; - mtx_lock(&rm->rm_lock); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + sx_xlock(&rm->rm_lock_sx); + else + mtx_lock(&rm->rm_lock_mtx); - if (rm->rm_noreadtoken == 0) { + if (rm->rm_writecpus != all_cpus) { /* Get all read tokens back */ - rm->rm_noreadtoken = 1; + readcpus = all_cpus & (all_cpus & ~rm->rm_writecpus); + rm->rm_writecpus = all_cpus; /* - * Assumes rm->rm_noreadtoken update is visible on other CPUs + * Assumes rm->rm_writecpus update is visible on other CPUs * before rm_cleanIPI is called. */ #ifdef SMP - smp_rendezvous(smp_no_rendevous_barrier, + smp_rendezvous_cpus(readcpus, + smp_no_rendevous_barrier, rm_cleanIPI, smp_no_rendevous_barrier, rm); @@ -439,7 +475,10 @@ void _rm_wunlock(struct rmlock *rm) { - mtx_unlock(&rm->rm_lock); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + sx_xunlock(&rm->rm_lock_sx); + else + mtx_unlock(&rm->rm_lock_mtx); } #ifdef LOCK_DEBUG @@ -454,7 +493,11 @@ void _rm_wlock_debug(struct rmlock *rm, const char *file, int line) LOCK_LOG_LOCK("RMWLOCK", &rm->lock_object, 0, 0, file, line); - WITNESS_LOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + WITNESS_LOCK(&rm->rm_lock_sx.lock_object, LOP_EXCLUSIVE, + file, line); + else + WITNESS_LOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); curthread->td_locks++; @@ -465,25 +508,35 @@ _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) { curthread->td_locks--; - WITNESS_UNLOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); + if (rm->lock_object.lo_flags & RM_SLEEPABLE) + WITNESS_UNLOCK(&rm->rm_lock_sx.lock_object, LOP_EXCLUSIVE, + file, line); + else + WITNESS_UNLOCK(&rm->lock_object, LOP_EXCLUSIVE, file, line); LOCK_LOG_LOCK("RMWUNLOCK", &rm->lock_object, 0, 0, file, line); _rm_wunlock(rm); } -void +int _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, - const char *file, int line) + int trylock, const char *file, int line) { - + if (!trylock && (rm->lock_object.lo_flags & RM_SLEEPABLE)) + WITNESS_CHECKORDER(&rm->rm_lock_sx.lock_object, LOP_NEWORDER, + file, line, NULL); WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER, file, line, NULL); - _rm_rlock(rm, tracker); + if (_rm_rlock(rm, tracker, trylock)) { + LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line); - LOCK_LOG_LOCK("RMRLOCK", &rm->lock_object, 0, 0, file, line); + WITNESS_LOCK(&rm->lock_object, 0, file, line); - WITNESS_LOCK(&rm->lock_object, 0, file, line); + curthread->td_locks++; - curthread->td_locks++; + return (1); + } + + return (0); } void @@ -517,12 +570,12 @@ _rm_wunlock_debug(struct rmlock *rm, const char *file, int line) _rm_wunlock(rm); } -void +int _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, - const char *file, int line) + int trylock, const char *file, int line) { - _rm_rlock(rm, tracker); + return _rm_rlock(rm, tracker, trylock); } void diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index bd3c7aa478c..9553a3aba3a 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -98,21 +98,24 @@ int debugger_on_panic = 0; #else int debugger_on_panic = 1; #endif -SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW, +SYSCTL_INT(_debug, OID_AUTO, debugger_on_panic, CTLFLAG_RW | CTLFLAG_TUN, &debugger_on_panic, 0, "Run debugger on kernel panic"); +TUNABLE_INT("debug.debugger_on_panic", &debugger_on_panic); #ifdef KDB_TRACE -int trace_on_panic = 1; +static int trace_on_panic = 1; #else -int trace_on_panic = 0; +static int trace_on_panic = 0; #endif -SYSCTL_INT(_debug, OID_AUTO, trace_on_panic, CTLFLAG_RW, +SYSCTL_INT(_debug, OID_AUTO, trace_on_panic, CTLFLAG_RW | CTLFLAG_TUN, &trace_on_panic, 0, "Print stack trace on kernel panic"); +TUNABLE_INT("debug.trace_on_panic", &trace_on_panic); #endif /* KDB */ -int sync_on_panic = 0; -SYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RW, +static int sync_on_panic = 0; +SYSCTL_INT(_kern, OID_AUTO, sync_on_panic, CTLFLAG_RW | CTLFLAG_TUN, &sync_on_panic, 0, "Do a sync before rebooting from a panic"); +TUNABLE_INT("kern.sync_on_panic", &sync_on_panic); SYSCTL_NODE(_kern, OID_AUTO, shutdown, CTLFLAG_RW, 0, "Shutdown environment"); @@ -130,7 +133,6 @@ static struct dumperinfo dumper; /* our selected dumper */ static struct pcb dumppcb; /* Registers. */ static lwpid_t dumptid; /* Thread ID. */ -static void boot(int) __dead2; static void poweroff_wait(void *, int); static void shutdown_halt(void *junk, int howto); static void shutdown_panic(void *junk, int howto); @@ -142,7 +144,7 @@ shutdown_conf(void *unused) { EVENTHANDLER_REGISTER(shutdown_final, poweroff_wait, NULL, - SHUTDOWN_PRI_FIRST + 100); + SHUTDOWN_PRI_FIRST); EVENTHANDLER_REGISTER(shutdown_final, shutdown_halt, NULL, SHUTDOWN_PRI_LAST + 100); EVENTHANDLER_REGISTER(shutdown_final, shutdown_panic, NULL, @@ -170,7 +172,7 @@ reboot(struct thread *td, struct reboot_args *uap) error = priv_check(td, PRIV_REBOOT); if (error == 0) { mtx_lock(&Giant); - boot(uap->opt); + kern_reboot(uap->opt); mtx_unlock(&Giant); } return (error); @@ -194,7 +196,7 @@ shutdown_nice(int howto) PROC_UNLOCK(initproc); } else { /* No init(8) running, so simply reboot */ - boot(RB_NOSYNC); + kern_reboot(RB_NOSYNC); } return; } @@ -266,8 +268,8 @@ isbufbusy(struct buf *bp) /* * Shutdown the system cleanly to prepare for reboot, halt, or power off. */ -static void -boot(int howto) +void +kern_reboot(int howto) { static int first_buf_printf = 1; @@ -280,7 +282,7 @@ boot(int howto) thread_lock(curthread); sched_bind(curthread, 0); thread_unlock(curthread); - KASSERT(PCPU_GET(cpuid) == 0, ("boot: not running on cpu 0")); + KASSERT(PCPU_GET(cpuid) == 0, ("%s: not running on cpu 0", __func__)); #endif /* We're in the process of rebooting. */ rebooting = 1; @@ -510,10 +512,6 @@ shutdown_reset(void *junk, int howto) /* NOTREACHED */ /* assuming reset worked */ } -#ifdef SMP -static u_int panic_cpu = NOCPU; -#endif - /* * Panic is called on unresolvable fatal errors. It prints "panic: mesg", * and then reboots. If we are called twice, then we avoid trying to sync @@ -522,6 +520,9 @@ static u_int panic_cpu = NOCPU; void panic(const char *fmt, ...) { +#ifdef SMP + static volatile u_int panic_cpu = NOCPU; +#endif struct thread *td = curthread; int bootopt, newpanic; va_list ap; @@ -587,7 +588,7 @@ panic(const char *fmt, ...) if (!sync_on_panic) bootopt |= RB_NOSYNC; critical_exit(); - boot(bootopt); + kern_reboot(bootopt); } /* diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 8a322de1d62..c37b974806f 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -89,14 +89,14 @@ __FBSDID("$FreeBSD$"); #define ONSIG 32 /* NSIG for osig* syscalls. XXX. */ SDT_PROVIDER_DECLARE(proc); -SDT_PROBE_DEFINE(proc, kernel, , signal_send); +SDT_PROBE_DEFINE(proc, kernel, , signal_send, signal-send); SDT_PROBE_ARGTYPE(proc, kernel, , signal_send, 0, "struct thread *"); SDT_PROBE_ARGTYPE(proc, kernel, , signal_send, 1, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, , signal_send, 2, "int"); -SDT_PROBE_DEFINE(proc, kernel, , signal_clear); +SDT_PROBE_DEFINE(proc, kernel, , signal_clear, signal-clear); SDT_PROBE_ARGTYPE(proc, kernel, , signal_clear, 0, "int"); SDT_PROBE_ARGTYPE(proc, kernel, , signal_clear, 1, "ksiginfo_t *"); -SDT_PROBE_DEFINE(proc, kernel, , signal_discard); +SDT_PROBE_DEFINE(proc, kernel, , signal_discard, signal-discard); SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 0, "struct thread *"); SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 1, "struct proc *"); SDT_PROBE_ARGTYPE(proc, kernel, , signal_discard, 2, "int"); @@ -107,8 +107,6 @@ static int killpg1(struct thread *td, int sig, int pgid, int all, ksiginfo_t *ksi); static int issignal(struct thread *td, int stop_allowed); static int sigprop(int sig); -static int tdsendsignal(struct proc *p, struct thread *td, int sig, - ksiginfo_t *ksi); static void tdsigwakeup(struct thread *, int, sig_t, int); static void sig_suspend_threads(struct thread *, struct proc *, int); static int filt_sigattach(struct knote *kn); @@ -433,36 +431,19 @@ sigqueue_flush(sigqueue_t *sq) } static void -sigqueue_collect_set(sigqueue_t *sq, sigset_t *set) +sigqueue_move_set(sigqueue_t *src, sigqueue_t *dst, const sigset_t *set) { - ksiginfo_t *ksi; - - KASSERT(sq->sq_flags & SQ_INIT, ("sigqueue not inited")); - - TAILQ_FOREACH(ksi, &sq->sq_list, ksi_link) - SIGADDSET(*set, ksi->ksi_signo); - SIGSETOR(*set, sq->sq_kill); -} - -static void -sigqueue_move_set(sigqueue_t *src, sigqueue_t *dst, sigset_t *setp) -{ - sigset_t tmp, set; + sigset_t tmp; struct proc *p1, *p2; ksiginfo_t *ksi, *next; KASSERT(src->sq_flags & SQ_INIT, ("src sigqueue not inited")); KASSERT(dst->sq_flags & SQ_INIT, ("dst sigqueue not inited")); - /* - * make a copy, this allows setp to point to src or dst - * sq_signals without trouble. - */ - set = *setp; p1 = src->sq_proc; p2 = dst->sq_proc; /* Move siginfo to target list */ TAILQ_FOREACH_SAFE(ksi, &src->sq_list, ksi_link, next) { - if (SIGISMEMBER(set, ksi->ksi_signo)) { + if (SIGISMEMBER(*set, ksi->ksi_signo)) { TAILQ_REMOVE(&src->sq_list, ksi, ksi_link); if (p1 != NULL) p1->p_pendingcnt--; @@ -475,19 +456,17 @@ sigqueue_move_set(sigqueue_t *src, sigqueue_t *dst, sigset_t *setp) /* Move pending bits to target list */ tmp = src->sq_kill; - SIGSETAND(tmp, set); + SIGSETAND(tmp, *set); SIGSETOR(dst->sq_kill, tmp); SIGSETNAND(src->sq_kill, tmp); tmp = src->sq_signals; - SIGSETAND(tmp, set); + SIGSETAND(tmp, *set); SIGSETOR(dst->sq_signals, tmp); SIGSETNAND(src->sq_signals, tmp); - - /* Finally, rescan src queue and set pending bits for it */ - sigqueue_collect_set(src, &src->sq_signals); } +#if 0 static void sigqueue_move(sigqueue_t *src, sigqueue_t *dst, int signo) { @@ -497,9 +476,10 @@ sigqueue_move(sigqueue_t *src, sigqueue_t *dst, int signo) SIGADDSET(set, signo); sigqueue_move_set(src, dst, &set); } +#endif static void -sigqueue_delete_set(sigqueue_t *sq, sigset_t *set) +sigqueue_delete_set(sigqueue_t *sq, const sigset_t *set) { struct proc *p = sq->sq_proc; ksiginfo_t *ksi, *next; @@ -517,8 +497,6 @@ sigqueue_delete_set(sigqueue_t *sq, sigset_t *set) } SIGSETNAND(sq->sq_kill, *set); SIGSETNAND(sq->sq_signals, *set); - /* Finally, rescan queue and set pending bits for it */ - sigqueue_collect_set(sq, &sq->sq_signals); } void @@ -533,7 +511,7 @@ sigqueue_delete(sigqueue_t *sq, int signo) /* Remove a set of signals for a process */ static void -sigqueue_delete_set_proc(struct proc *p, sigset_t *set) +sigqueue_delete_set_proc(struct proc *p, const sigset_t *set) { sigqueue_t worklist; struct thread *td0; @@ -997,7 +975,6 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, *oset = td->td_sigmask; error = 0; - SIGEMPTYSET(new_block); if (set != NULL) { switch (how) { case SIG_BLOCK: @@ -1010,7 +987,7 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, case SIG_UNBLOCK: SIGSETNAND(td->td_sigmask, *set); signotify(td); - break; + goto out; case SIG_SETMASK: SIG_CANTMASK(*set); oset1 = td->td_sigmask; @@ -1024,22 +1001,23 @@ kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, break; default: error = EINVAL; - break; + goto out; } + + /* + * The new_block set contains signals that were not previously + * blocked, but are blocked now. + * + * In case we block any signal that was not previously blocked + * for td, and process has the signal pending, try to schedule + * signal delivery to some thread that does not block the + * signal, possibly waking it up. + */ + if (p->p_numthreads != 1) + reschedule_signals(p, new_block, flags); } - /* - * The new_block set contains signals that were not previously - * blocked, but are blocked now. - * - * In case we block any signal that was not previously blocked - * for td, and process has the signal pending, try to schedule - * signal delivery to some thread that does not block the signal, - * possibly waking it up. - */ - if (p->p_numthreads != 1) - reschedule_signals(p, new_block, flags); - +out: if (!(flags & SIGPROCMASK_PROC_LOCKED)) PROC_UNLOCK(p); return (error); @@ -1185,23 +1163,18 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, struct timespec *timeout) { struct sigacts *ps; - sigset_t savedmask; + sigset_t saved_mask, new_block; struct proc *p; - int error, sig, hz, i, timevalid = 0; + int error, sig, timo, timevalid = 0; struct timespec rts, ets, ts; struct timeval tv; p = td->td_proc; error = 0; - sig = 0; ets.tv_sec = 0; ets.tv_nsec = 0; - SIG_CANTMASK(waitset); - PROC_LOCK(p); - ps = p->p_sigacts; - savedmask = td->td_sigmask; - if (timeout) { + if (timeout != NULL) { if (timeout->tv_nsec >= 0 && timeout->tv_nsec < 1000000000) { timevalid = 1; getnanouptime(&rts); @@ -1209,89 +1182,78 @@ kern_sigtimedwait(struct thread *td, sigset_t waitset, ksiginfo_t *ksi, timespecadd(&ets, timeout); } } - -restart: - for (i = 1; i <= _SIG_MAXSIG; ++i) { - if (!SIGISMEMBER(waitset, i)) - continue; - if (!SIGISMEMBER(td->td_sigqueue.sq_signals, i)) { - if (SIGISMEMBER(p->p_sigqueue.sq_signals, i)) { - sigqueue_move(&p->p_sigqueue, - &td->td_sigqueue, i); - } else - continue; - } - - SIGFILLSET(td->td_sigmask); - SIG_CANTMASK(td->td_sigmask); - SIGDELSET(td->td_sigmask, i); + ksiginfo_init(ksi); + /* Some signals can not be waited for. */ + SIG_CANTMASK(waitset); + ps = p->p_sigacts; + PROC_LOCK(p); + saved_mask = td->td_sigmask; + SIGSETNAND(td->td_sigmask, waitset); + for (;;) { mtx_lock(&ps->ps_mtx); sig = cursig(td, SIG_STOP_ALLOWED); mtx_unlock(&ps->ps_mtx); - if (sig) - goto out; - else { - /* - * Because cursig() may have stopped current thread, - * after it is resumed, things may have already been - * changed, it should rescan any pending signals. - */ - goto restart; + if (sig != 0 && SIGISMEMBER(waitset, sig)) { + if (sigqueue_get(&td->td_sigqueue, sig, ksi) != 0 || + sigqueue_get(&p->p_sigqueue, sig, ksi) != 0) { + error = 0; + break; + } + } + + if (error != 0) + break; + + /* + * POSIX says this must be checked after looking for pending + * signals. + */ + if (timeout != NULL) { + if (!timevalid) { + error = EINVAL; + break; + } + getnanouptime(&rts); + if (timespeccmp(&rts, &ets, >=)) { + error = EAGAIN; + break; + } + ts = ets; + timespecsub(&ts, &rts); + TIMESPEC_TO_TIMEVAL(&tv, &ts); + timo = tvtohz(&tv); + } else { + timo = 0; + } + + error = msleep(ps, &p->p_mtx, PPAUSE|PCATCH, "sigwait", timo); + + if (timeout != NULL) { + if (error == ERESTART) { + /* Timeout can not be restarted. */ + error = EINTR; + } else if (error == EAGAIN) { + /* We will calculate timeout by ourself. */ + error = 0; + } } } - if (error) - goto out; - + new_block = saved_mask; + SIGSETNAND(new_block, td->td_sigmask); + td->td_sigmask = saved_mask; /* - * POSIX says this must be checked after looking for pending - * signals. + * Fewer signals can be delivered to us, reschedule signal + * notification. */ - if (timeout) { - if (!timevalid) { - error = EINVAL; - goto out; - } - getnanouptime(&rts); - if (timespeccmp(&rts, &ets, >=)) { - error = EAGAIN; - goto out; - } - ts = ets; - timespecsub(&ts, &rts); - TIMESPEC_TO_TIMEVAL(&tv, &ts); - hz = tvtohz(&tv); - } else - hz = 0; - - td->td_sigmask = savedmask; - SIGSETNAND(td->td_sigmask, waitset); - signotify(td); - error = msleep(&ps, &p->p_mtx, PPAUSE|PCATCH, "sigwait", hz); - if (timeout) { - if (error == ERESTART) { - /* timeout can not be restarted. */ - error = EINTR; - } else if (error == EAGAIN) { - /* will calculate timeout by ourself. */ - error = 0; - } - } - goto restart; - -out: - td->td_sigmask = savedmask; - signotify(td); - if (sig) { - ksiginfo_init(ksi); - sigqueue_get(&td->td_sigqueue, sig, ksi); - ksi->ksi_signo = sig; + if (p->p_numthreads != 1) + reschedule_signals(p, new_block, 0); + if (error == 0) { SDT_PROBE(proc, kernel, , signal_clear, sig, ksi, 0, 0, 0); if (ksi->ksi_code == SI_TIMER) itimer_accept(p, ksi->ksi_timerid, ksi); - error = 0; #ifdef KTRACE if (KTRPOINT(td, KTR_PSIG)) { @@ -1974,27 +1936,22 @@ pksignal(struct proc *p, int sig, ksiginfo_t *ksi) return (tdsendsignal(p, NULL, sig, ksi)); } +/* Utility function for finding a thread to send signal event to. */ int -psignal_event(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi) +sigev_findtd(struct proc *p ,struct sigevent *sigev, struct thread **ttd) { - struct thread *td = NULL; + struct thread *td; - PROC_LOCK_ASSERT(p, MA_OWNED); - - KASSERT(!KSI_ONQ(ksi), ("psignal_event: ksi on queue")); - - /* - * ksi_code and other fields should be set before - * calling this function. - */ - ksi->ksi_signo = sigev->sigev_signo; - ksi->ksi_value = sigev->sigev_value; if (sigev->sigev_notify == SIGEV_THREAD_ID) { - td = thread_find(p, sigev->sigev_notify_thread_id); + td = tdfind(sigev->sigev_notify_thread_id, p->p_pid); if (td == NULL) return (ESRCH); + *ttd = td; + } else { + *ttd = NULL; + PROC_LOCK(p); } - return (tdsendsignal(p, td, ksi->ksi_signo, ksi)); + return (0); } void @@ -2015,7 +1972,7 @@ tdksignal(struct thread *td, int sig, ksiginfo_t *ksi) (void) tdsendsignal(td->td_proc, td, sig, ksi); } -static int +int tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) { sig_t action; @@ -2026,6 +1983,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) int ret = 0; int wakeup_swapper; + MPASS(td == NULL || p == td->td_proc); PROC_LOCK_ASSERT(p, MA_OWNED); if (!_SIG_VALID(sig)) @@ -2139,20 +2097,13 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) * We try do the per-process part here. */ if (P_SHOULDSTOP(p)) { - /* - * The process is in stopped mode. All the threads should be - * either winding down or already on the suspended queue. - */ - if (p->p_flag & P_TRACED) { - /* - * The traced process is already stopped, - * so no further action is necessary. - * No signal can restart us. - */ - goto out; - } - if (sig == SIGKILL) { + /* + * If traced process is already stopped, + * then no further action is necessary. + */ + if (p->p_flag & P_TRACED) + goto out; /* * SIGKILL sets process running. * It will die elsewhere. @@ -2163,6 +2114,12 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) } if (prop & SA_CONT) { + /* + * If traced process is already stopped, + * then no further action is necessary. + */ + if (p->p_flag & P_TRACED) + goto out; /* * If SIGCONT is default (or ignored), we continue the * process but don't leave the signal in sigqueue as @@ -2207,6 +2164,12 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi) } if (prop & SA_STOP) { + /* + * If traced process is already stopped, + * then no further action is necessary. + */ + if (p->p_flag & P_TRACED) + goto out; /* * Already stopped, don't need to stop again * (If we did the shell could get confused). @@ -2450,25 +2413,22 @@ reschedule_signals(struct proc *p, sigset_t block, int flags) { struct sigacts *ps; struct thread *td; - int i; + int sig; PROC_LOCK_ASSERT(p, MA_OWNED); - + if (SIGISEMPTY(p->p_siglist)) + return; ps = p->p_sigacts; - for (i = 1; !SIGISEMPTY(block); i++) { - if (!SIGISMEMBER(block, i)) - continue; - SIGDELSET(block, i); - if (!SIGISMEMBER(p->p_siglist, i)) - continue; - - td = sigtd(p, i, 0); + SIGSETAND(block, p->p_siglist); + while ((sig = sig_ffs(&block)) != 0) { + SIGDELSET(block, sig); + td = sigtd(p, sig, 0); signotify(td); if (!(flags & SIGPROCMASK_PS_LOCKED)) mtx_lock(&ps->ps_mtx); - if (p->p_flag & P_TRACED || SIGISMEMBER(ps->ps_sigcatch, i)) - tdsigwakeup(td, i, SIG_CATCH, - (SIGISMEMBER(ps->ps_sigintr, i) ? EINTR : + if (p->p_flag & P_TRACED || SIGISMEMBER(ps->ps_sigcatch, sig)) + tdsigwakeup(td, sig, SIG_CATCH, + (SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : ERESTART)); if (!(flags & SIGPROCMASK_PS_LOCKED)) mtx_unlock(&ps->ps_mtx); @@ -3088,7 +3048,7 @@ expand_name(const char *name, uid_t uid, pid_t pid, struct thread *td, sbuf_printf(&sb, GZ_SUFFIX); } #endif - if (sbuf_overflowed(&sb)) { + if (sbuf_error(&sb) != 0) { log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too " "long\n", (long)pid, name, (u_long)uid); nomem: diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c index d1a5c0dba5f..03f6088403d 100644 --- a/sys/kern/kern_syscalls.c +++ b/sys/kern/kern_syscalls.c @@ -181,13 +181,12 @@ syscall_module_handler(struct module *mod, int what, void *arg) error = syscall_deregister(data->offset, &data->old_sysent); return (error); default: - return EOPNOTSUPP; + if (data->chainevh) + return (data->chainevh(mod, what, data->chainarg)); + return (EOPNOTSUPP); } - if (data->chainevh) - return (data->chainevh(mod, what, data->chainarg)); - else - return (0); + /* NOTREACHED */ } int diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index b83502c2f41..49ccc505278 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1544,3 +1545,30 @@ userland_sysctl(struct thread *td, int *name, u_int namelen, void *old, } return (error); } + +/* + * Drain into a sysctl struct. The user buffer must be wired. + */ +static int +sbuf_sysctl_drain(void *arg, const char *data, int len) +{ + struct sysctl_req *req = arg; + int error; + + error = SYSCTL_OUT(req, data, len); + KASSERT(error >= 0, ("Got unexpected negative value %d", error)); + return (error == 0 ? len : -error); +} + +struct sbuf * +sbuf_new_for_sysctl(struct sbuf *s, char *buf, int length, + struct sysctl_req *req) +{ + + /* Wire the user buffer, so we can write without blocking. */ + sysctl_wire_old_buffer(req, 0); + + s = sbuf_new(s, buf, length, SBUF_FIXEDLEN); + sbuf_set_drain(s, sbuf_sysctl_drain, req); + return (s); +} diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index d97334849ce..cdca3a3e6af 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -87,6 +87,8 @@ static struct timehands *volatile timehands = &th0; struct timecounter *timecounter = &dummy_timecounter; static struct timecounter *timecounters = &dummy_timecounter; +int tc_min_ticktock_freq = 1; + time_t time_second = 1; time_t time_uptime = 1; @@ -482,6 +484,8 @@ tc_windup(void) if (th->th_counter != timecounter) { th->th_counter = timecounter; th->th_offset_count = ncount; + tc_min_ticktock_freq = max(1, timecounter->tc_frequency / + (((uint64_t)timecounter->tc_counter_mask + 1) / 3)); } /*- @@ -767,19 +771,15 @@ static int tc_tick; SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, ""); void -tc_ticktock(void) +tc_ticktock(int cnt) { static int count; - static time_t last_calib; - if (++count < tc_tick) + count += cnt; + if (count < tc_tick) return; count = 0; tc_windup(); - if (time_uptime != last_calib && !(time_uptime & 0xf)) { - cpu_tick_calibrate(0); - last_calib = time_uptime; - } } static void @@ -805,6 +805,7 @@ inittimecounter(void *dummy) /* warm up new timecounter (again) and get rolling. */ (void)timecounter->tc_get_timecount(timecounter); (void)timecounter->tc_get_timecount(timecounter); + tc_windup(); } SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); @@ -830,9 +831,20 @@ tc_cpu_ticks(void) return (u + base); } +void +cpu_tick_calibration(void) +{ + static time_t last_calib; + + if (time_uptime != last_calib && !(time_uptime & 0xf)) { + cpu_tick_calibrate(0); + last_calib = time_uptime; + } +} + /* * This function gets called every 16 seconds on only one designated - * CPU in the system from hardclock() via tc_ticktock(). + * CPU in the system from hardclock() via cpu_tick_calibration()(). * * Whenever the real time clock is stepped we get called with reset=1 * to make sure we handle suspend/resume and similar events correctly. diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index d8f7a8eb0f8..75656f03c18 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -240,6 +241,9 @@ create_thread(struct thread *td, mcontext_t *ctx, if (P_SHOULDSTOP(p)) newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; PROC_UNLOCK(p); + + tidhash_add(newtd); + thread_lock(newtd); if (rtp != NULL) { if (!(td->td_pri_class == PRI_TIMESHARE && @@ -281,21 +285,23 @@ thr_exit(struct thread *td, struct thr_exit_args *uap) kern_umtx_wake(td, uap->state, INT_MAX, 0); } + rw_wlock(&tidhash_lock); PROC_LOCK(p); - tdsigcleanup(td); - PROC_SLOCK(p); - /* * Shutting down last thread in the proc. This will actually * call exit() in the trampoline when it returns. */ if (p->p_numthreads != 1) { + LIST_REMOVE(td, td_hash); + rw_wunlock(&tidhash_lock); + tdsigcleanup(td); + PROC_SLOCK(p); thread_stopped(p); thread_exit(); /* NOTREACHED */ } - PROC_SUNLOCK(p); PROC_UNLOCK(p); + rw_wunlock(&tidhash_lock); return (0); } @@ -309,18 +315,17 @@ thr_kill(struct thread *td, struct thr_kill_args *uap) int error; p = td->td_proc; - error = 0; ksiginfo_init(&ksi); ksi.ksi_signo = uap->sig; - ksi.ksi_code = SI_USER; + ksi.ksi_code = SI_LWP; ksi.ksi_pid = p->p_pid; ksi.ksi_uid = td->td_ucred->cr_ruid; - PROC_LOCK(p); if (uap->id == -1) { if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { error = EINVAL; } else { error = ESRCH; + PROC_LOCK(p); FOREACH_THREAD_IN_PROC(p, ttd) { if (ttd != td) { error = 0; @@ -329,22 +334,21 @@ thr_kill(struct thread *td, struct thr_kill_args *uap) tdksignal(ttd, uap->sig, &ksi); } } + PROC_UNLOCK(p); } } else { - if (uap->id != td->td_tid) - ttd = thread_find(p, uap->id); - else - ttd = td; + error = 0; + ttd = tdfind((lwpid_t)uap->id, p->p_pid); if (ttd == NULL) - error = ESRCH; - else if (uap->sig == 0) + return (ESRCH); + if (uap->sig == 0) ; else if (!_SIG_VALID(uap->sig)) error = EINVAL; - else + else tdksignal(ttd, uap->sig, &ksi); + PROC_UNLOCK(ttd->td_proc); } - PROC_UNLOCK(p); return (error); } @@ -359,51 +363,49 @@ thr_kill2(struct thread *td, struct thr_kill2_args *uap) AUDIT_ARG_SIGNUM(uap->sig); - if (uap->pid == td->td_proc->p_pid) { - p = td->td_proc; - PROC_LOCK(p); - } else if ((p = pfind(uap->pid)) == NULL) { - return (ESRCH); - } - AUDIT_ARG_PROCESS(p); - - error = p_cansignal(td, p, uap->sig); - if (error == 0) { - ksiginfo_init(&ksi); - ksi.ksi_signo = uap->sig; - ksi.ksi_code = SI_USER; - ksi.ksi_pid = td->td_proc->p_pid; - ksi.ksi_uid = td->td_ucred->cr_ruid; - if (uap->id == -1) { - if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { - error = EINVAL; - } else { - error = ESRCH; - FOREACH_THREAD_IN_PROC(p, ttd) { - if (ttd != td) { - error = 0; - if (uap->sig == 0) - break; - tdksignal(ttd, uap->sig, &ksi); - } + ksiginfo_init(&ksi); + ksi.ksi_signo = uap->sig; + ksi.ksi_code = SI_LWP; + ksi.ksi_pid = td->td_proc->p_pid; + ksi.ksi_uid = td->td_ucred->cr_ruid; + if (uap->id == -1) { + if ((p = pfind(uap->pid)) == NULL) + return (ESRCH); + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, uap->sig); + if (error) { + PROC_UNLOCK(p); + return (error); + } + if (uap->sig != 0 && !_SIG_VALID(uap->sig)) { + error = EINVAL; + } else { + error = ESRCH; + FOREACH_THREAD_IN_PROC(p, ttd) { + if (ttd != td) { + error = 0; + if (uap->sig == 0) + break; + tdksignal(ttd, uap->sig, &ksi); } } - } else { - if (uap->id != td->td_tid) - ttd = thread_find(p, uap->id); - else - ttd = td; - if (ttd == NULL) - error = ESRCH; - else if (uap->sig == 0) - ; - else if (!_SIG_VALID(uap->sig)) - error = EINVAL; - else - tdksignal(ttd, uap->sig, &ksi); } + PROC_UNLOCK(p); + } else { + ttd = tdfind((lwpid_t)uap->id, uap->pid); + if (ttd == NULL) + return (ESRCH); + p = ttd->td_proc; + AUDIT_ARG_PROCESS(p); + error = p_cansignal(td, p, uap->sig); + if (uap->sig == 0) + ; + else if (!_SIG_VALID(uap->sig)) + error = EINVAL; + else + tdksignal(ttd, uap->sig, &ksi); + PROC_UNLOCK(p); } - PROC_UNLOCK(p); return (error); } @@ -429,39 +431,44 @@ thr_suspend(struct thread *td, struct thr_suspend_args *uap) int kern_thr_suspend(struct thread *td, struct timespec *tsp) { + struct proc *p = td->td_proc; struct timeval tv; - int error = 0, hz = 0; - - if (tsp != NULL) { - if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000) - return (EINVAL); - if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) - return (ETIMEDOUT); - TIMESPEC_TO_TIMEVAL(&tv, tsp); - hz = tvtohz(&tv); - } + int error = 0; + int timo = 0; if (td->td_pflags & TDP_WAKEUP) { td->td_pflags &= ~TDP_WAKEUP; return (0); } - PROC_LOCK(td->td_proc); - if ((td->td_flags & TDF_THRWAKEUP) == 0) - error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr", - hz); + if (tsp != NULL) { + if (tsp->tv_nsec < 0 || tsp->tv_nsec > 1000000000) + return (EINVAL); + if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) + error = EWOULDBLOCK; + else { + TIMESPEC_TO_TIMEVAL(&tv, tsp); + timo = tvtohz(&tv); + } + } + + PROC_LOCK(p); + if (error == 0 && (td->td_flags & TDF_THRWAKEUP) == 0) + error = msleep((void *)td, &p->p_mtx, + PCATCH, "lthr", timo); + if (td->td_flags & TDF_THRWAKEUP) { thread_lock(td); td->td_flags &= ~TDF_THRWAKEUP; thread_unlock(td); - PROC_UNLOCK(td->td_proc); + PROC_UNLOCK(p); return (0); } - PROC_UNLOCK(td->td_proc); + PROC_UNLOCK(p); if (error == EWOULDBLOCK) error = ETIMEDOUT; else if (error == ERESTART) { - if (hz != 0) + if (timo != 0) error = EINTR; } return (error); @@ -480,12 +487,9 @@ thr_wake(struct thread *td, struct thr_wake_args *uap) } p = td->td_proc; - PROC_LOCK(p); - ttd = thread_find(p, uap->id); - if (ttd == NULL) { - PROC_UNLOCK(p); + ttd = tdfind((lwpid_t)uap->id, p->p_pid); + if (ttd == NULL) return (ESRCH); - } thread_lock(ttd); ttd->td_flags |= TDF_THRWAKEUP; thread_unlock(ttd); @@ -497,7 +501,7 @@ thr_wake(struct thread *td, struct thr_wake_args *uap) int thr_set_name(struct thread *td, struct thr_set_name_args *uap) { - struct proc *p = td->td_proc; + struct proc *p; char name[MAXCOMLEN + 1]; struct thread *ttd; int error; @@ -510,15 +514,11 @@ thr_set_name(struct thread *td, struct thr_set_name_args *uap) if (error) return (error); } - PROC_LOCK(p); - if (uap->id == td->td_tid) - ttd = td; - else - ttd = thread_find(p, uap->id); - if (ttd != NULL) - strcpy(ttd->td_name, name); - else - error = ESRCH; + p = td->td_proc; + ttd = tdfind((lwpid_t)uap->id, p->p_pid); + if (ttd == NULL) + return (ESRCH); + strcpy(ttd->td_name, name); PROC_UNLOCK(p); return (error); } diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index e500e0a3a0f..5f0759028af 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #ifdef HWPMC_HOOKS @@ -83,6 +84,12 @@ static void thread_zombie(struct thread *); struct mtx tid_lock; static struct unrhdr *tid_unrhdr; +static MALLOC_DEFINE(M_TIDHASH, "tidhash", "thread hash"); + +struct tidhashhead *tidhashtbl; +u_long tidhash; +struct rwlock tidhash_lock; + /* * Prepare a thread for use. */ @@ -230,6 +237,8 @@ threadinit(void) thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(), thread_ctor, thread_dtor, thread_init, thread_fini, 16 - 1, 0); + tidhashtbl = hashinit(maxproc / 2, M_TIDHASH, &tidhash); + rw_init(&tidhash_lock, "tidhash"); } /* @@ -737,19 +746,23 @@ thread_suspend_check(int return_instead) (p->p_flag & P_SINGLE_BOUNDARY) && return_instead) return (ERESTART); - /* If thread will exit, flush its pending signals */ - if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) - sigqueue_flush(&td->td_sigqueue); - - PROC_SLOCK(p); - thread_stopped(p); /* * If the process is waiting for us to exit, * this thread should just suicide. * Assumes that P_SINGLE_EXIT implies P_STOPPED_SINGLE. */ - if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) + if ((p->p_flag & P_SINGLE_EXIT) && (p->p_singlethread != td)) { + PROC_UNLOCK(p); + tidhash_remove(td); + PROC_LOCK(p); + tdsigcleanup(td); + PROC_SLOCK(p); + thread_stopped(p); thread_exit(); + } + + PROC_SLOCK(p); + thread_stopped(p); if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { if (p->p_numthreads == p->p_suspcount + 1) { thread_lock(p->p_singlethread); @@ -923,3 +936,57 @@ thread_find(struct proc *p, lwpid_t tid) } return (td); } + +/* Locate a thread by number; return with proc lock held. */ +struct thread * +tdfind(lwpid_t tid, pid_t pid) +{ +#define RUN_THRESH 16 + struct thread *td; + int run = 0; + + rw_rlock(&tidhash_lock); + LIST_FOREACH(td, TIDHASH(tid), td_hash) { + if (td->td_tid == tid) { + if (pid != -1 && td->td_proc->p_pid != pid) { + td = NULL; + break; + } + if (td->td_proc->p_state == PRS_NEW) { + td = NULL; + break; + } + if (run > RUN_THRESH) { + if (rw_try_upgrade(&tidhash_lock)) { + LIST_REMOVE(td, td_hash); + LIST_INSERT_HEAD(TIDHASH(td->td_tid), + td, td_hash); + PROC_LOCK(td->td_proc); + rw_wunlock(&tidhash_lock); + return (td); + } + } + PROC_LOCK(td->td_proc); + break; + } + run++; + } + rw_runlock(&tidhash_lock); + return (td); +} + +void +tidhash_add(struct thread *td) +{ + rw_wlock(&tidhash_lock); + LIST_INSERT_HEAD(TIDHASH(td->td_tid), td, td_hash); + rw_wunlock(&tidhash_lock); +} + +void +tidhash_remove(struct thread *td) +{ + rw_wlock(&tidhash_lock); + LIST_REMOVE(td, td_hash); + rw_wunlock(&tidhash_lock); +} diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 3aea2bda8b6..a153fbc7749 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -1402,28 +1402,22 @@ void itimer_fire(struct itimer *it) { struct proc *p = it->it_proc; - int ret; + struct thread *td; if (it->it_sigev.sigev_notify == SIGEV_SIGNAL || it->it_sigev.sigev_notify == SIGEV_THREAD_ID) { - PROC_LOCK(p); + if (sigev_findtd(p, &it->it_sigev, &td) != 0) { + ITIMER_LOCK(it); + timespecclear(&it->it_time.it_value); + timespecclear(&it->it_time.it_interval); + callout_stop(&it->it_callout); + ITIMER_UNLOCK(it); + return; + } if (!KSI_ONQ(&it->it_ksi)) { it->it_ksi.ksi_errno = 0; - ret = psignal_event(p, &it->it_sigev, &it->it_ksi); - if (__predict_false(ret != 0)) { - it->it_overrun++; - /* - * Broken userland code, thread went - * away, disarm the timer. - */ - if (ret == ESRCH) { - ITIMER_LOCK(it); - timespecclear(&it->it_time.it_value); - timespecclear(&it->it_time.it_interval); - callout_stop(&it->it_callout); - ITIMER_UNLOCK(it); - } - } + ksiginfo_set_sigev(&it->it_ksi, &it->it_sigev); + tdsendsignal(p, td, it->it_ksi.ksi_signo, &it->it_ksi); } else { if (it->it_overrun < INT_MAX) it->it_overrun++; diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c index 78b094928b9..98f55da48cc 100644 --- a/sys/kern/kern_timeout.c +++ b/sys/kern/kern_timeout.c @@ -57,10 +57,10 @@ __FBSDID("$FreeBSD$"); #include SDT_PROVIDER_DEFINE(callout_execute); -SDT_PROBE_DEFINE(callout_execute, kernel, , callout_start); +SDT_PROBE_DEFINE(callout_execute, kernel, , callout_start, callout-start); SDT_PROBE_ARGTYPE(callout_execute, kernel, , callout_start, 0, "struct callout *"); -SDT_PROBE_DEFINE(callout_execute, kernel, , callout_end); +SDT_PROBE_DEFINE(callout_execute, kernel, , callout_end, callout-end); SDT_PROBE_ARGTYPE(callout_execute, kernel, , callout_end, 0, "struct callout *"); @@ -111,6 +111,7 @@ struct callout_cpu { int cc_softticks; int cc_cancel; int cc_waiting; + int cc_firsttick; }; #ifdef SMP @@ -126,6 +127,7 @@ struct callout_cpu cc_cpu; #define CC_UNLOCK(cc) mtx_unlock_spin(&(cc)->cc_lock) static int timeout_cpu; +void (*callout_new_inserted)(int cpu, int ticks) = NULL; MALLOC_DEFINE(M_CALLOUT, "callout", "Callout datastructures"); @@ -260,7 +262,7 @@ callout_tick(void) need_softclock = 0; cc = CC_SELF(); mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET); - cc->cc_ticks++; + cc->cc_firsttick = cc->cc_ticks = ticks; for (; (cc->cc_softticks - cc->cc_ticks) <= 0; cc->cc_softticks++) { bucket = cc->cc_softticks & callwheelmask; if (!TAILQ_EMPTY(&cc->cc_callwheel[bucket])) { @@ -277,6 +279,34 @@ callout_tick(void) swi_sched(cc->cc_cookie, 0); } +int +callout_tickstofirst(int limit) +{ + struct callout_cpu *cc; + struct callout *c; + struct callout_tailq *sc; + int curticks; + int skip = 1; + + cc = CC_SELF(); + mtx_lock_spin_flags(&cc->cc_lock, MTX_QUIET); + curticks = cc->cc_ticks; + while( skip < ncallout && skip < limit ) { + sc = &cc->cc_callwheel[ (curticks+skip) & callwheelmask ]; + /* search scanning ticks */ + TAILQ_FOREACH( c, sc, c_links.tqe ){ + if (c && (c->c_time <= curticks + ncallout) + && (c->c_time > 0)) + goto out; + } + skip++; + } +out: + cc->cc_firsttick = curticks + skip; + mtx_unlock_spin_flags(&cc->cc_lock, MTX_QUIET); + return (skip); +} + static struct callout_cpu * callout_lock(struct callout *c) { @@ -639,9 +669,15 @@ retry: c->c_arg = arg; c->c_flags |= (CALLOUT_ACTIVE | CALLOUT_PENDING); c->c_func = ftn; - c->c_time = cc->cc_ticks + to_ticks; + c->c_time = ticks + to_ticks; TAILQ_INSERT_TAIL(&cc->cc_callwheel[c->c_time & callwheelmask], c, c_links.tqe); + if ((c->c_time - cc->cc_firsttick) < 0 && + callout_new_inserted != NULL) { + cc->cc_firsttick = c->c_time; + (*callout_new_inserted)(cpu, + to_ticks + (ticks - cc->cc_ticks)); + } CTR5(KTR_CALLOUT, "%sscheduled %p func %p arg %p in %d", cancelled ? "re" : "", c, c->c_func, c->c_arg, to_ticks); CC_UNLOCK(cc); diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 42d2761d7cf..cf8c534bccd 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -1059,8 +1059,10 @@ do_wait(struct thread *td, void *addr, u_long id, umtxq_lock(&uq->uq_key); for (;;) { error = umtxq_sleep(uq, "uwait", tvtohz(&tv)); - if (!(uq->uq_flags & UQF_UMTXQ)) + if (!(uq->uq_flags & UQF_UMTXQ)) { + error = 0; break; + } if (error != ETIMEDOUT) break; umtxq_unlock(&uq->uq_key); @@ -1586,20 +1588,15 @@ umtxq_sleep_pi(struct umtx_q *uq, struct umtx_pi *pi, umtxq_insert(uq); mtx_lock_spin(&umtx_lock); if (pi->pi_owner == NULL) { - /* XXX - * Current, We only support process private PI-mutex, - * we need a faster way to find an owner thread for - * process-shared mutex (not available yet). - */ mtx_unlock_spin(&umtx_lock); - PROC_LOCK(curproc); - td1 = thread_find(curproc, owner); + /* XXX Only look up thread in current process. */ + td1 = tdfind(owner, curproc->p_pid); mtx_lock_spin(&umtx_lock); if (td1 != NULL && pi->pi_owner == NULL) { uq1 = td1->td_umtxq; umtx_pi_setowner(pi, td1); } - PROC_UNLOCK(curproc); + PROC_UNLOCK(td1->td_proc); } TAILQ_FOREACH(uq1, &pi->pi_blocked, uq_lockq) { @@ -2404,25 +2401,14 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m, } } - if (error != 0) { - if ((uq->uq_flags & UQF_UMTXQ) == 0) { - /* - * If we concurrently got do_cv_signal()d - * and we got an error or UNIX signals or a timeout, - * then, perform another umtxq_signal to avoid - * consuming the wakeup. This may cause supurious - * wakeup for another thread which was just queued, - * but SUSV3 explicitly allows supurious wakeup to - * occur, and indeed a kernel based implementation - * can not avoid it. - */ - if (!umtxq_signal(&uq->uq_key, 1)) - error = 0; - } + if ((uq->uq_flags & UQF_UMTXQ) == 0) + error = 0; + else { + umtxq_remove(uq); if (error == ERESTART) error = EINTR; } - umtxq_remove(uq); + umtxq_unlock(&uq->uq_key); umtx_key_release(&uq->uq_key); return (error); @@ -2891,15 +2877,13 @@ do_sem_wait(struct thread *td, struct _usem *sem, struct timespec *timeout) } } - if (error != 0) { - if ((uq->uq_flags & UQF_UMTXQ) == 0) { - if (!umtxq_signal(&uq->uq_key, 1)) - error = 0; - } + if ((uq->uq_flags & UQF_UMTXQ) == 0) + error = 0; + else { + umtxq_remove(uq); if (error == ERESTART) error = EINTR; } - umtxq_remove(uq); umtxq_unlock(&uq->uq_key); umtx_key_release(&uq->uq_key); return (error); diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index b389ace5bd4..eaaefde9522 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -967,15 +967,15 @@ nosyms: *result = lf; out: + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); if (error && lf) linker_file_unload(lf, LINKER_UNLOAD_FORCE); if (shdr) free(shdr, M_LINKER); if (firstpage) free(firstpage, M_LINKER); - VOP_UNLOCK(nd.ni_vp, 0); - vn_close(nd.ni_vp, FREAD, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); return error; } diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index b0df57dcbac..c1888521869 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -885,13 +885,13 @@ link_elf_load_file(linker_class_t cls, const char *filename, *result = lf; out: + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); if (error && lf) linker_file_unload(lf, LINKER_UNLOAD_FORCE); if (hdr) free(hdr, M_LINKER); - VOP_UNLOCK(nd.ni_vp, 0); - vn_close(nd.ni_vp, FREAD, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); return error; } diff --git a/sys/kern/p1003_1b.c b/sys/kern/p1003_1b.c index 6d05972f415..5de60f2ce8e 100644 --- a/sys/kern/p1003_1b.c +++ b/sys/kern/p1003_1b.c @@ -219,10 +219,8 @@ sched_getscheduler(struct thread *td, struct sched_getscheduler_args *uap) PROC_LOCK(targetp); } else { targetp = pfind(uap->pid); - if (targetp == NULL) { - e = ESRCH; - goto done2; - } + if (targetp == NULL) + return (ESRCH); targettd = FIRST_THREAD_IN_PROC(targetp); } @@ -233,7 +231,6 @@ sched_getscheduler(struct thread *td, struct sched_getscheduler_args *uap) } PROC_UNLOCK(targetp); -done2: return (e); } @@ -293,13 +290,10 @@ kern_sched_rr_get_interval(struct thread *td, pid_t pid, targetp = td->td_proc; PROC_LOCK(targetp); } else { - targetp = td->td_proc; - PROC_LOCK(targetp); - targettd = thread_find(targetp, pid); - if (targettd == NULL) { - PROC_UNLOCK(targetp); + targetp = pfind(pid); + if (targetp == NULL) return (ESRCH); - } + targettd = FIRST_THREAD_IN_PROC(targetp); } e = p_cansee(td, targetp); diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c index e579198adc6..9face648de9 100644 --- a/sys/kern/sched_4bsd.c +++ b/sys/kern/sched_4bsd.c @@ -157,6 +157,12 @@ static struct runq runq_pcpu[MAXCPU]; long runq_length[MAXCPU]; #endif +struct pcpuidlestat { + u_int idlecalls; + u_int oldidlecalls; +}; +static DPCPU_DEFINE(struct pcpuidlestat, idlestat); + static void setup_runqs(void) { @@ -684,6 +690,7 @@ sched_rr_interval(void) void sched_clock(struct thread *td) { + struct pcpuidlestat *stat; struct td_sched *ts; THREAD_LOCK_ASSERT(td, MA_OWNED); @@ -703,6 +710,10 @@ sched_clock(struct thread *td) if (!TD_IS_IDLETHREAD(td) && ticks - PCPU_GET(switchticks) >= sched_quantum) td->td_flags |= TDF_NEEDRESCHED; + + stat = DPCPU_PTR(idlestat); + stat->oldidlecalls = stat->idlecalls; + stat->idlecalls = 0; } /* @@ -1137,7 +1148,15 @@ forward_wakeup(int cpunum) } if (map) { forward_wakeups_delivered++; - ipi_selected(map, IPI_AST); + SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { + id = pc->pc_cpumask; + if ((map & id) == 0) + continue; + if (cpu_idle_wakeup(pc->pc_cpuid)) + map &= ~id; + } + if (map) + ipi_selected(map, IPI_AST); return (1); } if (cpunum == NOCPU) @@ -1154,7 +1173,8 @@ kick_other_cpu(int pri, int cpuid) pcpu = pcpu_find(cpuid); if (idle_cpus_mask & pcpu->pc_cpumask) { forward_wakeups_delivered++; - ipi_cpu(cpuid, IPI_AST); + if (!cpu_idle_wakeup(cpuid)) + ipi_cpu(cpuid, IPI_AST); return; } @@ -1527,7 +1547,7 @@ sched_pctcpu(struct thread *td) } void -sched_tick(void) +sched_tick(int cnt) { } @@ -1537,12 +1557,16 @@ sched_tick(void) void sched_idletd(void *dummy) { + struct pcpuidlestat *stat; + stat = DPCPU_PTR(idlestat); for (;;) { mtx_assert(&Giant, MA_NOTOWNED); - while (sched_runnable() == 0) - cpu_idle(0); + while (sched_runnable() == 0) { + cpu_idle(stat->idlecalls + stat->oldidlecalls > 64); + stat->idlecalls++; + } mtx_lock_spin(&sched_lock); mi_switch(SW_VOL | SWT_IDLE, NULL); diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c index e210ebc09f6..4765c1cc698 100644 --- a/sys/kern/sched_ule.c +++ b/sys/kern/sched_ule.c @@ -62,10 +62,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#include -#endif #ifdef HWPMC_HOOKS #include @@ -200,7 +196,7 @@ static int preempt_thresh = 0; #endif static int static_boost = PRI_MIN_TIMESHARE; static int sched_idlespins = 10000; -static int sched_idlespinthresh = 4; +static int sched_idlespinthresh = 16; /* * tdq - per processor runqs and statistics. All fields are protected by the @@ -212,6 +208,7 @@ struct tdq { struct mtx tdq_lock; /* run queue lock. */ struct cpu_group *tdq_cg; /* Pointer to cpu topology. */ volatile int tdq_load; /* Aggregate load. */ + volatile int tdq_cpu_idle; /* cpu_idle() is active. */ int tdq_sysload; /* For loadavg, !ITHD load. */ int tdq_transferable; /* Transferable thread count. */ short tdq_switchcnt; /* Switches this tick. */ @@ -970,7 +967,7 @@ tdq_notify(struct tdq *tdq, struct thread *td) * If the MD code has an idle wakeup routine try that before * falling back to IPI. */ - if (cpu_idle_wakeup(cpu)) + if (!tdq->tdq_cpu_idle || cpu_idle_wakeup(cpu)) return; } tdq->tdq_ipipending = 1; @@ -1801,10 +1798,18 @@ sched_switch(struct thread *td, struct thread *newtd, int flags) srqflag = (flags & SW_PREEMPT) ? SRQ_OURSELF|SRQ_YIELDING|SRQ_PREEMPTED : SRQ_OURSELF|SRQ_YIELDING; +#ifdef SMP + if (THREAD_CAN_MIGRATE(td) && !THREAD_CAN_SCHED(td, ts->ts_cpu)) + ts->ts_cpu = sched_pickcpu(td, 0); +#endif if (ts->ts_cpu == cpuid) tdq_runq_add(tdq, td, srqflag); - else + else { + KASSERT(THREAD_CAN_MIGRATE(td) || + (ts->ts_flags & TSF_BOUND) != 0, + ("Thread %p shouldn't migrate", td)); mtx = sched_switch_migrate(tdq, td, srqflag); + } } else { /* This thread must be going to sleep. */ TDQ_LOCK(tdq); @@ -2158,7 +2163,7 @@ sched_clock(struct thread *td) * is easier than trying to scale based on stathz. */ void -sched_tick(void) +sched_tick(int cnt) { struct td_sched *ts; @@ -2170,7 +2175,7 @@ sched_tick(void) if (ts->ts_incrtick == ticks) return; /* Adjust ticks for pctcpu */ - ts->ts_ticks += 1 << SCHED_TICK_SHIFT; + ts->ts_ticks += cnt << SCHED_TICK_SHIFT; ts->ts_ltick = ticks; ts->ts_incrtick = ticks; /* @@ -2387,7 +2392,6 @@ sched_affinity(struct thread *td) { #ifdef SMP struct td_sched *ts; - int cpu; THREAD_LOCK_ASSERT(td, MA_OWNED); ts = td->td_sched; @@ -2400,18 +2404,14 @@ sched_affinity(struct thread *td) } if (!TD_IS_RUNNING(td)) return; - td->td_flags |= TDF_NEEDRESCHED; - if (!THREAD_CAN_MIGRATE(td)) - return; /* - * Assign the new cpu and force a switch before returning to - * userspace. If the target thread is not running locally send - * an ipi to force the issue. + * Force a switch before returning to userspace. If the + * target thread is not running locally send an ipi to force + * the issue. */ - cpu = ts->ts_cpu; - ts->ts_cpu = sched_pickcpu(td, 0); - if (cpu != PCPU_GET(cpuid)) - ipi_cpu(cpu, IPI_PREEMPT); + td->td_flags |= TDF_NEEDRESCHED; + if (td != curthread) + ipi_cpu(ts->ts_cpu, IPI_PREEMPT); #endif } @@ -2428,6 +2428,7 @@ sched_bind(struct thread *td, int cpu) ts = td->td_sched; if (ts->ts_flags & TSF_BOUND) sched_unbind(td); + KASSERT(THREAD_CAN_MIGRATE(td), ("%p must be migratable", td)); ts->ts_flags |= TSF_BOUND; sched_pin(); if (PCPU_GET(cpuid) == cpu) @@ -2545,8 +2546,14 @@ sched_idletd(void *dummy) } } switchcnt = tdq->tdq_switchcnt + tdq->tdq_oldswitchcnt; - if (tdq->tdq_load == 0) - cpu_idle(switchcnt > 1); + if (tdq->tdq_load == 0) { + tdq->tdq_cpu_idle = 1; + if (tdq->tdq_load == 0) { + cpu_idle(switchcnt > sched_idlespinthresh * 4); + tdq->tdq_switchcnt++; + } + tdq->tdq_cpu_idle = 0; + } if (tdq->tdq_load) { thread_lock(td); mi_switch(SW_VOL | SWT_IDLE, NULL); @@ -2641,7 +2648,7 @@ sysctl_kern_sched_topology_spec_internal(struct sbuf *sb, struct cpu_group *cg, int i, first; sbuf_printf(sb, "%*s\n", indent, - "", indent, cg->cg_level); + "", 1 + indent / 2, cg->cg_level); sbuf_printf(sb, "%*s ", indent, "", cg->cg_count, cg->cg_mask); first = TRUE; diff --git a/sys/kern/subr_acl_nfs4.c b/sys/kern/subr_acl_nfs4.c index ec7ead930bb..cf664bf898b 100644 --- a/sys/kern/subr_acl_nfs4.c +++ b/sys/kern/subr_acl_nfs4.c @@ -162,6 +162,7 @@ vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, accmode_t priv_granted = 0; int denied, explicitly_denied, access_mask, is_directory, must_be_owner = 0; + mode_t file_mode; KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND | VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS | @@ -216,6 +217,17 @@ vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, denied = EPERM; } + /* + * For VEXEC, ensure that at least one execute bit is set for + * non-directories. We have to check the mode here to stay + * consistent with execve(2). See the test in + * exec_check_permissions(). + */ + acl_nfs4_sync_mode_from_acl(&file_mode, aclp); + if (!denied && !is_directory && (accmode & VEXEC) && + (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) + denied = EACCES; + if (!denied) return (0); @@ -236,8 +248,14 @@ vaccess_acl_nfs4(enum vtype type, uid_t file_uid, gid_t file_gid, PRIV_VFS_LOOKUP, 0)) priv_granted |= VEXEC; } else { - if ((accmode & VEXEC) && !priv_check_cred(cred, - PRIV_VFS_EXEC, 0)) + /* + * Ensure that at least one execute bit is on. Otherwise, + * a privileged user will always succeed, and we don't want + * this to happen unless the file really is executable. + */ + if ((accmode & VEXEC) && (file_mode & + (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && + !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) priv_granted |= VEXEC; } @@ -331,6 +349,61 @@ _acl_duplicate_entry(struct acl *aclp, int entry_index) return (&(aclp->acl_entry[entry_index + 1])); } +/* + * Calculate trivial ACL in a manner compatible with PSARC/2010/029. + * Note that this results in an ACL different from (but semantically + * equal to) the "canonical six" trivial ACL computed using algorithm + * described in draft-ietf-nfsv4-minorversion1-03.txt, 3.16.6.2. + */ +void +acl_nfs4_trivial_from_mode(struct acl *aclp, mode_t mode) +{ + acl_perm_t user_allow_first = 0, user_deny = 0, group_deny = 0; + acl_perm_t user_allow, group_allow, everyone_allow; + + KASSERT(aclp->acl_cnt == 0, ("aclp->acl_cnt == 0")); + + user_allow = group_allow = everyone_allow = ACL_READ_ACL | + ACL_READ_ATTRIBUTES | ACL_READ_NAMED_ATTRS | ACL_SYNCHRONIZE; + user_allow |= ACL_WRITE_ACL | ACL_WRITE_OWNER | ACL_WRITE_ATTRIBUTES | + ACL_WRITE_NAMED_ATTRS; + + if (mode & S_IRUSR) + user_allow |= ACL_READ_DATA; + if (mode & S_IWUSR) + user_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); + if (mode & S_IXUSR) + user_allow |= ACL_EXECUTE; + + if (mode & S_IRGRP) + group_allow |= ACL_READ_DATA; + if (mode & S_IWGRP) + group_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); + if (mode & S_IXGRP) + group_allow |= ACL_EXECUTE; + + if (mode & S_IROTH) + everyone_allow |= ACL_READ_DATA; + if (mode & S_IWOTH) + everyone_allow |= (ACL_WRITE_DATA | ACL_APPEND_DATA); + if (mode & S_IXOTH) + everyone_allow |= ACL_EXECUTE; + + user_deny = ((group_allow | everyone_allow) & ~user_allow); + group_deny = everyone_allow & ~group_allow; + user_allow_first = group_deny & ~user_deny; + + if (user_allow_first != 0) + _acl_append(aclp, ACL_USER_OBJ, user_allow_first, ACL_ENTRY_TYPE_ALLOW); + if (user_deny != 0) + _acl_append(aclp, ACL_USER_OBJ, user_deny, ACL_ENTRY_TYPE_DENY); + if (group_deny != 0) + _acl_append(aclp, ACL_GROUP_OBJ, group_deny, ACL_ENTRY_TYPE_DENY); + _acl_append(aclp, ACL_USER_OBJ, user_allow, ACL_ENTRY_TYPE_ALLOW); + _acl_append(aclp, ACL_GROUP_OBJ, group_allow, ACL_ENTRY_TYPE_ALLOW); + _acl_append(aclp, ACL_EVERYONE, everyone_allow, ACL_ENTRY_TYPE_ALLOW); +} + void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id) { diff --git a/sys/kern/subr_acl_posix1e.c b/sys/kern/subr_acl_posix1e.c index f6fc6b2f990..311b214ff37 100644 --- a/sys/kern/subr_acl_posix1e.c +++ b/sys/kern/subr_acl_posix1e.c @@ -90,8 +90,14 @@ vaccess_acl_posix1e(enum vtype type, uid_t file_uid, gid_t file_gid, PRIV_VFS_LOOKUP, 0)) priv_granted |= VEXEC; } else { - if ((accmode & VEXEC) && !priv_check_cred(cred, - PRIV_VFS_EXEC, 0)) + /* + * Ensure that at least one execute bit is on. Otherwise, + * a privileged user will always succeed, and we don't want + * this to happen unless the file really is executable. + */ + if ((accmode & VEXEC) && (acl_posix1e_acl_to_mode(acl) & + (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && + !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) priv_granted |= VEXEC; } diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 39398c4d1f2..d12968c07c2 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -121,17 +121,16 @@ struct device { int busy; /**< count of calls to device_busy() */ device_state_t state; /**< current device state */ uint32_t devflags; /**< api level flags for device_get_flags() */ - u_short flags; /**< internal device flags */ -#define DF_ENABLED 1 /* device should be probed/attached */ -#define DF_FIXEDCLASS 2 /* devclass specified at create time */ -#define DF_WILDCARD 4 /* unit was originally wildcard */ -#define DF_DESCMALLOCED 8 /* description was malloced */ -#define DF_QUIET 16 /* don't print verbose attach message */ -#define DF_DONENOMATCH 32 /* don't execute DEVICE_NOMATCH again */ -#define DF_EXTERNALSOFTC 64 /* softc not allocated by us */ -#define DF_REBID 128 /* Can rebid after attach */ - u_char order; /**< order from device_add_child_ordered() */ - u_char pad; + u_int flags; /**< internal device flags */ +#define DF_ENABLED 0x01 /* device should be probed/attached */ +#define DF_FIXEDCLASS 0x02 /* devclass specified at create time */ +#define DF_WILDCARD 0x04 /* unit was originally wildcard */ +#define DF_DESCMALLOCED 0x08 /* description was malloced */ +#define DF_QUIET 0x10 /* don't print verbose attach message */ +#define DF_DONENOMATCH 0x20 /* don't execute DEVICE_NOMATCH again */ +#define DF_EXTERNALSOFTC 0x40 /* softc not allocated by us */ +#define DF_REBID 0x80 /* Can rebid after attach */ + u_int order; /**< order from device_add_child_ordered() */ void *ivars; /**< instance variables */ void *softc; /**< current driver's variables */ @@ -1790,12 +1789,12 @@ device_add_child(device_t dev, const char *name, int unit) * @returns the new device */ device_t -device_add_child_ordered(device_t dev, int order, const char *name, int unit) +device_add_child_ordered(device_t dev, u_int order, const char *name, int unit) { device_t child; device_t place; - PDEBUG(("%s at %s with order %d as unit %d", + PDEBUG(("%s at %s with order %u as unit %d", name, DEVICENAME(dev), order, unit)); child = make_device(dev, name, unit); @@ -3285,7 +3284,7 @@ resource_list_purge(struct resource_list *rl) } device_t -bus_generic_add_child(device_t dev, int order, const char *name, int unit) +bus_generic_add_child(device_t dev, u_int order, const char *name, int unit) { return (device_add_child_ordered(dev, order, name, unit)); @@ -3999,15 +3998,6 @@ bus_setup_intr(device_t dev, struct resource *r, int flags, return (error); if (handler != NULL && !(flags & INTR_MPSAFE)) device_printf(dev, "[GIANT-LOCKED]\n"); - if (bootverbose && (flags & INTR_MPSAFE)) - device_printf(dev, "[MPSAFE]\n"); - if (filter != NULL) { - if (handler == NULL) - device_printf(dev, "[FILTER]\n"); - else - device_printf(dev, "[FILTER+ITHREAD]\n"); - } else - device_printf(dev, "[ITHREAD]\n"); return (0); } diff --git a/sys/kern/subr_busdma.c b/sys/kern/subr_busdma.c index f5eb46ebb87..7c76469b344 100644 --- a/sys/kern/subr_busdma.c +++ b/sys/kern/subr_busdma.c @@ -549,7 +549,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); - } else if ((uintptr_t)*vaddr & (dmat->alignment - 1)) { + } else if (vtophys(*vaddr) & (dmat->alignment - 1)) { printf("bus_dmamem_alloc failed to align memory properly.\n"); } #if defined(__amd64__) || defined(__i386__) diff --git a/sys/kern/subr_clock.c b/sys/kern/subr_clock.c index ffc70afa353..28e0dad4d53 100644 --- a/sys/kern/subr_clock.c +++ b/sys/kern/subr_clock.c @@ -164,10 +164,6 @@ clock_ct_to_ts(struct clocktime *ct, struct timespec *ts) days += days_in_month(year, i); days += (ct->day - 1); - /* XXX Dow sanity check. Dow is not used, so should we check it? */ - if (ct->dow != -1 && ct->dow != day_of_week(days)) - return (EINVAL); - /* Add hours, minutes, seconds. */ secs = ((days * 24 + ct->hour) * 60 + ct->min) * 60 + ct->sec; diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c index 12b015944c2..23915402e30 100644 --- a/sys/kern/subr_disk.c +++ b/sys/kern/subr_disk.c @@ -127,7 +127,7 @@ disk_err(struct bio *bp, const char *what, int blkdone, int nl) * bioq_remove() remove a generic element from the queue, act as * bioq_takefirst() if invoked on the head of the queue. * - * The semantic of these methods is the same of the operations + * The semantic of these methods is the same as the operations * on the underlying TAILQ, but with additional guarantees on * subsequent bioq_disksort() calls. E.g. bioq_insert_tail() * can be useful for making sure that all previous ops are flushed @@ -156,10 +156,10 @@ void bioq_remove(struct bio_queue_head *head, struct bio *bp) { - if (bp == TAILQ_FIRST(&head->queue)) - head->last_offset = bp->bio_offset + bp->bio_length; - - if (bp == head->insert_point) + if (head->insert_point == NULL) { + if (bp == TAILQ_FIRST(&head->queue)) + head->last_offset = bp->bio_offset + bp->bio_length; + } else if (bp == head->insert_point) head->insert_point = NULL; TAILQ_REMOVE(&head->queue, bp, bio_queue); @@ -178,7 +178,8 @@ void bioq_insert_head(struct bio_queue_head *head, struct bio *bp) { - head->last_offset = bp->bio_offset; + if (head->insert_point == NULL) + head->last_offset = bp->bio_offset; TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue); } @@ -188,6 +189,7 @@ bioq_insert_tail(struct bio_queue_head *head, struct bio *bp) TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue); head->insert_point = bp; + head->last_offset = bp->bio_offset; } struct bio * @@ -230,13 +232,28 @@ bioq_bio_key(struct bio_queue_head *head, struct bio *bp) void bioq_disksort(struct bio_queue_head *head, struct bio *bp) { - struct bio *cur, *prev = NULL; - uoff_t key = bioq_bio_key(head, bp); + struct bio *cur, *prev; + uoff_t key; + if ((bp->bio_flags & BIO_ORDERED) != 0) { + /* + * Ordered transactions can only be dispatched + * after any currently queued transactions. They + * also have barrier semantics - no transactions + * queued in the future can pass them. + */ + bioq_insert_tail(head, bp); + return; + } + + prev = NULL; + key = bioq_bio_key(head, bp); cur = TAILQ_FIRST(&head->queue); - if (head->insert_point) - cur = head->insert_point; + if (head->insert_point) { + prev = head->insert_point; + cur = TAILQ_NEXT(head->insert_point, bio_queue); + } while (cur != NULL && key >= bioq_bio_key(head, cur)) { prev = cur; diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c index 2a59503633a..692ecb4d437 100644 --- a/sys/kern/subr_kdb.c +++ b/sys/kern/subr_kdb.c @@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$"); #include "opt_kdb.h" +#include "opt_stack.h" #include #include @@ -37,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -93,7 +95,7 @@ SYSCTL_PROC(_debug_kdb, OID_AUTO, trap_code, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, */ #ifdef SMP static int kdb_stop_cpus = 1; -SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus, CTLTYPE_INT | CTLFLAG_RW, +SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus, CTLFLAG_RW | CTLFLAG_TUN, &kdb_stop_cpus, 0, "stop other CPUs when entering the debugger"); TUNABLE_INT("debug.kdb.stop_cpus", &kdb_stop_cpus); #endif @@ -300,6 +302,15 @@ kdb_backtrace(void) printf("KDB: stack backtrace:\n"); kdb_dbbe->dbbe_trace(); } +#ifdef STACK + else { + struct stack st; + + printf("KDB: stack backtrace:\n"); + stack_save(&st); + stack_print_ddb(&st); + } +#endif } /* diff --git a/sys/kern/subr_lock.c b/sys/kern/subr_lock.c index 61263f962aa..530ebc5b265 100644 --- a/sys/kern/subr_lock.c +++ b/sys/kern/subr_lock.c @@ -191,8 +191,7 @@ struct lock_prof_cpu *lp_cpu[MAXCPU]; volatile int lock_prof_enable = 0; static volatile int lock_prof_resetting; -/* SWAG: sbuf size = avg stat. line size * number of locks */ -#define LPROF_SBUF_SIZE 256 * 400 +#define LPROF_SBUF_SIZE 256 static int lock_prof_rejected; static int lock_prof_skipspin; @@ -384,8 +383,6 @@ lock_prof_type_stats(struct lock_prof_type *type, struct sbuf *sb, int spin, continue; lock_prof_sum(l, &lp, i, spin, t); lock_prof_output(&lp, sb); - if (sbuf_overflowed(sb)) - return; } } } @@ -393,13 +390,11 @@ lock_prof_type_stats(struct lock_prof_type *type, struct sbuf *sb, int spin, static int dump_lock_prof_stats(SYSCTL_HANDLER_ARGS) { - static int multiplier = 1; struct sbuf *sb; int error, cpu, t; int enabled; -retry_sbufops: - sb = sbuf_new(NULL, NULL, LPROF_SBUF_SIZE * multiplier, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, LPROF_SBUF_SIZE, req); sbuf_printf(sb, "\n%8s %9s %11s %11s %11s %6s %6s %2s %6s %s\n", "max", "wait_max", "total", "wait_total", "count", "avg", "wait_avg", "cnt_hold", "cnt_lock", "name"); enabled = lock_prof_enable; @@ -411,16 +406,13 @@ retry_sbufops: continue; lock_prof_type_stats(&lp_cpu[cpu]->lpc_types[0], sb, 0, t); lock_prof_type_stats(&lp_cpu[cpu]->lpc_types[1], sb, 1, t); - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } } lock_prof_enable = enabled; - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); + /* Output a trailing NUL. */ + if (error == 0) + error = SYSCTL_OUT(req, "", 1); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c index 5225c2f7889..0d083b4b33e 100644 --- a/sys/kern/subr_sbuf.c +++ b/sys/kern/subr_sbuf.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #ifdef _KERNEL #include +#include #include #include #include @@ -40,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #else /* _KERNEL */ #include +#include #include #include #include @@ -56,7 +58,6 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); #define KASSERT(e, m) #define SBMALLOC(size) malloc(size) #define SBFREE(buf) free(buf) -#define min(x,y) MIN(x,y) #endif /* _KERNEL */ /* @@ -65,7 +66,6 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); #define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) #define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) #define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) -#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) #define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) #define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) @@ -116,18 +116,24 @@ _assert_sbuf_state(const char *fun, struct sbuf *s, int state) #endif /* _KERNEL && INVARIANTS */ +#ifdef CTASSERT +CTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); +CTASSERT(powerof2(SBUF_MAXEXTENDINCR)); +#endif + static int sbuf_extendsize(int size) { int newsize; - newsize = SBUF_MINEXTENDSIZE; - while (newsize < size) { - if (newsize < (int)SBUF_MAXEXTENDSIZE) + if (size < (int)SBUF_MAXEXTENDSIZE) { + newsize = SBUF_MINEXTENDSIZE; + while (newsize < size) newsize *= 2; - else - newsize += SBUF_MAXEXTENDINCR; + } else { + newsize = roundup2(size, SBUF_MAXEXTENDINCR); } + KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); return (newsize); } @@ -184,11 +190,11 @@ sbuf_new(struct sbuf *s, char *buf, int length, int flags) s->s_flags = flags; } s->s_size = length; - if (buf) { + if (buf != NULL) { s->s_buf = buf; return (s); } - if (flags & SBUF_AUTOEXTEND) + if ((flags & SBUF_AUTOEXTEND) != 0) s->s_size = sbuf_extendsize(s->s_size); s->s_buf = SBMALLOC(s->s_size); if (s->s_buf == NULL) { @@ -240,7 +246,7 @@ sbuf_clear(struct sbuf *s) /* don't care if it's finished or not */ SBUF_CLEARFLAG(s, SBUF_FINISHED); - SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); + s->s_error = 0; s->s_len = 0; } @@ -266,6 +272,95 @@ sbuf_setpos(struct sbuf *s, int pos) return (0); } +/* + * Set up a drain function and argument on an sbuf to flush data to + * when the sbuf buffer overflows. + */ +void +sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx) +{ + + assert_sbuf_state(s, 0); + assert_sbuf_integrity(s); + KASSERT(func == s->s_drain_func || s->s_len == 0, + ("Cannot change drain to %p on non-empty sbuf %p", func, s)); + s->s_drain_func = func; + s->s_drain_arg = ctx; +} + +/* + * Call the drain and process the return. + */ +static int +sbuf_drain(struct sbuf *s) +{ + int len; + + KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); + KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); + len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len); + if (len < 0) { + s->s_error = -len; + return (s->s_error); + } + KASSERT(len > 0 && len <= s->s_len, + ("Bad drain amount %d for sbuf %p", len, s)); + s->s_len -= len; + /* + * Fast path for the expected case where all the data was + * drained. + */ + if (s->s_len == 0) + return (0); + /* + * Move the remaining characters to the beginning of the + * string. + */ + memmove(s->s_buf, s->s_buf + len, s->s_len); + return (0); +} + +/* + * Append a byte to an sbuf. This is the core function for appending + * to an sbuf and is the main place that deals with extending the + * buffer and marking overflow. + */ +static void +sbuf_put_byte(int c, struct sbuf *s) +{ + + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + if (s->s_error != 0) + return; + if (SBUF_FREESPACE(s) <= 0) { + /* + * If there is a drain, use it, otherwise extend the + * buffer. + */ + if (s->s_drain_func != NULL) + (void)sbuf_drain(s); + else if (sbuf_extend(s, 1) < 0) + s->s_error = ENOMEM; + if (s->s_error != 0) + return; + } + s->s_buf[s->s_len++] = c; +} + +/* + * Append a non-NUL character to an sbuf. This prototype signature is + * suitable for use with kvprintf(9). + */ +static void +sbuf_putc_func(int c, void *arg) +{ + + if (c != '\0') + sbuf_put_byte(c, arg); +} + /* * Append a byte string to an sbuf. */ @@ -273,21 +368,18 @@ int sbuf_bcat(struct sbuf *s, const void *buf, size_t len) { const char *str = buf; + const char *end = str + len; assert_sbuf_integrity(s); assert_sbuf_state(s, 0); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); - for (; len; len--) { - if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) - break; - s->s_buf[s->s_len++] = *str++; - } - if (len) { - SBUF_SETFLAG(s, SBUF_OVERFLOWED); - return (-1); - } + for (; str < end; str++) { + sbuf_put_byte(*str, s); + if (s->s_error != 0) + return (-1); + } return (0); } @@ -301,14 +393,17 @@ sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + KASSERT(s->s_drain_func == NULL, + ("Nonsensical copyin to sbuf %p with a drain", s)); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); if (len == 0) return (0); if (len > SBUF_FREESPACE(s)) { sbuf_extend(s, len - SBUF_FREESPACE(s)); - len = min(len, SBUF_FREESPACE(s)); + if (SBUF_FREESPACE(s) < len) + len = SBUF_FREESPACE(s); } if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) return (-1); @@ -342,17 +437,13 @@ sbuf_cat(struct sbuf *s, const char *str) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); - while (*str) { - if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) - break; - s->s_buf[s->s_len++] = *str++; - } - if (*str) { - SBUF_SETFLAG(s, SBUF_OVERFLOWED); - return (-1); + while (*str != '\0') { + sbuf_put_byte(*str++, s); + if (s->s_error != 0) + return (-1); } return (0); } @@ -368,19 +459,22 @@ sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + KASSERT(s->s_drain_func == NULL, + ("Nonsensical copyin to sbuf %p with a drain", s)); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); if (len == 0) len = SBUF_FREESPACE(s); /* XXX return 0? */ if (len > SBUF_FREESPACE(s)) { sbuf_extend(s, len); - len = min(len, SBUF_FREESPACE(s)); + if (SBUF_FREESPACE(s) < len) + len = SBUF_FREESPACE(s); } switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { case ENAMETOOLONG: - SBUF_SETFLAG(s, SBUF_OVERFLOWED); + s->s_error = ENOMEM; /* fall through */ case 0: s->s_len += done - 1; @@ -410,11 +504,10 @@ sbuf_cpy(struct sbuf *s, const char *str) /* * Format the given argument list and append the resulting string to an sbuf. */ +#ifdef _KERNEL int sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) { - va_list ap_copy; - int len; assert_sbuf_integrity(s); assert_sbuf_state(s, 0); @@ -422,16 +515,53 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) KASSERT(fmt != NULL, ("%s called with a NULL format string", __func__)); - if (SBUF_HASOVERFLOWED(s)) + (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap); + if (s->s_error != 0) + return (-1); + return (0); +} +#else /* !_KERNEL */ +int +sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) +{ + va_list ap_copy; + int error, len; + + assert_sbuf_integrity(s); + assert_sbuf_state(s, 0); + + KASSERT(fmt != NULL, + ("%s called with a NULL format string", __func__)); + + if (s->s_error != 0) return (-1); + /* + * For the moment, there is no way to get vsnprintf(3) to hand + * back a character at a time, to push everything into + * sbuf_putc_func() as was done for the kernel. + * + * In userspace, while drains are useful, there's generally + * not a problem attempting to malloc(3) on out of space. So + * expand a userland sbuf if there is not enough room for the + * data produced by sbuf_[v]printf(3). + */ + + error = 0; do { va_copy(ap_copy, ap); len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, fmt, ap_copy); va_end(ap_copy); - } while (len > SBUF_FREESPACE(s) && - sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); + + if (SBUF_FREESPACE(s) >= len) + break; + /* Cannot print with the current available space. */ + if (s->s_drain_func != NULL && s->s_len > 0) + error = sbuf_drain(s); + else + error = sbuf_extend(s, len - SBUF_FREESPACE(s)); + } while (error == 0); /* * s->s_len is the length of the string, without the terminating nul. @@ -440,19 +570,22 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) * terminating nul. * * vsnprintf() returns the amount that would have been copied, - * given sufficient space, hence the min() calculation below. + * given sufficient space, so don't over-increment s_len. */ - s->s_len += min(len, SBUF_FREESPACE(s)); + if (SBUF_FREESPACE(s) < len) + len = SBUF_FREESPACE(s); + s->s_len += len; if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) - SBUF_SETFLAG(s, SBUF_OVERFLOWED); + s->s_error = ENOMEM; KASSERT(s->s_len < s->s_size, ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); return (0); } +#endif /* _KERNEL */ /* * Format the given arguments and append the resulting string to an sbuf. @@ -476,17 +609,9 @@ int sbuf_putc(struct sbuf *s, int c) { - assert_sbuf_integrity(s); - assert_sbuf_state(s, 0); - - if (SBUF_HASOVERFLOWED(s)) + sbuf_putc_func(c, s); + if (s->s_error != 0) return (-1); - if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { - SBUF_SETFLAG(s, SBUF_OVERFLOWED); - return (-1); - } - if (c != '\0') - s->s_buf[s->s_len++] = c; return (0); } @@ -499,39 +624,53 @@ sbuf_trim(struct sbuf *s) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + KASSERT(s->s_drain_func == NULL, + ("%s makes no sense on sbuf %p with drain", __func__, s)); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); - while (s->s_len && isspace(s->s_buf[s->s_len-1])) + while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) --s->s_len; return (0); } /* - * Check if an sbuf overflowed + * Check if an sbuf has an error. */ int -sbuf_overflowed(struct sbuf *s) +sbuf_error(struct sbuf *s) { - return (SBUF_HASOVERFLOWED(s)); + return (s->s_error); } /* * Finish off an sbuf. */ -void +int sbuf_finish(struct sbuf *s) { + int error; assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + error = s->s_error; + if (s->s_drain_func != NULL) { + while (s->s_len > 0 && error == 0) + error = sbuf_drain(s); + } s->s_buf[s->s_len] = '\0'; - SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); + s->s_error = 0; SBUF_SETFLAG(s, SBUF_FINISHED); +#ifdef _KERNEL + return (error); +#else + errno = error; + return (-1); +#endif } /* @@ -543,6 +682,8 @@ sbuf_data(struct sbuf *s) assert_sbuf_integrity(s); assert_sbuf_state(s, SBUF_FINISHED); + KASSERT(s->s_drain_func == NULL, + ("%s makes no sense on sbuf %p with drain", __func__, s)); return (s->s_buf); } @@ -556,8 +697,10 @@ sbuf_len(struct sbuf *s) assert_sbuf_integrity(s); /* don't care if it's finished or not */ + KASSERT(s->s_drain_func == NULL, + ("%s makes no sense on sbuf %p with drain", __func__, s)); - if (SBUF_HASOVERFLOWED(s)) + if (s->s_error != 0) return (-1); return (s->s_len); } diff --git a/sys/kern/subr_sleepqueue.c b/sys/kern/subr_sleepqueue.c index c51def62091..cdf7a47c368 100644 --- a/sys/kern/subr_sleepqueue.c +++ b/sys/kern/subr_sleepqueue.c @@ -408,6 +408,13 @@ sleepq_catch_signals(void *wchan, int pri) sc = SC_LOOKUP(wchan); mtx_assert(&sc->sc_lock, MA_OWNED); MPASS(wchan != NULL); + if ((td->td_pflags & TDP_WAKEUP) != 0) { + td->td_pflags &= ~TDP_WAKEUP; + ret = EINTR; + thread_lock(td); + goto out; + } + /* * See if there are any pending signals for this thread. If not * we can switch immediately. Otherwise do the signal processing @@ -453,6 +460,7 @@ sleepq_catch_signals(void *wchan, int pri) sleepq_switch(wchan, pri); return (0); } +out: /* * There were pending signals and this thread is still * on the sleep queue, remove it from the sleep queue. @@ -1010,7 +1018,7 @@ sleepq_abort(struct thread *td, int intrval) #ifdef SLEEPQUEUE_PROFILING #define SLEEPQ_PROF_LOCATIONS 1024 -#define SLEEPQ_SBUFSIZE (40 * 512) +#define SLEEPQ_SBUFSIZE 512 struct sleepq_prof { LIST_ENTRY(sleepq_prof) sp_link; const char *sp_wmesg; @@ -1115,15 +1123,13 @@ reset_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) static int dump_sleepq_prof_stats(SYSCTL_HANDLER_ARGS) { - static int multiplier = 1; struct sleepq_prof *sp; struct sbuf *sb; int enabled; int error; int i; -retry_sbufops: - sb = sbuf_new(NULL, NULL, SLEEPQ_SBUFSIZE * multiplier, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, SLEEPQ_SBUFSIZE, req); sbuf_printf(sb, "\nwmesg\tcount\n"); enabled = prof_enabled; mtx_lock_spin(&sleepq_prof_lock); @@ -1133,19 +1139,13 @@ retry_sbufops: LIST_FOREACH(sp, &sleepq_hash[i], sp_link) { sbuf_printf(sb, "%s\t%ld\n", sp->sp_wmesg, sp->sp_count); - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - multiplier++; - goto retry_sbufops; - } } } mtx_lock_spin(&sleepq_prof_lock); prof_enabled = enabled; mtx_unlock_spin(&sleepq_prof_lock); - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); sbuf_delete(sb); return (error); } diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index 711b98382b7..3138c610e21 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -198,22 +198,32 @@ forward_signal(struct thread *td) * 0: NA * 1: ok * - * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs - * from executing at same time. */ static int generic_stop_cpus(cpumask_t map, u_int type) { + static volatile u_int stopping_cpu = NOCPU; int i; - KASSERT(type == IPI_STOP || type == IPI_STOP_HARD, + KASSERT( +#if defined(__amd64__) + type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND, +#else + type == IPI_STOP || type == IPI_STOP_HARD, +#endif ("%s: invalid stop type", __func__)); if (!smp_started) - return 0; + return (0); CTR2(KTR_SMP, "stop_cpus(%x) with %u type", map, type); + if (stopping_cpu != PCPU_GET(cpuid)) + while (atomic_cmpset_int(&stopping_cpu, NOCPU, + PCPU_GET(cpuid)) == 0) + while (stopping_cpu != NOCPU) + cpu_spinwait(); /* spin */ + /* send the stop IPI to all CPUs in map */ ipi_selected(map, type); @@ -230,7 +240,8 @@ generic_stop_cpus(cpumask_t map, u_int type) #endif } - return 1; + stopping_cpu = NOCPU; + return (1); } int @@ -248,50 +259,11 @@ stop_cpus_hard(cpumask_t map) } #if defined(__amd64__) -/* - * When called the executing CPU will send an IPI to all other CPUs - * requesting that they halt execution. - * - * Usually (but not necessarily) called with 'other_cpus' as its arg. - * - * - Signals all CPUs in map to suspend. - * - Waits for each to suspend. - * - * Returns: - * -1: error - * 0: NA - * 1: ok - * - * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs - * from executing at same time. - */ int suspend_cpus(cpumask_t map) { - int i; - if (!smp_started) - return (0); - - CTR1(KTR_SMP, "suspend_cpus(%x)", map); - - /* send the suspend IPI to all CPUs in map */ - ipi_selected(map, IPI_SUSPEND); - - i = 0; - while ((stopped_cpus & map) != map) { - /* spin */ - cpu_spinwait(); - i++; -#ifdef DIAGNOSTIC - if (i == 100000) { - printf("timeout suspending cpus\n"); - break; - } -#endif - } - - return (1); + return (generic_stop_cpus(map, IPI_SUSPEND)); } #endif diff --git a/sys/kern/subr_stack.c b/sys/kern/subr_stack.c index 6b80554994f..b719b71e27b 100644 --- a/sys/kern/subr_stack.c +++ b/sys/kern/subr_stack.c @@ -44,9 +44,7 @@ static MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); static int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset); -#ifdef DDB static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset); -#endif struct stack * stack_create(void) @@ -125,7 +123,6 @@ stack_print_short(struct stack *st) printf("\n"); } -#ifdef DDB void stack_print_ddb(struct stack *st) { @@ -141,6 +138,7 @@ stack_print_ddb(struct stack *st) } } +#ifdef DDB void stack_print_short_ddb(struct stack *st) { @@ -255,7 +253,6 @@ stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) return (0); } -#ifdef DDB static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) { @@ -275,4 +272,3 @@ stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) *name = "??"; return (ENOENT); } -#endif diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index fcf235c85ed..fd6dd4f5488 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -46,12 +46,17 @@ static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); static void *taskqueue_giant_ih; static void *taskqueue_ih; +struct taskqueue_busy { + struct task *tb_running; + TAILQ_ENTRY(taskqueue_busy) tb_link; +}; + struct taskqueue { STAILQ_HEAD(, task) tq_queue; const char *tq_name; taskqueue_enqueue_fn tq_enqueue; void *tq_context; - struct task *tq_running; + TAILQ_HEAD(, taskqueue_busy) tq_active; struct mtx tq_mutex; struct thread **tq_threads; int tq_tcount; @@ -63,8 +68,6 @@ struct taskqueue { #define TQ_FLAGS_BLOCKED (1 << 1) #define TQ_FLAGS_PENDING (1 << 2) -static void taskqueue_run(struct taskqueue *, struct task **); - static __inline void TQ_LOCK(struct taskqueue *tq) { @@ -104,6 +107,7 @@ _taskqueue_create(const char *name, int mflags, return NULL; STAILQ_INIT(&queue->tq_queue); + TAILQ_INIT(&queue->tq_active); queue->tq_name = name; queue->tq_enqueue = enqueue; queue->tq_context = context; @@ -141,8 +145,8 @@ taskqueue_free(struct taskqueue *queue) TQ_LOCK(queue); queue->tq_flags &= ~TQ_FLAGS_ACTIVE; - taskqueue_run(queue, &queue->tq_running); taskqueue_terminate(queue->tq_threads, queue); + KASSERT(TAILQ_EMPTY(&queue->tq_active), ("Tasks still running?")); mtx_destroy(&queue->tq_mutex); free(queue->tq_threads, M_TASKQUEUE); free(queue, M_TASKQUEUE); @@ -218,12 +222,16 @@ taskqueue_unblock(struct taskqueue *queue) } static void -taskqueue_run(struct taskqueue *queue, struct task **tpp) +taskqueue_run_locked(struct taskqueue *queue) { + struct taskqueue_busy tb; struct task *task; int pending; mtx_assert(&queue->tq_mutex, MA_OWNED); + tb.tb_running = NULL; + TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link); + while (STAILQ_FIRST(&queue->tq_queue)) { /* * Carefully remove the first task from the queue and @@ -233,16 +241,38 @@ taskqueue_run(struct taskqueue *queue, struct task **tpp) STAILQ_REMOVE_HEAD(&queue->tq_queue, ta_link); pending = task->ta_pending; task->ta_pending = 0; - task->ta_running = tpp; - *tpp = task; + tb.tb_running = task; TQ_UNLOCK(queue); task->ta_func(task->ta_context, pending); TQ_LOCK(queue); - *tpp = NULL; + tb.tb_running = NULL; wakeup(task); } + TAILQ_REMOVE(&queue->tq_active, &tb, tb_link); +} + +void +taskqueue_run(struct taskqueue *queue) +{ + + TQ_LOCK(queue); + taskqueue_run_locked(queue); + TQ_UNLOCK(queue); +} + +static int +task_is_running(struct taskqueue *queue, struct task *task) +{ + struct taskqueue_busy *tb; + + mtx_assert(&queue->tq_mutex, MA_OWNED); + TAILQ_FOREACH(tb, &queue->tq_active, tb_link) { + if (tb->tb_running == task) + return (1); + } + return (0); } void @@ -253,10 +283,8 @@ taskqueue_drain(struct taskqueue *queue, struct task *task) WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, __func__); TQ_LOCK(queue); - while (task->ta_pending != 0 || - (task->ta_running != NULL && task == *task->ta_running)) { + while (task->ta_pending != 0 || task_is_running(queue, task)) TQ_SLEEP(queue, task, &queue->tq_mutex, PWAIT, "-", 0); - } TQ_UNLOCK(queue); } @@ -269,9 +297,7 @@ taskqueue_swi_enqueue(void *context) static void taskqueue_swi_run(void *dummy) { - TQ_LOCK(taskqueue_swi); - taskqueue_run(taskqueue_swi, &taskqueue_swi->tq_running); - TQ_UNLOCK(taskqueue_swi); + taskqueue_run(taskqueue_swi); } static void @@ -283,9 +309,7 @@ taskqueue_swi_giant_enqueue(void *context) static void taskqueue_swi_giant_run(void *dummy) { - TQ_LOCK(taskqueue_swi_giant); - taskqueue_run(taskqueue_swi_giant, &taskqueue_swi_giant->tq_running); - TQ_UNLOCK(taskqueue_swi_giant); + taskqueue_run(taskqueue_swi_giant); } int @@ -347,22 +371,12 @@ void taskqueue_thread_loop(void *arg) { struct taskqueue **tqp, *tq; - struct task *running; - - /* - * The kernel stack space is globaly addressable, and it would - * be an error to ask whether a task is running after the - * taskqueue has been released. So it is safe to have the - * task point back to an address in the taskqueue's stack to - * determine if the task is running. - */ - running = NULL; tqp = arg; tq = *tqp; TQ_LOCK(tq); while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0) { - taskqueue_run(tq, &running); + taskqueue_run_locked(tq); /* * Because taskqueue_run() can drop tq_mutex, we need to * check if the TQ_FLAGS_ACTIVE flag wasn't removed in the @@ -372,6 +386,7 @@ taskqueue_thread_loop(void *arg) break; TQ_SLEEP(tq, tq, &tq->tq_mutex, 0, "-", 0); } + taskqueue_run_locked(tq); /* rendezvous with thread that asked us to terminate */ tq->tq_tcount--; @@ -428,9 +443,7 @@ taskqueue_fast_enqueue(void *context) static void taskqueue_fast_run(void *dummy) { - TQ_LOCK(taskqueue_fast); - taskqueue_run(taskqueue_fast, &taskqueue_fast->tq_running); - TQ_UNLOCK(taskqueue_fast); + taskqueue_run(taskqueue_fast); } TASKQUEUE_FAST_DEFINE(fast, taskqueue_fast_enqueue, NULL, diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 5c90d956e78..ac55cea3a11 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -118,9 +118,8 @@ userret(struct thread *td, struct trapframe *frame) /* * Charge system time if profiling. */ - if (p->p_flag & P_PROFIL) { + if (p->p_flag & P_PROFIL) addupc_task(td, TRAPF_PC(frame), td->td_pticks * psratio); - } /* * Let the scheduler adjust our priority etc. */ @@ -312,7 +311,7 @@ syscallenter(struct thread *td, struct syscall_args *sa) */ if (systrace_probe_func != NULL && sa->callp->sy_entry != 0) (*systrace_probe_func)(sa->callp->sy_entry, sa->code, - sa->callp, sa->args); + sa->callp, sa->args, 0); #endif AUDIT_SYSCALL_ENTER(sa->code, td); @@ -330,7 +329,7 @@ syscallenter(struct thread *td, struct syscall_args *sa) */ if (systrace_probe_func != NULL && sa->callp->sy_return != 0) (*systrace_probe_func)(sa->callp->sy_return, sa->code, - sa->callp, sa->args); + sa->callp, NULL, (error) ? -1 : td->td_retval[0]); #endif syscall_thread_exit(td, sa->callp); CTR4(KTR_SYSC, "syscall: p=%p error=%d return %#lx %#lx", diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index 201be995ffd..3fec4c420b2 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -154,8 +154,7 @@ __FBSDID("$FreeBSD$"); #define MAX_W_NAME 64 #define BADSTACK_SBUF_SIZE (256 * WITNESS_COUNT) -#define CYCLEGRAPH_SBUF_SIZE 8192 -#define FULLGRAPH_SBUF_SIZE 32768 +#define FULLGRAPH_SBUF_SIZE 512 /* * These flags go in the witness relationship matrix and describe the @@ -2545,7 +2544,7 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) return (error); } error = 0; - sb = sbuf_new(NULL, NULL, FULLGRAPH_SBUF_SIZE, SBUF_FIXEDLEN); + sb = sbuf_new_for_sysctl(NULL, NULL, FULLGRAPH_SBUF_SIZE, req); if (sb == NULL) return (ENOMEM); sbuf_printf(sb, "\n"); @@ -2557,20 +2556,10 @@ sysctl_debug_witness_fullgraph(SYSCTL_HANDLER_ARGS) witness_add_fullgraph(sb, w); mtx_unlock_spin(&w_mtx); - /* - * While using SBUF_FIXEDLEN, check if the sbuf overflowed. - */ - if (sbuf_overflowed(sb)) { - sbuf_delete(sb); - panic("%s: sbuf overflowed, bump FULLGRAPH_SBUF_SIZE value\n", - __func__); - } - /* * Close the sbuf and return to userland. */ - sbuf_finish(sb); - error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + error = sbuf_finish(sb); sbuf_delete(sb); return (error); diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index a1a7086dd03..1a2685cc1f0 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -76,7 +76,8 @@ static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer"); static MALLOC_DEFINE(M_SELECT, "select", "select() buffer"); MALLOC_DEFINE(M_IOV, "iov", "large iov's"); -static int pollout(struct pollfd *, struct pollfd *, u_int); +static int pollout(struct thread *, struct pollfd *, struct pollfd *, + u_int); static int pollscan(struct thread *, struct pollfd *, u_int); static int pollrescan(struct thread *); static int selscan(struct thread *, fd_mask **, fd_mask **, int); @@ -1207,7 +1208,7 @@ done: if (error == EWOULDBLOCK) error = 0; if (error == 0) { - error = pollout(bits, uap->fds, nfds); + error = pollout(td, bits, uap->fds, nfds); if (error) goto out; } @@ -1262,22 +1263,27 @@ pollrescan(struct thread *td) static int -pollout(fds, ufds, nfd) +pollout(td, fds, ufds, nfd) + struct thread *td; struct pollfd *fds; struct pollfd *ufds; u_int nfd; { int error = 0; u_int i = 0; + u_int n = 0; for (i = 0; i < nfd; i++) { error = copyout(&fds->revents, &ufds->revents, sizeof(ufds->revents)); if (error) return (error); + if (fds->revents != 0) + n++; fds++; ufds++; } + td->td_retval[0] = n; return (0); } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 525c0e2efa4..af6b2989691 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -721,24 +721,13 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) return (ESRCH); } } else { - /* this is slow, should be optimized */ - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - PROC_LOCK(p); - FOREACH_THREAD_IN_PROC(p, td2) { - if (td2->td_tid == pid) - break; - } - if (td2 != NULL) - break; /* proc lock held */ - PROC_UNLOCK(p); - } - sx_sunlock(&allproc_lock); - if (p == NULL) { + td2 = tdfind(pid, -1); + if (td2 == NULL) { if (proctree_locked) sx_xunlock(&proctree_lock); return (ESRCH); } + p = td2->td_proc; tid = pid; pid = p->p_pid; } diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index e783799c192..77cc53f0a9a 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 209579 2010-06-28 18:06:46Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 211998 2010-08-30 14:24:44Z kib */ const char *syscallnames[] = { @@ -346,7 +346,7 @@ const char *syscallnames[] = { "compat4.sendfile", /* 336 = freebsd4 sendfile */ "kldsym", /* 337 = kldsym */ "jail", /* 338 = jail */ - "#339", /* 339 = pioctl */ + "nnpfs_syscall", /* 339 = nnpfs_syscall */ "sigprocmask", /* 340 = sigprocmask */ "sigsuspend", /* 341 = sigsuspend */ "compat4.sigaction", /* 342 = freebsd4 sigaction */ @@ -384,7 +384,7 @@ const char *syscallnames[] = { "__setugid", /* 374 = __setugid */ "#375", /* 375 = nfsclnt */ "eaccess", /* 376 = eaccess */ - "#377", /* 377 = afs_syscall */ + "afs3_syscall", /* 377 = afs3_syscall */ "nmount", /* 378 = nmount */ "#379", /* 379 = kse_exit */ "#380", /* 380 = kse_wakeup */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 8e11134d06e..ef6082847ca 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -40,7 +40,7 @@ ; NOPROTO same as STD except do not create structure or ; function prototype in sys/sysproto.h. Does add a ; definition to syscall.h besides adding a sysent. -; NONSTATIC syscall is loadable +; NOTSTATIC syscall is loadable ; ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master @@ -594,7 +594,9 @@ 337 AUE_NULL STD { int kldsym(int fileid, int cmd, \ void *data); } 338 AUE_JAIL STD { int jail(struct jail *jail); } -339 AUE_NULL UNIMPL pioctl +339 AUE_NULL NOSTD|NOTSTATIC { int nnpfs_syscall(int operation, \ + char *a_pathP, int a_opcode, \ + void *a_paramsP, int a_followSymlinks); } 340 AUE_SIGPROCMASK STD { int sigprocmask(int how, \ const sigset_t *set, sigset_t *oset); } 341 AUE_SIGSUSPEND STD { int sigsuspend(const sigset_t *sigmask); } @@ -670,7 +672,9 @@ 374 AUE_NULL STD { int __setugid(int flag); } 375 AUE_NULL UNIMPL nfsclnt 376 AUE_EACCESS STD { int eaccess(char *path, int flags); } -377 AUE_NULL UNIMPL afs_syscall +377 AUE_NULL NOSTD|NOTSTATIC { int afs3_syscall(long syscall, \ + long parm1, long parm2, long parm3, \ + long parm4, long parm5, long parm6); } 378 AUE_NMOUNT STD { int nmount(struct iovec *iovp, \ unsigned int iovcnt, int flags); } 379 AUE_NULL UNIMPL kse_exit diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index 743ad033dd9..4b95f010ea7 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -1770,6 +1770,17 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 1; break; } + /* nnpfs_syscall */ + case 339: { + struct nnpfs_syscall_args *p = params; + iarg[0] = p->operation; /* int */ + uarg[1] = (intptr_t) p->a_pathP; /* char * */ + iarg[2] = p->a_opcode; /* int */ + uarg[3] = (intptr_t) p->a_paramsP; /* void * */ + iarg[4] = p->a_followSymlinks; /* int */ + *n_args = 5; + break; + } /* sigprocmask */ case 340: { struct sigprocmask_args *p = params; @@ -2011,6 +2022,19 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } + /* afs3_syscall */ + case 377: { + struct afs3_syscall_args *p = params; + iarg[0] = p->syscall; /* long */ + iarg[1] = p->parm1; /* long */ + iarg[2] = p->parm2; /* long */ + iarg[3] = p->parm3; /* long */ + iarg[4] = p->parm4; /* long */ + iarg[5] = p->parm5; /* long */ + iarg[6] = p->parm6; /* long */ + *n_args = 7; + break; + } /* nmount */ case 378: { struct nmount_args *p = params; @@ -5900,6 +5924,28 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* nnpfs_syscall */ + case 339: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "char *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "void *"; + break; + case 4: + p = "int"; + break; + default: + break; + }; + break; /* sigprocmask */ case 340: switch(ndx) { @@ -6325,6 +6371,34 @@ systrace_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* afs3_syscall */ + case 377: + switch(ndx) { + case 0: + p = "long"; + break; + case 1: + p = "long"; + break; + case 2: + p = "long"; + break; + case 3: + p = "long"; + break; + case 4: + p = "long"; + break; + case 5: + p = "long"; + break; + case 6: + p = "long"; + break; + default: + break; + }; + break; /* nmount */ case 378: switch(ndx) { diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 90218495937..05eb27d4b62 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -263,12 +263,14 @@ ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) if (!tty_opened(tp)) { /* Set proper termios flags. */ - if (TTY_CALLOUT(tp, dev)) { + if (TTY_CALLOUT(tp, dev)) tp->t_termios = tp->t_termios_init_out; - } else { + else tp->t_termios = tp->t_termios_init_in; - } ttydevsw_param(tp, &tp->t_termios); + /* Prevent modem control on callout devices and /dev/console. */ + if (TTY_CALLOUT(tp, dev) || dev == dev_console) + tp->t_termios.c_cflag |= CLOCAL; ttydevsw_modem(tp, SER_DTR|SER_RTS, 0); @@ -281,7 +283,7 @@ ttydev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) } /* Wait for Carrier Detect. */ - if (!TTY_CALLOUT(tp, dev) && (oflags & O_NONBLOCK) == 0 && + if ((oflags & O_NONBLOCK) == 0 && (tp->t_termios.c_cflag & CLOCAL) == 0) { while ((ttydevsw_modem(tp, 0, 0) & SER_DCD) == 0) { error = tty_wait(tp, &tp->t_dcdwait); diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index de65462fb9a..30c1aa93a86 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -1747,15 +1747,23 @@ static void mqueue_send_notification(struct mqueue *mq) { struct mqueue_notifier *nt; + struct thread *td; struct proc *p; + int error; mtx_assert(&mq->mq_mutex, MA_OWNED); nt = mq->mq_notifier; if (nt->nt_sigev.sigev_notify != SIGEV_NONE) { p = nt->nt_proc; - PROC_LOCK(p); - if (!KSI_ONQ(&nt->nt_ksi)) - psignal_event(p, &nt->nt_sigev, &nt->nt_ksi); + error = sigev_findtd(p, &nt->nt_sigev, &td); + if (error) { + mq->mq_notifier = NULL; + return; + } + if (!KSI_ONQ(&nt->nt_ksi)) { + ksiginfo_set_sigev(&nt->nt_ksi, &nt->nt_sigev); + tdsendsignal(p, td, nt->nt_ksi.ksi_signo, &nt->nt_ksi); + } PROC_UNLOCK(p); } mq->mq_notifier = NULL; diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index d3aa490c315..d6c9854fa1f 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -559,9 +559,12 @@ solisten_proto(struct socket *so, int backlog) } /* - * Attempt to free a socket. This should really be sotryfree(). + * Evaluate the reference count and named references on a socket; if no + * references remain, free it. This should be called whenever a reference is + * released, such as in sorele(), but also when named reference flags are + * cleared in socket or protocol code. * - * sofree() will succeed if: + * sofree() will free the socket if: * * - There are no outstanding file descriptor references or related consumers * (so_count == 0). @@ -574,9 +577,6 @@ solisten_proto(struct socket *so, int backlog) * - The socket is not in a completed connection queue, so a process has been * notified that it is present. If it is removed, the user process may * block in accept() despite select() saying the socket was ready. - * - * Otherwise, it will quietly abort so that a future call to sofree(), when - * conditions are right, can succeed. */ void sofree(struct socket *so) diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 3165dab5c55..06869b21d28 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -2381,7 +2381,6 @@ sctp_generic_sendmsg (td, uap) struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL; struct socket *so; struct file *fp = NULL; - int use_rcvinfo = 1; int error = 0, len; struct sockaddr *to = NULL; #ifdef KTRACE @@ -2434,7 +2433,7 @@ sctp_generic_sendmsg (td, uap) CURVNET_SET(so->so_vnet); error = sctp_lower_sosend(so, to, &auio, (struct mbuf *)NULL, (struct mbuf *)NULL, - uap->flags, use_rcvinfo, u_sinfo, td); + uap->flags, u_sinfo, td); CURVNET_RESTORE(); if (error) { if (auio.uio_resid != len && (error == ERESTART || @@ -2485,7 +2484,6 @@ sctp_generic_sendmsg_iov(td, uap) struct sctp_sndrcvinfo sinfo, *u_sinfo = NULL; struct socket *so; struct file *fp = NULL; - int use_rcvinfo = 1; int error=0, len, i; struct sockaddr *to = NULL; #ifdef KTRACE @@ -2552,7 +2550,7 @@ sctp_generic_sendmsg_iov(td, uap) CURVNET_SET(so->so_vnet); error = sctp_lower_sosend(so, to, &auio, (struct mbuf *)NULL, (struct mbuf *)NULL, - uap->flags, use_rcvinfo, u_sinfo, td); + uap->flags, u_sinfo, td); CURVNET_RESTORE(); if (error) { if (auio.uio_resid != len && (error == ERESTART || diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index e05106a2c57..69b4e0a00c7 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -609,16 +609,20 @@ aio_init_aioinfo(struct proc *p) static int aio_sendsig(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi) { - int ret = 0; + struct thread *td; + int error; - PROC_LOCK(p); + error = sigev_findtd(p, sigev, &td); + if (error) + return (error); if (!KSI_ONQ(ksi)) { + ksiginfo_set_sigev(ksi, sigev); ksi->ksi_code = SI_ASYNCIO; ksi->ksi_flags |= KSI_EXT | KSI_INS; - ret = psignal_event(p, sigev, ksi); + tdsendsignal(p, td, ksi->ksi_signo, ksi); } PROC_UNLOCK(p); - return (ret); + return (error); } /* diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index c0732ac63f7..5a48a675d22 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -61,28 +61,28 @@ __FBSDID("$FreeBSD$"); #include SDT_PROVIDER_DECLARE(vfs); -SDT_PROBE_DEFINE3(vfs, namecache, enter, done, "struct vnode *", "char *", +SDT_PROBE_DEFINE3(vfs, namecache, enter, done, done, "struct vnode *", "char *", "struct vnode *"); -SDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, "struct vnode *", +SDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, done, "struct vnode *", "char *"); -SDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, "struct vnode *"); -SDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, "struct vnode *", +SDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, entry, "struct vnode *"); +SDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, hit, "struct vnode *", "struct char *", "struct vnode *"); -SDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, "struct vnode *"); -SDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, "int", "struct vnode *", - "struct char *"); -SDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, "struct vnode *", "char *", +SDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, miss, "struct vnode *"); +SDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, return, "int", + "struct vnode *", "struct char *"); +SDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, hit, "struct vnode *", "char *", "struct vnode *"); -SDT_PROBE_DEFINE2(vfs, namecache, lookup, hit_negative, "struct vnode *", +SDT_PROBE_DEFINE2(vfs, namecache, lookup, hit_negative, hit-negative, + "struct vnode *", "char *"); +SDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, miss, "struct vnode *", "char *"); -SDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, "struct vnode *", - "char *"); -SDT_PROBE_DEFINE1(vfs, namecache, purge, done, "struct vnode *"); -SDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *"); -SDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *"); -SDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *", +SDT_PROBE_DEFINE1(vfs, namecache, purge, done, done, "struct vnode *"); +SDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, done, "struct vnode *"); +SDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, done, "struct mount *"); +SDT_PROBE_DEFINE3(vfs, namecache, zap, done, done, "struct vnode *", "char *", "struct vnode *"); -SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *", +SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, done, "struct vnode *", "char *"); /* @@ -126,20 +126,27 @@ struct namecache { static LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */ static TAILQ_HEAD(, namecache) ncneg; /* Hash Table */ static u_long nchash; /* size of hash table */ -SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, ""); +SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, + "Size of namecache hash table"); static u_long ncnegfactor = 16; /* ratio of negative entries */ +/* _debug sysctl left for backward compatibility */ SYSCTL_ULONG(_debug, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0, ""); -static u_long numneg; /* number of cache entries allocated */ -SYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, ""); +SYSCTL_ULONG(_vfs, OID_AUTO, ncnegfactor, CTLFLAG_RW, &ncnegfactor, 0, + "Ratio of negative namecache entries"); +static u_long numneg; /* number of negative entries allocated */ +SYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, + "Number of negative entries in namecache"); static u_long numcache; /* number of cache entries allocated */ -SYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, ""); +SYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, + "Number of namecache entries"); static u_long numcachehv; /* number of cache entries with vnodes held */ -SYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0, ""); -#if 0 -static u_long numcachepl; /* number of cache purge for leaf entries */ -SYSCTL_ULONG(_debug, OID_AUTO, numcachepl, CTLFLAG_RD, &numcachepl, 0, ""); -#endif -struct nchstats nchstats; /* cache effectiveness statistics */ +SYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0, + "Number of namecache entries with vnodes held"); +static u_int ncsizefactor = 2; +SYSCTL_UINT(_vfs, OID_AUTO, ncsizefactor, CTLFLAG_RW, &ncsizefactor, 0, + "Size factor for namecache"); + +struct nchstats nchstats; /* cache effectiveness statistics */ static struct rwlock cache_lock; RW_SYSINIT(vfscache, &cache_lock, "Name Cache"); @@ -174,7 +181,8 @@ static uma_zone_t cache_zone_large; } while (0) static int doingcache = 1; /* 1 => enable the cache */ -SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, ""); +SYSCTL_INT(_debug, OID_AUTO, vfscache, CTLFLAG_RW, &doingcache, 0, + "VFS namecache enabled"); /* Export size information to userland */ SYSCTL_INT(_debug_sizeof, OID_AUTO, namecache, CTLFLAG_RD, 0, @@ -620,7 +628,7 @@ cache_enter(dvp, vp, cnp) /* * Avoid blowout in namecache entries. */ - if (numcache >= desiredvnodes * 2) + if (numcache >= desiredvnodes * ncsizefactor) return; flag = 0; diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c index 2d9a9082422..195e7354a3e 100644 --- a/sys/kern/vfs_default.c +++ b/sys/kern/vfs_default.c @@ -285,6 +285,9 @@ get_next_dirent(struct vnode *vp, struct dirent **dpp, char *dirbuf, *cpos = dirbuf; *len = (dirbuflen - uio.uio_resid); + + if (*len == 0) + return (ENOENT); } dp = (struct dirent *)(*cpos); diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 5b6ccf6ff46..50a2570254f 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -68,9 +68,9 @@ __FBSDID("$FreeBSD$"); #undef NAMEI_DIAGNOSTIC SDT_PROVIDER_DECLARE(vfs); -SDT_PROBE_DEFINE3(vfs, namei, lookup, entry, "struct vnode *", "char *", +SDT_PROBE_DEFINE3(vfs, namei, lookup, entry, entry, "struct vnode *", "char *", "unsigned long"); -SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *"); +SDT_PROBE_DEFINE2(vfs, namei, lookup, return, return, "int", "struct vnode *"); /* * Allocation zone for namei @@ -84,14 +84,13 @@ static struct vnode *vp_crossmp; static void nameiinit(void *dummy __unused) { - int error; namei_zone = uma_zcreate("NAMEI", MAXPATHLEN, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - error = getnewvnode("crossmp", NULL, &dead_vnodeops, &vp_crossmp); - if (error != 0) - panic("nameiinit: getnewvnode"); + getnewvnode("crossmp", NULL, &dead_vnodeops, &vp_crossmp); + vn_lock(vp_crossmp, LK_EXCLUSIVE); VN_LOCK_ASHARE(vp_crossmp); + VOP_UNLOCK(vp_crossmp, 0); } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL); diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 088d93973bd..83cbc604493 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -67,16 +67,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include "opt_rootdevname.h" - -#define ROOTNAME "root_device" #define VFS_MOUNTARG_SIZE_MAX (1024 * 64) -static void set_rootvnode(void); static int vfs_domount(struct thread *td, const char *fstype, char *fspath, int fsflags, void *fsdata); -static int vfs_mountroot_ask(void); -static int vfs_mountroot_try(const char *mountfrom, const char *options); static void free_mntarg(struct mntarg *ma); static int usermount = 0; @@ -94,31 +88,6 @@ struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist); struct mtx mountlist_mtx; MTX_SYSINIT(mountlist, &mountlist_mtx, "mountlist", MTX_DEF); -/* - * The vnode of the system's root (/ in the filesystem, without chroot - * active.) - */ -struct vnode *rootvnode; - -/* - * The root filesystem is detailed in the kernel environment variable - * vfs.root.mountfrom, which is expected to be in the general format - * - * :[][ :[] ...] - * vfsname := the name of a VFS known to the kernel and capable - * of being mounted as root - * path := disk device name or other data used by the filesystem - * to locate its physical store - * - * If the environment variable vfs.root.mountfrom is a space separated list, - * each list element is tried in turn and the root filesystem will be mounted - * from the first one that suceeds. - * - * The environment variable vfs.root.mountfrom.options is a comma delimited - * set of string mount options. These mount options must be parseable - * by nmount() in the kernel. - */ - /* * Global opts, taken by all filesystems */ @@ -133,21 +102,35 @@ static const char *global_opts[] = { NULL }; -/* - * The root specifiers we will try if RB_CDROM is specified. - */ -static char *cdrom_rootdevnames[] = { - "cd9660:cd0", - "cd9660:acd0", - NULL -}; +static int +mount_init(void *mem, int size, int flags) +{ + struct mount *mp; -/* legacy find-root code */ -char *rootdevnames[2] = {NULL, NULL}; -#ifndef ROOTDEVNAME -# define ROOTDEVNAME NULL -#endif -static const char *ctrootdevname = ROOTDEVNAME; + mp = (struct mount *)mem; + mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); + lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0); + return (0); +} + +static void +mount_fini(void *mem, int size) +{ + struct mount *mp; + + mp = (struct mount *)mem; + lockdestroy(&mp->mnt_explock); + mtx_destroy(&mp->mnt_mtx); +} + +static void +vfs_mount_init(void *dummy __unused) +{ + + mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount), NULL, + NULL, mount_init, mount_fini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); +} +SYSINIT(vfs_mount, SI_SUB_VFS, SI_ORDER_ANY, vfs_mount_init, NULL); /* * --------------------------------------------------------------------- @@ -452,27 +435,6 @@ vfs_rel(struct mount *mp) MNT_IUNLOCK(mp); } -static int -mount_init(void *mem, int size, int flags) -{ - struct mount *mp; - - mp = (struct mount *)mem; - mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); - lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0); - return (0); -} - -static void -mount_fini(void *mem, int size) -{ - struct mount *mp; - - mp = (struct mount *)mem; - lockdestroy(&mp->mnt_explock); - mtx_destroy(&mp->mnt_mtx); -} - /* * Allocate and initialize the mount point struct. */ @@ -704,9 +666,7 @@ vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions) goto bail; } - mtx_lock(&Giant); error = vfs_domount(td, fstype, fspath, fsflags, optlist); - mtx_unlock(&Giant); bail: /* copyout the errmsg */ if (errmsg_pos != -1 && ((2 * errmsg_pos + 1) < fsoptions->uio_iovcnt) @@ -795,6 +755,256 @@ mount(td, uap) return (error); } +/* + * vfs_domount_first(): first file system mount (not update) + */ +static int +vfs_domount_first( + struct thread *td, /* Calling thread. */ + struct vfsconf *vfsp, /* File system type. */ + char *fspath, /* Mount path. */ + struct vnode *vp, /* Vnode to be covered. */ + int fsflags, /* Flags common to all filesystems. */ + void *fsdata /* Options local to the filesystem. */ + ) +{ + struct vattr va; + struct mount *mp; + struct vnode *newdp; + int error; + + mtx_assert(&Giant, MA_OWNED); + ASSERT_VOP_ELOCKED(vp, __func__); + KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here")); + + /* + * If the user is not root, ensure that they own the directory + * onto which we are attempting to mount. + */ + error = VOP_GETATTR(vp, &va, td->td_ucred); + if (error == 0 && va.va_uid != td->td_ucred->cr_uid) + error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, 0); + if (error == 0) + error = vinvalbuf(vp, V_SAVE, 0, 0); + if (error == 0 && vp->v_type != VDIR) + error = ENOTDIR; + if (error == 0) { + VI_LOCK(vp); + if ((vp->v_iflag & VI_MOUNT) == 0 && vp->v_mountedhere == NULL) + vp->v_iflag |= VI_MOUNT; + else + error = EBUSY; + VI_UNLOCK(vp); + } + if (error != 0) { + vput(vp); + return (error); + } + VOP_UNLOCK(vp, 0); + + /* Allocate and initialize the filesystem. */ + mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred); + /* XXXMAC: pass to vfs_mount_alloc? */ + mp->mnt_optnew = fsdata; + /* Set the mount level flags. */ + mp->mnt_flag = (fsflags & (MNT_UPDATEMASK | MNT_ROOTFS | MNT_RDONLY)); + + /* + * Mount the filesystem. + * XXX The final recipients of VFS_MOUNT just overwrite the ndp they + * get. No freeing of cn_pnbuf. + */ + error = VFS_MOUNT(mp); + if (error != 0) { + vfs_unbusy(mp); + vfs_mount_destroy(mp); + VI_LOCK(vp); + vp->v_iflag &= ~VI_MOUNT; + VI_UNLOCK(vp); + vrele(vp); + return (error); + } + + if (mp->mnt_opt != NULL) + vfs_freeopts(mp->mnt_opt); + mp->mnt_opt = mp->mnt_optnew; + (void)VFS_STATFS(mp, &mp->mnt_stat); + + /* + * Prevent external consumers of mount options from reading mnt_optnew. + */ + mp->mnt_optnew = NULL; + + MNT_ILOCK(mp); + if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) + mp->mnt_kern_flag |= MNTK_ASYNC; + else + mp->mnt_kern_flag &= ~MNTK_ASYNC; + MNT_IUNLOCK(mp); + + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + cache_purge(vp); + VI_LOCK(vp); + vp->v_iflag &= ~VI_MOUNT; + VI_UNLOCK(vp); + vp->v_mountedhere = mp; + /* Place the new filesystem at the end of the mount list. */ + mtx_lock(&mountlist_mtx); + TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); + mtx_unlock(&mountlist_mtx); + vfs_event_signal(NULL, VQ_MOUNT, 0); + if (VFS_ROOT(mp, LK_EXCLUSIVE, &newdp)) + panic("mount: lost mount"); + VOP_UNLOCK(newdp, 0); + VOP_UNLOCK(vp, 0); + mountcheckdirs(vp, newdp); + vrele(newdp); + if ((mp->mnt_flag & MNT_RDONLY) == 0) + vfs_allocate_syncvnode(mp); + vfs_unbusy(mp); + return (0); +} + +/* + * vfs_domount_update(): update of mounted file system + */ +static int +vfs_domount_update( + struct thread *td, /* Calling thread. */ + struct vnode *vp, /* Mount point vnode. */ + int fsflags, /* Flags common to all filesystems. */ + void *fsdata /* Options local to the filesystem. */ + ) +{ + struct oexport_args oexport; + struct export_args export; + struct mount *mp; + int error, flag; + + mtx_assert(&Giant, MA_OWNED); + ASSERT_VOP_ELOCKED(vp, __func__); + KASSERT((fsflags & MNT_UPDATE) != 0, ("MNT_UPDATE should be here")); + + if ((vp->v_vflag & VV_ROOT) == 0) { + vput(vp); + return (EINVAL); + } + mp = vp->v_mount; + /* + * We only allow the filesystem to be reloaded if it + * is currently mounted read-only. + */ + flag = mp->mnt_flag; + if ((fsflags & MNT_RELOAD) != 0 && (flag & MNT_RDONLY) == 0) { + vput(vp); + return (EOPNOTSUPP); /* Needs translation */ + } + /* + * Only privileged root, or (if MNT_USER is set) the user that + * did the original mount is permitted to update it. + */ + error = vfs_suser(mp, td); + if (error != 0) { + vput(vp); + return (error); + } + if (vfs_busy(mp, MBF_NOWAIT)) { + vput(vp); + return (EBUSY); + } + VI_LOCK(vp); + if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) { + VI_UNLOCK(vp); + vfs_unbusy(mp); + vput(vp); + return (EBUSY); + } + vp->v_iflag |= VI_MOUNT; + VI_UNLOCK(vp); + VOP_UNLOCK(vp, 0); + + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_UPDATEMASK; + mp->mnt_flag |= fsflags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | + MNT_SNAPSHOT | MNT_ROOTFS | MNT_UPDATEMASK | MNT_RDONLY); + if ((mp->mnt_flag & MNT_ASYNC) == 0) + mp->mnt_kern_flag &= ~MNTK_ASYNC; + MNT_IUNLOCK(mp); + mp->mnt_optnew = fsdata; + vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); + + /* + * Mount the filesystem. + * XXX The final recipients of VFS_MOUNT just overwrite the ndp they + * get. No freeing of cn_pnbuf. + */ + error = VFS_MOUNT(mp); + + if (error == 0) { + /* Process the export option. */ + if (vfs_copyopt(mp->mnt_optnew, "export", &export, + sizeof(export)) == 0) { + error = vfs_export(mp, &export); + } else if (vfs_copyopt(mp->mnt_optnew, "export", &oexport, + sizeof(oexport)) == 0) { + export.ex_flags = oexport.ex_flags; + export.ex_root = oexport.ex_root; + export.ex_anon = oexport.ex_anon; + export.ex_addr = oexport.ex_addr; + export.ex_addrlen = oexport.ex_addrlen; + export.ex_mask = oexport.ex_mask; + export.ex_masklen = oexport.ex_masklen; + export.ex_indexfile = oexport.ex_indexfile; + export.ex_numsecflavors = 0; + error = vfs_export(mp, &export); + } + } + + MNT_ILOCK(mp); + if (error == 0) { + mp->mnt_flag &= ~(MNT_UPDATE | MNT_RELOAD | MNT_FORCE | + MNT_SNAPSHOT); + } else { + /* + * If we fail, restore old mount flags. MNT_QUOTA is special, + * because it is not part of MNT_UPDATEMASK, but it could have + * changed in the meantime if quotactl(2) was called. + * All in all we want current value of MNT_QUOTA, not the old + * one. + */ + mp->mnt_flag = (mp->mnt_flag & MNT_QUOTA) | (flag & ~MNT_QUOTA); + } + if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) + mp->mnt_kern_flag |= MNTK_ASYNC; + else + mp->mnt_kern_flag &= ~MNTK_ASYNC; + MNT_IUNLOCK(mp); + + if (error != 0) + goto end; + + if (mp->mnt_opt != NULL) + vfs_freeopts(mp->mnt_opt); + mp->mnt_opt = mp->mnt_optnew; + (void)VFS_STATFS(mp, &mp->mnt_stat); + /* + * Prevent external consumers of mount options from reading + * mnt_optnew. + */ + mp->mnt_optnew = NULL; + + if ((mp->mnt_flag & MNT_RDONLY) == 0) + vfs_allocate_syncvnode(mp); + else + vfs_deallocate_syncvnode(mp); +end: + vfs_unbusy(mp); + VI_LOCK(vp); + vp->v_iflag &= ~VI_MOUNT; + VI_UNLOCK(vp); + vrele(vp); + return (error); +} /* * vfs_domount(): actually attempt a filesystem mount. @@ -808,16 +1018,11 @@ vfs_domount( void *fsdata /* Options local to the filesystem. */ ) { - struct vnode *vp; - struct mount *mp; struct vfsconf *vfsp; - struct oexport_args oexport; - struct export_args export; - int error, flag = 0; - struct vattr va; struct nameidata nd; + struct vnode *vp; + int error; - mtx_assert(&Giant, MA_OWNED); /* * Be ultra-paranoid about making sure the type and fspath * variables will fit in our mp buffers, including the @@ -865,228 +1070,30 @@ vfs_domount( if (jailed(td->td_ucred) && !(vfsp->vfc_flags & VFCF_JAIL)) return (EPERM); } + /* - * Get vnode to be covered + * Get vnode to be covered or mount point's vnode in case of MNT_UPDATE. */ - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_SYSSPACE, - fspath, td); - if ((error = namei(&nd)) != 0) + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, + UIO_SYSSPACE, fspath, td); + error = namei(&nd); + if (error != 0) return (error); + if (!NDHASGIANT(&nd)) + mtx_lock(&Giant); NDFREE(&nd, NDF_ONLY_PNBUF); vp = nd.ni_vp; - if (fsflags & MNT_UPDATE) { - if ((vp->v_vflag & VV_ROOT) == 0) { - vput(vp); - return (EINVAL); - } - mp = vp->v_mount; - MNT_ILOCK(mp); - flag = mp->mnt_flag; - /* - * We only allow the filesystem to be reloaded if it - * is currently mounted read-only. - */ - if ((fsflags & MNT_RELOAD) && - ((mp->mnt_flag & MNT_RDONLY) == 0)) { - MNT_IUNLOCK(mp); - vput(vp); - return (EOPNOTSUPP); /* Needs translation */ - } - MNT_IUNLOCK(mp); - /* - * Only privileged root, or (if MNT_USER is set) the user that - * did the original mount is permitted to update it. - */ - error = vfs_suser(mp, td); - if (error) { - vput(vp); - return (error); - } - if (vfs_busy(mp, MBF_NOWAIT)) { - vput(vp); - return (EBUSY); - } - VI_LOCK(vp); - if ((vp->v_iflag & VI_MOUNT) != 0 || - vp->v_mountedhere != NULL) { - VI_UNLOCK(vp); - vfs_unbusy(mp); - vput(vp); - return (EBUSY); - } - vp->v_iflag |= VI_MOUNT; - VI_UNLOCK(vp); - MNT_ILOCK(mp); - mp->mnt_flag |= fsflags & - (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT | MNT_ROOTFS); - MNT_IUNLOCK(mp); - VOP_UNLOCK(vp, 0); - mp->mnt_optnew = fsdata; - vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); + if ((fsflags & MNT_UPDATE) == 0) { + error = vfs_domount_first(td, vfsp, fspath, vp, fsflags, + fsdata); } else { - /* - * If the user is not root, ensure that they own the directory - * onto which we are attempting to mount. - */ - error = VOP_GETATTR(vp, &va, td->td_ucred); - if (error) { - vput(vp); - return (error); - } - if (va.va_uid != td->td_ucred->cr_uid) { - error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, - 0); - if (error) { - vput(vp); - return (error); - } - } - error = vinvalbuf(vp, V_SAVE, 0, 0); - if (error != 0) { - vput(vp); - return (error); - } - if (vp->v_type != VDIR) { - vput(vp); - return (ENOTDIR); - } - VI_LOCK(vp); - if ((vp->v_iflag & VI_MOUNT) != 0 || - vp->v_mountedhere != NULL) { - VI_UNLOCK(vp); - vput(vp); - return (EBUSY); - } - vp->v_iflag |= VI_MOUNT; - VI_UNLOCK(vp); - VOP_UNLOCK(vp, 0); - - /* - * Allocate and initialize the filesystem. - */ - mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred); - - /* XXXMAC: pass to vfs_mount_alloc? */ - mp->mnt_optnew = fsdata; + error = vfs_domount_update(td, vp, fsflags, fsdata); } + mtx_unlock(&Giant); - /* - * Set the mount level flags. - */ - MNT_ILOCK(mp); - mp->mnt_flag = (mp->mnt_flag & ~MNT_UPDATEMASK) | - (fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS | - MNT_RDONLY)); - if ((mp->mnt_flag & MNT_ASYNC) == 0) - mp->mnt_kern_flag &= ~MNTK_ASYNC; - MNT_IUNLOCK(mp); - /* - * Mount the filesystem. - * XXX The final recipients of VFS_MOUNT just overwrite the ndp they - * get. No freeing of cn_pnbuf. - */ - error = VFS_MOUNT(mp); + ASSERT_VI_UNLOCKED(vp, __func__); + ASSERT_VOP_UNLOCKED(vp, __func__); - /* - * Process the export option only if we are - * updating mount options. - */ - if (!error && (fsflags & MNT_UPDATE)) { - if (vfs_copyopt(mp->mnt_optnew, "export", &export, - sizeof(export)) == 0) - error = vfs_export(mp, &export); - else if (vfs_copyopt(mp->mnt_optnew, "export", &oexport, - sizeof(oexport)) == 0) { - export.ex_flags = oexport.ex_flags; - export.ex_root = oexport.ex_root; - export.ex_anon = oexport.ex_anon; - export.ex_addr = oexport.ex_addr; - export.ex_addrlen = oexport.ex_addrlen; - export.ex_mask = oexport.ex_mask; - export.ex_masklen = oexport.ex_masklen; - export.ex_indexfile = oexport.ex_indexfile; - export.ex_numsecflavors = 0; - error = vfs_export(mp, &export); - } - } - - if (!error) { - if (mp->mnt_opt != NULL) - vfs_freeopts(mp->mnt_opt); - mp->mnt_opt = mp->mnt_optnew; - (void)VFS_STATFS(mp, &mp->mnt_stat); - } - /* - * Prevent external consumers of mount options from reading - * mnt_optnew. - */ - mp->mnt_optnew = NULL; - if (mp->mnt_flag & MNT_UPDATE) { - MNT_ILOCK(mp); - if (error) - mp->mnt_flag = (mp->mnt_flag & MNT_QUOTA) | - (flag & ~MNT_QUOTA); - else - mp->mnt_flag &= ~(MNT_UPDATE | MNT_RELOAD | - MNT_FORCE | MNT_SNAPSHOT); - if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) - mp->mnt_kern_flag |= MNTK_ASYNC; - else - mp->mnt_kern_flag &= ~MNTK_ASYNC; - MNT_IUNLOCK(mp); - if ((mp->mnt_flag & MNT_RDONLY) == 0) { - if (mp->mnt_syncer == NULL) - error = vfs_allocate_syncvnode(mp); - } else { - if (mp->mnt_syncer != NULL) - vrele(mp->mnt_syncer); - mp->mnt_syncer = NULL; - } - vfs_unbusy(mp); - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - vrele(vp); - return (error); - } - MNT_ILOCK(mp); - if ((mp->mnt_flag & MNT_ASYNC) != 0 && mp->mnt_noasync == 0) - mp->mnt_kern_flag |= MNTK_ASYNC; - else - mp->mnt_kern_flag &= ~MNTK_ASYNC; - MNT_IUNLOCK(mp); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - /* - * Put the new filesystem on the mount list after root. - */ - cache_purge(vp); - VI_LOCK(vp); - vp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(vp); - if (!error) { - struct vnode *newdp; - - vp->v_mountedhere = mp; - mtx_lock(&mountlist_mtx); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mtx_unlock(&mountlist_mtx); - vfs_event_signal(NULL, VQ_MOUNT, 0); - if (VFS_ROOT(mp, LK_EXCLUSIVE, &newdp)) - panic("mount: lost mount"); - VOP_UNLOCK(newdp, 0); - VOP_UNLOCK(vp, 0); - mountcheckdirs(vp, newdp); - vrele(newdp); - if ((mp->mnt_flag & MNT_RDONLY) == 0) - error = vfs_allocate_syncvnode(mp); - vfs_unbusy(mp); - if (error) - vrele(vp); - } else { - vfs_unbusy(mp); - vfs_mount_destroy(mp); - vput(vp); - } return (error); } @@ -1269,8 +1276,7 @@ dounmount(mp, flags, td) mp->mnt_kern_flag &= ~MNTK_ASYNC; MNT_IUNLOCK(mp); cache_purgevfs(mp); /* remove cache entries for this file sys */ - if (mp->mnt_syncer != NULL) - vrele(mp->mnt_syncer); + vfs_deallocate_syncvnode(mp); /* * For forced unmounts, move process cdir/rdir refs on the fs root * vnode to the covered vnode. For non-forced unmounts we want @@ -1309,9 +1315,9 @@ dounmount(mp, flags, td) } MNT_ILOCK(mp); mp->mnt_kern_flag &= ~MNTK_NOINSMNTQ; - if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) { + if ((mp->mnt_flag & MNT_RDONLY) == 0) { MNT_IUNLOCK(mp); - (void) vfs_allocate_syncvnode(mp); + vfs_allocate_syncvnode(mp); MNT_ILOCK(mp); } mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); @@ -1339,269 +1345,6 @@ dounmount(mp, flags, td) return (0); } -/* - * --------------------------------------------------------------------- - * Mounting of root filesystem - * - */ - -struct root_hold_token { - const char *who; - LIST_ENTRY(root_hold_token) list; -}; - -static LIST_HEAD(, root_hold_token) root_holds = - LIST_HEAD_INITIALIZER(root_holds); - -static int root_mount_complete; - -/* - * Hold root mount. - */ -struct root_hold_token * -root_mount_hold(const char *identifier) -{ - struct root_hold_token *h; - - if (root_mounted()) - return (NULL); - - h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK); - h->who = identifier; - mtx_lock(&mountlist_mtx); - LIST_INSERT_HEAD(&root_holds, h, list); - mtx_unlock(&mountlist_mtx); - return (h); -} - -/* - * Release root mount. - */ -void -root_mount_rel(struct root_hold_token *h) -{ - - if (h == NULL) - return; - mtx_lock(&mountlist_mtx); - LIST_REMOVE(h, list); - wakeup(&root_holds); - mtx_unlock(&mountlist_mtx); - free(h, M_DEVBUF); -} - -/* - * Wait for all subsystems to release root mount. - */ -static void -root_mount_prepare(void) -{ - struct root_hold_token *h; - struct timeval lastfail; - int curfail = 0; - - for (;;) { - DROP_GIANT(); - g_waitidle(); - PICKUP_GIANT(); - mtx_lock(&mountlist_mtx); - if (LIST_EMPTY(&root_holds)) { - mtx_unlock(&mountlist_mtx); - break; - } - if (ppsratecheck(&lastfail, &curfail, 1)) { - printf("Root mount waiting for:"); - LIST_FOREACH(h, &root_holds, list) - printf(" %s", h->who); - printf("\n"); - } - msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold", - hz); - } -} - -/* - * Root was mounted, share the good news. - */ -static void -root_mount_done(void) -{ - - /* Keep prison0's root in sync with the global rootvnode. */ - mtx_lock(&prison0.pr_mtx); - prison0.pr_root = rootvnode; - vref(prison0.pr_root); - mtx_unlock(&prison0.pr_mtx); - /* - * Use a mutex to prevent the wakeup being missed and waiting for - * an extra 1 second sleep. - */ - mtx_lock(&mountlist_mtx); - root_mount_complete = 1; - wakeup(&root_mount_complete); - mtx_unlock(&mountlist_mtx); -} - -/* - * Return true if root is already mounted. - */ -int -root_mounted(void) -{ - - /* No mutex is acquired here because int stores are atomic. */ - return (root_mount_complete); -} - -/* - * Wait until root is mounted. - */ -void -root_mount_wait(void) -{ - - /* - * Panic on an obvious deadlock - the function can't be called from - * a thread which is doing the whole SYSINIT stuff. - */ - KASSERT(curthread->td_proc->p_pid != 0, - ("root_mount_wait: cannot be called from the swapper thread")); - mtx_lock(&mountlist_mtx); - while (!root_mount_complete) { - msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait", - hz); - } - mtx_unlock(&mountlist_mtx); -} - -static void -set_rootvnode() -{ - struct proc *p; - - if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode)) - panic("Cannot find root vnode"); - - VOP_UNLOCK(rootvnode, 0); - - p = curthread->td_proc; - FILEDESC_XLOCK(p->p_fd); - - if (p->p_fd->fd_cdir != NULL) - vrele(p->p_fd->fd_cdir); - p->p_fd->fd_cdir = rootvnode; - VREF(rootvnode); - - if (p->p_fd->fd_rdir != NULL) - vrele(p->p_fd->fd_rdir); - p->p_fd->fd_rdir = rootvnode; - VREF(rootvnode); - - FILEDESC_XUNLOCK(p->p_fd); - - EVENTHANDLER_INVOKE(mountroot); -} - -/* - * Mount /devfs as our root filesystem, but do not put it on the mountlist - * yet. Create a /dev -> / symlink so that absolute pathnames will lookup. - */ - -static void -devfs_first(void) -{ - struct thread *td = curthread; - struct vfsoptlist *opts; - struct vfsconf *vfsp; - struct mount *mp = NULL; - int error; - - vfsp = vfs_byname("devfs"); - KASSERT(vfsp != NULL, ("Could not find devfs by name")); - if (vfsp == NULL) - return; - - mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred); - - error = VFS_MOUNT(mp); - KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error)); - if (error) - return; - - opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); - TAILQ_INIT(opts); - mp->mnt_opt = opts; - - mtx_lock(&mountlist_mtx); - TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); - mtx_unlock(&mountlist_mtx); - - set_rootvnode(); - - error = kern_symlink(td, "/", "dev", UIO_SYSSPACE); - if (error) - printf("kern_symlink /dev -> / returns %d\n", error); -} - -/* - * Surgically move our devfs to be mounted on /dev. - */ - -static void -devfs_fixup(struct thread *td) -{ - struct nameidata nd; - int error; - struct vnode *vp, *dvp; - struct mount *mp; - - /* Remove our devfs mount from the mountlist and purge the cache */ - mtx_lock(&mountlist_mtx); - mp = TAILQ_FIRST(&mountlist); - TAILQ_REMOVE(&mountlist, mp, mnt_list); - mtx_unlock(&mountlist_mtx); - cache_purgevfs(mp); - - VFS_ROOT(mp, LK_EXCLUSIVE, &dvp); - VI_LOCK(dvp); - dvp->v_iflag &= ~VI_MOUNT; - VI_UNLOCK(dvp); - dvp->v_mountedhere = NULL; - - /* Set up the real rootvnode, and purge the cache */ - TAILQ_FIRST(&mountlist)->mnt_vnodecovered = NULL; - set_rootvnode(); - cache_purgevfs(rootvnode->v_mount); - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td); - error = namei(&nd); - if (error) { - printf("Lookup of /dev for devfs, error: %d\n", error); - return; - } - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; - if (vp->v_type != VDIR) { - vput(vp); - } - error = vinvalbuf(vp, V_SAVE, 0, 0); - if (error) { - vput(vp); - } - cache_purge(vp); - mp->mnt_vnodecovered = vp; - vp->v_mountedhere = mp; - mtx_lock(&mountlist_mtx); - TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); - mtx_unlock(&mountlist_mtx); - VOP_UNLOCK(vp, 0); - vput(dvp); - vfs_unbusy(mp); - - /* Unlink the no longer needed /dev/dev -> / symlink */ - kern_unlink(td, "/dev/dev", UIO_SYSSPACE); -} - /* * Report errors during filesystem mounting. */ @@ -1638,288 +1381,6 @@ vfs_opterror(struct vfsoptlist *opts, const char *fmt, ...) va_end(ap); } -/* - * Find and mount the root filesystem - */ -void -vfs_mountroot(void) -{ - char *cp, *cpt, *options, *tmpdev; - int error, i, asked = 0; - - options = NULL; - - root_mount_prepare(); - - mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount), - NULL, NULL, mount_init, mount_fini, - UMA_ALIGN_PTR, UMA_ZONE_NOFREE); - devfs_first(); - - /* - * We are booted with instructions to prompt for the root filesystem. - */ - if (boothowto & RB_ASKNAME) { - if (!vfs_mountroot_ask()) - goto mounted; - asked = 1; - } - - options = getenv("vfs.root.mountfrom.options"); - - /* - * The root filesystem information is compiled in, and we are - * booted with instructions to use it. - */ - if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) { - if (!vfs_mountroot_try(ctrootdevname, options)) - goto mounted; - ctrootdevname = NULL; - } - - /* - * We've been given the generic "use CDROM as root" flag. This is - * necessary because one media may be used in many different - * devices, so we need to search for them. - */ - if (boothowto & RB_CDROM) { - for (i = 0; cdrom_rootdevnames[i] != NULL; i++) { - if (!vfs_mountroot_try(cdrom_rootdevnames[i], options)) - goto mounted; - } - } - - /* - * Try to use the value read by the loader from /etc/fstab, or - * supplied via some other means. This is the preferred - * mechanism. - */ - cp = getenv("vfs.root.mountfrom"); - if (cp != NULL) { - cpt = cp; - while ((tmpdev = strsep(&cpt, " \t")) != NULL) { - error = vfs_mountroot_try(tmpdev, options); - if (error == 0) { - freeenv(cp); - goto mounted; - } - } - freeenv(cp); - } - - /* - * Try values that may have been computed by code during boot - */ - if (!vfs_mountroot_try(rootdevnames[0], options)) - goto mounted; - if (!vfs_mountroot_try(rootdevnames[1], options)) - goto mounted; - - /* - * If we (still) have a compiled-in default, try it. - */ - if (ctrootdevname != NULL) - if (!vfs_mountroot_try(ctrootdevname, options)) - goto mounted; - /* - * Everything so far has failed, prompt on the console if we haven't - * already tried that. - */ - if (!asked) - if (!vfs_mountroot_ask()) - goto mounted; - - panic("Root mount failed, startup aborted."); - -mounted: - root_mount_done(); - freeenv(options); -} - -static struct mntarg * -parse_mountroot_options(struct mntarg *ma, const char *options) -{ - char *p; - char *name, *name_arg; - char *val, *val_arg; - char *opts; - - if (options == NULL || options[0] == '\0') - return (ma); - - p = opts = strdup(options, M_MOUNT); - if (opts == NULL) { - return (ma); - } - - while((name = strsep(&p, ",")) != NULL) { - if (name[0] == '\0') - break; - - val = strchr(name, '='); - if (val != NULL) { - *val = '\0'; - ++val; - } - if( strcmp(name, "rw") == 0 || - strcmp(name, "noro") == 0) { - /* - * The first time we mount the root file system, - * we need to mount 'ro', so We need to ignore - * 'rw' and 'noro' mount options. - */ - continue; - } - name_arg = strdup(name, M_MOUNT); - val_arg = NULL; - if (val != NULL) - val_arg = strdup(val, M_MOUNT); - - ma = mount_arg(ma, name_arg, val_arg, - (val_arg != NULL ? -1 : 0)); - } - free(opts, M_MOUNT); - return (ma); -} - -/* - * Mount (mountfrom) as the root filesystem. - */ -static int -vfs_mountroot_try(const char *mountfrom, const char *options) -{ - struct mount *mp; - struct mntarg *ma; - char *vfsname, *path; - time_t timebase; - int error; - char patt[32]; - char errmsg[255]; - - vfsname = NULL; - path = NULL; - mp = NULL; - ma = NULL; - error = EINVAL; - bzero(errmsg, sizeof(errmsg)); - - if (mountfrom == NULL) - return (error); /* don't complain */ - printf("Trying to mount root from %s\n", mountfrom); - - /* parse vfs name and path */ - vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK); - path = malloc(MNAMELEN, M_MOUNT, M_WAITOK); - vfsname[0] = path[0] = 0; - sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); - if (sscanf(mountfrom, patt, vfsname, path) < 1) - goto out; - - if (path[0] == '\0') - strcpy(path, ROOTNAME); - - ma = mount_arg(ma, "fstype", vfsname, -1); - ma = mount_arg(ma, "fspath", "/", -1); - ma = mount_arg(ma, "from", path, -1); - ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg)); - ma = mount_arg(ma, "ro", NULL, 0); - ma = parse_mountroot_options(ma, options); - error = kernel_mount(ma, MNT_ROOTFS); - - if (error == 0) { - /* - * We mount devfs prior to mounting the / FS, so the first - * entry will typically be devfs. - */ - mp = TAILQ_FIRST(&mountlist); - KASSERT(mp != NULL, ("%s: mountlist is empty", __func__)); - - /* - * Iterate over all currently mounted file systems and use - * the time stamp found to check and/or initialize the RTC. - * Typically devfs has no time stamp and the only other FS - * is the actual / FS. - * Call inittodr() only once and pass it the largest of the - * timestamps we encounter. - */ - timebase = 0; - do { - if (mp->mnt_time > timebase) - timebase = mp->mnt_time; - mp = TAILQ_NEXT(mp, mnt_list); - } while (mp != NULL); - inittodr(timebase); - - devfs_fixup(curthread); - } - - if (error != 0 ) { - printf("ROOT MOUNT ERROR: %s\n", errmsg); - printf("If you have invalid mount options, reboot, and "); - printf("first try the following from\n"); - printf("the loader prompt:\n\n"); - printf(" set vfs.root.mountfrom.options=rw\n\n"); - printf("and then remove invalid mount options from "); - printf("/etc/fstab.\n\n"); - } -out: - free(path, M_MOUNT); - free(vfsname, M_MOUNT); - return (error); -} - -/* - * --------------------------------------------------------------------- - * Interactive root filesystem selection code. - */ - -static int -vfs_mountroot_ask(void) -{ - char name[128]; - char *mountfrom; - char *options; - - for(;;) { - printf("Loader variables:\n"); - printf("vfs.root.mountfrom="); - mountfrom = getenv("vfs.root.mountfrom"); - if (mountfrom != NULL) { - printf("%s", mountfrom); - } - printf("\n"); - printf("vfs.root.mountfrom.options="); - options = getenv("vfs.root.mountfrom.options"); - if (options != NULL) { - printf("%s", options); - } - printf("\n"); - freeenv(mountfrom); - freeenv(options); - printf("\nManual root filesystem specification:\n"); - printf(" : Mount using filesystem \n"); - printf(" eg. zfs:tank\n"); - printf(" eg. ufs:/dev/da0s1a\n"); - printf(" eg. cd9660:/dev/acd0\n"); - printf(" This is equivalent to: "); - printf("mount -t cd9660 /dev/acd0 /\n"); - printf("\n"); - printf(" ? List valid disk boot devices\n"); - printf(" Abort manual input\n"); - printf("\nmountroot> "); - gets(name, sizeof(name), 1); - if (name[0] == '\0') - return (1); - if (name[0] == '?') { - printf("\nList of GEOM managed disk devices:\n "); - g_dev_print(); - continue; - } - if (!vfs_mountroot_try(name, NULL)) - return (0); - } -} - /* * --------------------------------------------------------------------- * Functions for querying mount options/arguments from filesystems. @@ -1963,15 +1424,17 @@ vfs_filteropt(struct vfsoptlist *opts, const char **legal) continue; snprintf(errmsg, sizeof(errmsg), "mount option <%s> is unknown", p); - printf("%s\n", errmsg); ret = EINVAL; } if (ret != 0) { TAILQ_FOREACH(opt, opts, link) { if (strcmp(opt->name, "errmsg") == 0) { strncpy((char *)opt->value, errmsg, opt->len); + break; } } + if (opt == NULL) + printf("%s\n", errmsg); } return (ret); } @@ -2499,3 +1962,11 @@ kernel_vmount(int flags, ...) error = kernel_mount(ma, flags); return (error); } + +void +vfs_oexport_conv(const struct oexport_args *oexp, struct export_args *exp) +{ + + bcopy(oexp, exp, sizeof(*oexp)); + exp->ex_numsecflavors = 0; +} diff --git a/sys/kern/vfs_mountroot.c b/sys/kern/vfs_mountroot.c new file mode 100644 index 00000000000..07c29882c5b --- /dev/null +++ b/sys/kern/vfs_mountroot.c @@ -0,0 +1,1039 @@ +/*- + * Copyright (c) 2010 Marcel Moolenaar + * Copyright (c) 1999-2004 Poul-Henning Kamp + * Copyright (c) 1999 Michael Smith + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_rootdevname.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * The root filesystem is detailed in the kernel environment variable + * vfs.root.mountfrom, which is expected to be in the general format + * + * :[][ :[] ...] + * vfsname := the name of a VFS known to the kernel and capable + * of being mounted as root + * path := disk device name or other data used by the filesystem + * to locate its physical store + * + * If the environment variable vfs.root.mountfrom is a space separated list, + * each list element is tried in turn and the root filesystem will be mounted + * from the first one that suceeds. + * + * The environment variable vfs.root.mountfrom.options is a comma delimited + * set of string mount options. These mount options must be parseable + * by nmount() in the kernel. + */ + +static int parse_mount(char **); +static struct mntarg *parse_mountroot_options(struct mntarg *, const char *); + +/* + * The vnode of the system's root (/ in the filesystem, without chroot + * active.) + */ +struct vnode *rootvnode; + +char *rootdevnames[2] = {NULL, NULL}; + +struct root_hold_token { + const char *who; + LIST_ENTRY(root_hold_token) list; +}; + +static LIST_HEAD(, root_hold_token) root_holds = + LIST_HEAD_INITIALIZER(root_holds); + +enum action { + A_CONTINUE, + A_PANIC, + A_REBOOT, + A_RETRY +}; + +static enum action root_mount_onfail = A_CONTINUE; + +static int root_mount_mddev; +static int root_mount_complete; + +/* By default wait up to 3 seconds for devices to appear. */ +static int root_mount_timeout = 3; + +struct root_hold_token * +root_mount_hold(const char *identifier) +{ + struct root_hold_token *h; + + if (root_mounted()) + return (NULL); + + h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK); + h->who = identifier; + mtx_lock(&mountlist_mtx); + LIST_INSERT_HEAD(&root_holds, h, list); + mtx_unlock(&mountlist_mtx); + return (h); +} + +void +root_mount_rel(struct root_hold_token *h) +{ + + if (h == NULL) + return; + mtx_lock(&mountlist_mtx); + LIST_REMOVE(h, list); + wakeup(&root_holds); + mtx_unlock(&mountlist_mtx); + free(h, M_DEVBUF); +} + +int +root_mounted(void) +{ + + /* No mutex is acquired here because int stores are atomic. */ + return (root_mount_complete); +} + +void +root_mount_wait(void) +{ + + /* + * Panic on an obvious deadlock - the function can't be called from + * a thread which is doing the whole SYSINIT stuff. + */ + KASSERT(curthread->td_proc->p_pid != 0, + ("root_mount_wait: cannot be called from the swapper thread")); + mtx_lock(&mountlist_mtx); + while (!root_mount_complete) { + msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait", + hz); + } + mtx_unlock(&mountlist_mtx); +} + +static void +set_rootvnode(void) +{ + struct proc *p; + + if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode)) + panic("Cannot find root vnode"); + + VOP_UNLOCK(rootvnode, 0); + + p = curthread->td_proc; + FILEDESC_XLOCK(p->p_fd); + + if (p->p_fd->fd_cdir != NULL) + vrele(p->p_fd->fd_cdir); + p->p_fd->fd_cdir = rootvnode; + VREF(rootvnode); + + if (p->p_fd->fd_rdir != NULL) + vrele(p->p_fd->fd_rdir); + p->p_fd->fd_rdir = rootvnode; + VREF(rootvnode); + + FILEDESC_XUNLOCK(p->p_fd); + + EVENTHANDLER_INVOKE(mountroot); +} + +static int +vfs_mountroot_devfs(struct thread *td, struct mount **mpp) +{ + struct vfsoptlist *opts; + struct vfsconf *vfsp; + struct mount *mp; + int error; + + *mpp = NULL; + + vfsp = vfs_byname("devfs"); + KASSERT(vfsp != NULL, ("Could not find devfs by name")); + if (vfsp == NULL) + return (ENOENT); + + mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred); + + error = VFS_MOUNT(mp); + KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error)); + if (error) + return (error); + + opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); + TAILQ_INIT(opts); + mp->mnt_opt = opts; + + mtx_lock(&mountlist_mtx); + TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); + mtx_unlock(&mountlist_mtx); + + *mpp = mp; + set_rootvnode(); + + error = kern_symlink(td, "/", "dev", UIO_SYSSPACE); + if (error) + printf("kern_symlink /dev -> / returns %d\n", error); + + return (error); +} + +static int +vfs_mountroot_shuffle(struct thread *td, struct mount *mpdevfs) +{ + struct nameidata nd; + struct mount *mporoot, *mpnroot; + struct vnode *vp, *vporoot, *vpdevfs; + char *fspath; + int error; + + mpnroot = TAILQ_NEXT(mpdevfs, mnt_list); + + /* Shuffle the mountlist. */ + mtx_lock(&mountlist_mtx); + mporoot = TAILQ_FIRST(&mountlist); + TAILQ_REMOVE(&mountlist, mpdevfs, mnt_list); + if (mporoot != mpdevfs) { + TAILQ_REMOVE(&mountlist, mpnroot, mnt_list); + TAILQ_INSERT_HEAD(&mountlist, mpnroot, mnt_list); + } + TAILQ_INSERT_TAIL(&mountlist, mpdevfs, mnt_list); + mtx_unlock(&mountlist_mtx); + + cache_purgevfs(mporoot); + if (mporoot != mpdevfs) + cache_purgevfs(mpdevfs); + + VFS_ROOT(mporoot, LK_EXCLUSIVE, &vporoot); + + VI_LOCK(vporoot); + vporoot->v_iflag &= ~VI_MOUNT; + VI_UNLOCK(vporoot); + vporoot->v_mountedhere = NULL; + mporoot->mnt_flag &= ~MNT_ROOTFS; + mporoot->mnt_vnodecovered = NULL; + vput(vporoot); + + /* Set up the new rootvnode, and purge the cache */ + mpnroot->mnt_vnodecovered = NULL; + set_rootvnode(); + cache_purgevfs(rootvnode->v_mount); + + if (mporoot != mpdevfs) { + /* Remount old root under /.mount or /mnt */ + fspath = "/.mount"; + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, + fspath, td); + error = namei(&nd); + if (error) { + NDFREE(&nd, NDF_ONLY_PNBUF); + fspath = "/mnt"; + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, + fspath, td); + error = namei(&nd); + } + if (!error) { + vp = nd.ni_vp; + error = (vp->v_type == VDIR) ? 0 : ENOTDIR; + if (!error) + error = vinvalbuf(vp, V_SAVE, 0, 0); + if (!error) { + cache_purge(vp); + mporoot->mnt_vnodecovered = vp; + vp->v_mountedhere = mporoot; + strlcpy(mporoot->mnt_stat.f_mntonname, + fspath, MNAMELEN); + VOP_UNLOCK(vp, 0); + } else + vput(vp); + } + NDFREE(&nd, NDF_ONLY_PNBUF); + + if (error && bootverbose) + printf("mountroot: unable to remount previous root " + "under /.mount or /mnt (error %d).\n", error); + } + + /* Remount devfs under /dev */ + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td); + error = namei(&nd); + if (!error) { + vp = nd.ni_vp; + error = (vp->v_type == VDIR) ? 0 : ENOTDIR; + if (!error) + error = vinvalbuf(vp, V_SAVE, 0, 0); + if (!error) { + vpdevfs = mpdevfs->mnt_vnodecovered; + if (vpdevfs != NULL) { + cache_purge(vpdevfs); + vpdevfs->v_mountedhere = NULL; + vrele(vpdevfs); + } + mpdevfs->mnt_vnodecovered = vp; + vp->v_mountedhere = mpdevfs; + VOP_UNLOCK(vp, 0); + } else + vput(vp); + } + if (error && bootverbose) + printf("mountroot: unable to remount devfs under /dev " + "(error %d).\n", error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + if (mporoot == mpdevfs) { + vfs_unbusy(mpdevfs); + /* Unlink the no longer needed /dev/dev -> / symlink */ + error = kern_unlink(td, "/dev/dev", UIO_SYSSPACE); + if (error && bootverbose) + printf("mountroot: unable to unlink /dev/dev " + "(error %d)\n", error); + } + + return (0); +} + +/* + * Configuration parser. + */ + +/* Parser character classes. */ +#define CC_WHITESPACE -1 +#define CC_NONWHITESPACE -2 + +/* Parse errors. */ +#define PE_EOF -1 +#define PE_EOL -2 + +static __inline int +parse_peek(char **conf) +{ + + return (**conf); +} + +static __inline void +parse_poke(char **conf, int c) +{ + + **conf = c; +} + +static __inline void +parse_advance(char **conf) +{ + + (*conf)++; +} + +static __inline int +parse_isspace(int c) +{ + + return ((c == ' ' || c == '\t' || c == '\n') ? 1 : 0); +} + +static int +parse_skipto(char **conf, int mc) +{ + int c, match; + + while (1) { + c = parse_peek(conf); + if (c == 0) + return (PE_EOF); + switch (mc) { + case CC_WHITESPACE: + match = (c == ' ' || c == '\t' || c == '\n') ? 1 : 0; + break; + case CC_NONWHITESPACE: + if (c == '\n') + return (PE_EOL); + match = (c != ' ' && c != '\t') ? 1 : 0; + break; + default: + match = (c == mc) ? 1 : 0; + break; + } + if (match) + break; + parse_advance(conf); + } + return (0); +} + +static int +parse_token(char **conf, char **tok) +{ + char *p; + size_t len; + int error; + + *tok = NULL; + error = parse_skipto(conf, CC_NONWHITESPACE); + if (error) + return (error); + p = *conf; + error = parse_skipto(conf, CC_WHITESPACE); + len = *conf - p; + *tok = malloc(len + 1, M_TEMP, M_WAITOK | M_ZERO); + bcopy(p, *tok, len); + return (0); +} + +static void +parse_dir_ask_printenv(const char *var) +{ + char *val; + + val = getenv(var); + if (val != NULL) { + printf(" %s=%s\n", var, val); + freeenv(val); + } +} + +static int +parse_dir_ask(char **conf) +{ + char name[80]; + char *mnt; + int error; + + printf("\nLoader variables:\n"); + parse_dir_ask_printenv("vfs.root.mountfrom"); + parse_dir_ask_printenv("vfs.root.mountfrom.options"); + + printf("\nManual root filesystem specification:\n"); + printf(" : [options]\n"); + printf(" Mount using filesystem \n"); + printf(" and with the specified (optional) option list.\n"); + printf("\n"); + printf(" eg. ufs:/dev/da0s1a\n"); + printf(" zfs:tank\n"); + printf(" cd9660:/dev/acd0 ro\n"); + printf(" (which is equivalent to: "); + printf("mount -t cd9660 -o ro /dev/acd0 /)\n"); + printf("\n"); + printf(" ? List valid disk boot devices\n"); + printf(" . Yield 1 second (for background tasks)\n"); + printf(" Abort manual input\n"); + + again: + printf("\nmountroot> "); + gets(name, sizeof(name), 1); + if (name[0] == '\0') + return (0); + if (name[0] == '?') { + printf("\nList of GEOM managed disk devices:\n "); + g_dev_print(); + goto again; + } + if (name[0] == '.') { + pause("rmask", hz); + goto again; + } + mnt = name; + error = parse_mount(&mnt); + if (error == -1) { + printf("Invalid specification.\n"); + goto again; + } + return (error); +} + +static int +parse_dir_md(char **conf) +{ + struct stat sb; + struct thread *td; + struct md_ioctl *mdio; + char *path, *tok; + int error, fd, len; + + td = curthread; + + error = parse_token(conf, &tok); + if (error) + return (error); + + len = strlen(tok); + mdio = malloc(sizeof(*mdio) + len + 1, M_TEMP, M_WAITOK | M_ZERO); + path = (void *)(mdio + 1); + bcopy(tok, path, len); + free(tok, M_TEMP); + + /* Get file status. */ + error = kern_stat(td, path, UIO_SYSSPACE, &sb); + if (error) + goto out; + + /* Open /dev/mdctl so that we can attach/detach. */ + error = kern_open(td, "/dev/" MDCTL_NAME, UIO_SYSSPACE, O_RDWR, 0); + if (error) + goto out; + + fd = td->td_retval[0]; + mdio->md_version = MDIOVERSION; + mdio->md_type = MD_VNODE; + + if (root_mount_mddev != -1) { + mdio->md_unit = root_mount_mddev; + DROP_GIANT(); + error = kern_ioctl(td, fd, MDIOCDETACH, (void *)mdio); + PICKUP_GIANT(); + /* Ignore errors. We don't care. */ + root_mount_mddev = -1; + } + + mdio->md_file = (void *)(mdio + 1); + mdio->md_options = MD_AUTOUNIT | MD_READONLY; + mdio->md_mediasize = sb.st_size; + mdio->md_unit = 0; + DROP_GIANT(); + error = kern_ioctl(td, fd, MDIOCATTACH, (void *)mdio); + PICKUP_GIANT(); + if (error) + goto out; + + if (mdio->md_unit > 9) { + printf("rootmount: too many md units\n"); + mdio->md_file = NULL; + mdio->md_options = 0; + mdio->md_mediasize = 0; + DROP_GIANT(); + error = kern_ioctl(td, fd, MDIOCDETACH, (void *)mdio); + PICKUP_GIANT(); + /* Ignore errors. We don't care. */ + error = ERANGE; + goto out; + } + + root_mount_mddev = mdio->md_unit; + printf(MD_NAME "%u attached to %s\n", root_mount_mddev, mdio->md_file); + + error = kern_close(td, fd); + + out: + free(mdio, M_TEMP); + return (error); +} + +static int +parse_dir_onfail(char **conf) +{ + char *action; + int error; + + error = parse_token(conf, &action); + if (error) + return (error); + + if (!strcmp(action, "continue")) + root_mount_onfail = A_CONTINUE; + else if (!strcmp(action, "panic")) + root_mount_onfail = A_PANIC; + else if (!strcmp(action, "reboot")) + root_mount_onfail = A_REBOOT; + else if (!strcmp(action, "retry")) + root_mount_onfail = A_RETRY; + else { + printf("rootmount: %s: unknown action\n", action); + error = EINVAL; + } + + free(action, M_TEMP); + return (0); +} + +static int +parse_dir_timeout(char **conf) +{ + char *tok, *endtok; + long secs; + int error; + + error = parse_token(conf, &tok); + if (error) + return (error); + + secs = strtol(tok, &endtok, 0); + error = (secs < 0 || *endtok != '\0') ? EINVAL : 0; + if (!error) + root_mount_timeout = secs; + free(tok, M_TEMP); + return (error); +} + +static int +parse_directive(char **conf) +{ + char *dir; + int error; + + error = parse_token(conf, &dir); + if (error) + return (error); + + if (strcmp(dir, ".ask") == 0) + error = parse_dir_ask(conf); + else if (strcmp(dir, ".md") == 0) + error = parse_dir_md(conf); + else if (strcmp(dir, ".onfail") == 0) + error = parse_dir_onfail(conf); + else if (strcmp(dir, ".timeout") == 0) + error = parse_dir_timeout(conf); + else { + printf("mountroot: invalid directive `%s'\n", dir); + /* Ignore the rest of the line. */ + (void)parse_skipto(conf, '\n'); + error = EINVAL; + } + free(dir, M_TEMP); + return (error); +} + +static int +parse_mount_dev_present(const char *dev) +{ + struct nameidata nd; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, dev, curthread); + error = namei(&nd); + if (!error) + vput(nd.ni_vp); + NDFREE(&nd, NDF_ONLY_PNBUF); + return (error != 0) ? 0 : 1; +} + +static int +parse_mount(char **conf) +{ + char errmsg[255]; + struct mntarg *ma; + char *dev, *fs, *opts, *tok; + int delay, error, timeout; + + error = parse_token(conf, &tok); + if (error) + return (error); + fs = tok; + error = parse_skipto(&tok, ':'); + if (error) { + free(fs, M_TEMP); + return (error); + } + parse_poke(&tok, '\0'); + parse_advance(&tok); + dev = tok; + + if (root_mount_mddev != -1) { + /* Handle substitution for the md unit number. */ + tok = strstr(dev, "md#"); + if (tok != NULL) + tok[2] = '0' + root_mount_mddev; + } + + /* Parse options. */ + error = parse_token(conf, &tok); + opts = (error == 0) ? tok : NULL; + + printf("Trying to mount root from %s:%s [%s]...\n", fs, dev, + (opts != NULL) ? opts : ""); + + bzero(errmsg, sizeof(errmsg)); + + if (vfs_byname(fs) == NULL) { + strlcpy(errmsg, "unknown file system", sizeof(errmsg)); + error = ENOENT; + goto out; + } + + if (strcmp(fs, "zfs") != 0 && dev[0] != '\0' && + !parse_mount_dev_present(dev)) { + printf("mountroot: waiting for device %s ...\n", dev); + delay = hz / 10; + timeout = root_mount_timeout * hz; + do { + pause("rmdev", delay); + timeout -= delay; + } while (timeout > 0 && !parse_mount_dev_present(dev)); + if (timeout <= 0) { + error = ENODEV; + goto out; + } + } + + ma = NULL; + ma = mount_arg(ma, "fstype", fs, -1); + ma = mount_arg(ma, "fspath", "/", -1); + ma = mount_arg(ma, "from", dev, -1); + ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg)); + ma = mount_arg(ma, "ro", NULL, 0); + ma = parse_mountroot_options(ma, opts); + error = kernel_mount(ma, MNT_ROOTFS); + + out: + if (error) { + printf("Mounting from %s:%s failed with error %d", + fs, dev, error); + if (errmsg[0] != '\0') + printf(": %s", errmsg); + printf(".\n"); + } + free(fs, M_TEMP); + if (opts != NULL) + free(opts, M_TEMP); + /* kernel_mount can return -1 on error. */ + return ((error < 0) ? EDOOFUS : error); +} + +static int +vfs_mountroot_parse(struct sbuf *sb, struct mount *mpdevfs) +{ + struct mount *mp; + char *conf; + int error; + + root_mount_mddev = -1; + +retry: + conf = sbuf_data(sb); + mp = TAILQ_NEXT(mpdevfs, mnt_list); + error = (mp == NULL) ? 0 : EDOOFUS; + root_mount_onfail = A_CONTINUE; + while (mp == NULL) { + error = parse_skipto(&conf, CC_NONWHITESPACE); + if (error == PE_EOL) { + parse_advance(&conf); + continue; + } + if (error < 0) + break; + switch (parse_peek(&conf)) { + case '#': + error = parse_skipto(&conf, '\n'); + break; + case '.': + error = parse_directive(&conf); + break; + default: + error = parse_mount(&conf); + break; + } + if (error < 0) + break; + /* Ignore any trailing garbage on the line. */ + if (parse_peek(&conf) != '\n') { + printf("mountroot: advancing to next directive...\n"); + (void)parse_skipto(&conf, '\n'); + } + mp = TAILQ_NEXT(mpdevfs, mnt_list); + } + if (mp != NULL) + return (0); + + /* + * We failed to mount (a new) root. + */ + switch (root_mount_onfail) { + case A_CONTINUE: + break; + case A_PANIC: + panic("mountroot: unable to (re-)mount root."); + /* NOTREACHED */ + case A_RETRY: + goto retry; + case A_REBOOT: + kern_reboot(RB_NOSYNC); + /* NOTREACHED */ + } + + return (error); +} + +static void +vfs_mountroot_conf0(struct sbuf *sb) +{ + char *s, *tok, *mnt, *opt; + int error; + + sbuf_printf(sb, ".onfail panic\n"); + sbuf_printf(sb, ".timeout %d\n", root_mount_timeout); + if (boothowto & RB_ASKNAME) + sbuf_printf(sb, ".ask\n"); +#ifdef ROOTDEVNAME + if (boothowto & RB_DFLTROOT) + sbuf_printf(sb, "%s\n", ROOTDEVNAME); +#endif + if (boothowto & RB_CDROM) { + sbuf_printf(sb, "cd9660:cd0\n"); + sbuf_printf(sb, ".timeout 0\n"); + sbuf_printf(sb, "cd9660:acd0\n"); + sbuf_printf(sb, ".timeout %d\n", root_mount_timeout); + } + s = getenv("vfs.root.mountfrom"); + if (s != NULL) { + opt = getenv("vfs.root.mountfrom.options"); + tok = s; + error = parse_token(&tok, &mnt); + while (!error) { + sbuf_printf(sb, "%s %s\n", mnt, + (opt != NULL) ? opt : ""); + free(mnt, M_TEMP); + error = parse_token(&tok, &mnt); + } + if (opt != NULL) + freeenv(opt); + freeenv(s); + } + if (rootdevnames[0] != NULL) + sbuf_printf(sb, "%s\n", rootdevnames[0]); + if (rootdevnames[1] != NULL) + sbuf_printf(sb, "%s\n", rootdevnames[1]); +#ifdef ROOTDEVNAME + if (!(boothowto & RB_DFLTROOT)) + sbuf_printf(sb, "%s\n", ROOTDEVNAME); +#endif + if (!(boothowto & RB_ASKNAME)) + sbuf_printf(sb, ".ask\n"); +} + +static int +vfs_mountroot_readconf(struct thread *td, struct sbuf *sb) +{ + static char buf[128]; + struct nameidata nd; + off_t ofs; + int error, flags; + int len, resid; + int vfslocked; + + NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, + "/.mount.conf", td); + flags = FREAD; + error = vn_open(&nd, &flags, 0, NULL); + if (error) + return (error); + + vfslocked = NDHASGIANT(&nd); + NDFREE(&nd, NDF_ONLY_PNBUF); + ofs = 0; + len = sizeof(buf) - 1; + while (1) { + error = vn_rdwr(UIO_READ, nd.ni_vp, buf, len, ofs, + UIO_SYSSPACE, IO_NODELOCKED, td->td_ucred, + NOCRED, &resid, td); + if (error) + break; + if (resid == len) + break; + buf[len - resid] = 0; + sbuf_printf(sb, "%s", buf); + ofs += len - resid; + } + + VOP_UNLOCK(nd.ni_vp, 0); + vn_close(nd.ni_vp, FREAD, td->td_ucred, td); + VFS_UNLOCK_GIANT(vfslocked); + return (error); +} + +static void +vfs_mountroot_wait(void) +{ + struct root_hold_token *h; + struct timeval lastfail; + int curfail; + + curfail = 0; + while (1) { + DROP_GIANT(); + g_waitidle(); + PICKUP_GIANT(); + mtx_lock(&mountlist_mtx); + if (LIST_EMPTY(&root_holds)) { + mtx_unlock(&mountlist_mtx); + break; + } + if (ppsratecheck(&lastfail, &curfail, 1)) { + printf("Root mount waiting for:"); + LIST_FOREACH(h, &root_holds, list) + printf(" %s", h->who); + printf("\n"); + } + msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold", + hz); + } +} + +void +vfs_mountroot(void) +{ + struct mount *mp; + struct sbuf *sb; + struct thread *td; + time_t timebase; + int error; + + td = curthread; + + vfs_mountroot_wait(); + + sb = sbuf_new_auto(); + vfs_mountroot_conf0(sb); + sbuf_finish(sb); + + error = vfs_mountroot_devfs(td, &mp); + while (!error) { + error = vfs_mountroot_parse(sb, mp); + if (!error) { + error = vfs_mountroot_shuffle(td, mp); + if (!error) { + sbuf_clear(sb); + error = vfs_mountroot_readconf(td, sb); + sbuf_finish(sb); + } + } + } + + sbuf_delete(sb); + + /* + * Iterate over all currently mounted file systems and use + * the time stamp found to check and/or initialize the RTC. + * Call inittodr() only once and pass it the largest of the + * timestamps we encounter. + */ + timebase = 0; + mtx_lock(&mountlist_mtx); + mp = TAILQ_FIRST(&mountlist); + while (mp != NULL) { + if (mp->mnt_time > timebase) + timebase = mp->mnt_time; + mp = TAILQ_NEXT(mp, mnt_list); + } + mtx_unlock(&mountlist_mtx); + inittodr(timebase); + + /* Keep prison0's root in sync with the global rootvnode. */ + mtx_lock(&prison0.pr_mtx); + prison0.pr_root = rootvnode; + vref(prison0.pr_root); + mtx_unlock(&prison0.pr_mtx); + + mtx_lock(&mountlist_mtx); + atomic_store_rel_int(&root_mount_complete, 1); + wakeup(&root_mount_complete); + mtx_unlock(&mountlist_mtx); +} + +static struct mntarg * +parse_mountroot_options(struct mntarg *ma, const char *options) +{ + char *p; + char *name, *name_arg; + char *val, *val_arg; + char *opts; + + if (options == NULL || options[0] == '\0') + return (ma); + + p = opts = strdup(options, M_MOUNT); + if (opts == NULL) { + return (ma); + } + + while((name = strsep(&p, ",")) != NULL) { + if (name[0] == '\0') + break; + + val = strchr(name, '='); + if (val != NULL) { + *val = '\0'; + ++val; + } + if( strcmp(name, "rw") == 0 || + strcmp(name, "noro") == 0) { + /* + * The first time we mount the root file system, + * we need to mount 'ro', so We need to ignore + * 'rw' and 'noro' mount options. + */ + continue; + } + name_arg = strdup(name, M_MOUNT); + val_arg = NULL; + if (val != NULL) + val_arg = strdup(val, M_MOUNT); + + ma = mount_arg(ma, name_arg, val_arg, + (val_arg != NULL ? -1 : 0)); + } + free(opts, M_MOUNT); + return (ma); +} diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 985d73bc54f..6b90888a7b2 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -2203,9 +2203,7 @@ vputx(struct vnode *vp, int func) } if (vp->v_usecount != 1) { -#ifdef DIAGNOSTIC vprint("vputx: negative ref count", vp); -#endif panic("vputx: negative ref cnt"); } CTR2(KTR_VFS, "%s: return vnode %p to the freelist", __func__, vp); @@ -3365,7 +3363,7 @@ static struct vop_vector sync_vnodeops = { /* * Create a new filesystem syncer vnode for the specified mount point. */ -int +void vfs_allocate_syncvnode(struct mount *mp) { struct vnode *vp; @@ -3374,16 +3372,15 @@ vfs_allocate_syncvnode(struct mount *mp) int error; /* Allocate a new vnode */ - if ((error = getnewvnode("syncer", mp, &sync_vnodeops, &vp)) != 0) { - mp->mnt_syncer = NULL; - return (error); - } + error = getnewvnode("syncer", mp, &sync_vnodeops, &vp); + if (error != 0) + panic("vfs_allocate_syncvnode: getnewvnode() failed"); vp->v_type = VNON; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); vp->v_vflag |= VV_FORCEINSMQ; error = insmntque(vp, mp); if (error != 0) - panic("vfs_allocate_syncvnode: insmntque failed"); + panic("vfs_allocate_syncvnode: insmntque() failed"); vp->v_vflag &= ~VV_FORCEINSMQ; VOP_UNLOCK(vp, 0); /* @@ -3408,10 +3405,31 @@ vfs_allocate_syncvnode(struct mount *mp) /* XXX - vn_syncer_add_to_worklist() also grabs and drops sync_mtx. */ mtx_lock(&sync_mtx); sync_vnode_count++; + if (mp->mnt_syncer == NULL) { + mp->mnt_syncer = vp; + vp = NULL; + } mtx_unlock(&sync_mtx); BO_UNLOCK(bo); - mp->mnt_syncer = vp; - return (0); + if (vp != NULL) { + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + vgone(vp); + vput(vp); + } +} + +void +vfs_deallocate_syncvnode(struct mount *mp) +{ + struct vnode *vp; + + mtx_lock(&sync_mtx); + vp = mp->mnt_syncer; + if (vp != NULL) + mp->mnt_syncer = NULL; + mtx_unlock(&sync_mtx); + if (vp != NULL) + vrele(vp); } /* @@ -3492,15 +3510,16 @@ sync_reclaim(struct vop_reclaim_args *ap) bo = &vp->v_bufobj; BO_LOCK(bo); - vp->v_mount->mnt_syncer = NULL; + mtx_lock(&sync_mtx); + if (vp->v_mount->mnt_syncer == vp) + vp->v_mount->mnt_syncer = NULL; if (bo->bo_flag & BO_ONWORKLST) { - mtx_lock(&sync_mtx); LIST_REMOVE(bo, bo_synclist); syncer_worklist_len--; sync_vnode_count--; - mtx_unlock(&sync_mtx); bo->bo_flag &= ~BO_ONWORKLST; } + mtx_unlock(&sync_mtx); BO_UNLOCK(bo); return (0); @@ -3621,7 +3640,13 @@ privcheck: !priv_check_cred(cred, PRIV_VFS_LOOKUP, 0)) priv_granted |= VEXEC; } else { + /* + * Ensure that at least one execute bit is on. Otherwise, + * a privileged user will always succeed, and we don't want + * this to happen unless the file really is executable. + */ if ((accmode & VEXEC) && ((dac_granted & VEXEC) == 0) && + (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 && !priv_check_cred(cred, PRIV_VFS_EXEC, 0)) priv_granted |= VEXEC; } diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 4fd9dfa0e8f..9046d1cb17e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -85,10 +85,10 @@ __FBSDID("$FreeBSD$"); #include SDT_PROVIDER_DEFINE(vfs); -SDT_PROBE_DEFINE(vfs, , stat, mode); +SDT_PROBE_DEFINE(vfs, , stat, mode, mode); SDT_PROBE_ARGTYPE(vfs, , stat, mode, 0, "char *"); SDT_PROBE_ARGTYPE(vfs, , stat, mode, 1, "int"); -SDT_PROBE_DEFINE(vfs, , stat, reg); +SDT_PROBE_DEFINE(vfs, , stat, reg, reg); SDT_PROBE_ARGTYPE(vfs, , stat, reg, 0, "char *"); SDT_PROBE_ARGTYPE(vfs, , stat, reg, 1, "int"); diff --git a/sys/rpc/inet_ntop.c b/sys/libkern/inet_ntop.c similarity index 92% rename from sys/rpc/inet_ntop.c rename to sys/libkern/inet_ntop.c index d093a970345..ce7d93eb9d3 100644 --- a/sys/rpc/inet_ntop.c +++ b/sys/libkern/inet_ntop.c @@ -22,20 +22,18 @@ static const char rcsid[] = "$Id: inet_ntop.c,v 1.3.18.2 2005/11/03 23:02:22 mar __FBSDID("$FreeBSD$"); #include -#include #include #include -#include -#include +#include /*% * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ -static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size); -static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size); +static char *inet_ntop4(const u_char *src, char *dst, socklen_t size); +static char *inet_ntop6(const u_char *src, char *dst, socklen_t size); /* char * * inet_ntop(af, src, dst, size) @@ -45,9 +43,8 @@ static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size); * author: * Paul Vixie, 1996. */ -const char * -__rpc_inet_ntop(int af, const void * __restrict src, char * __restrict dst, - socklen_t size) +char * +inet_ntop(int af, const void *src, char *dst, socklen_t size) { switch (af) { case AF_INET: @@ -71,7 +68,7 @@ __rpc_inet_ntop(int af, const void * __restrict src, char * __restrict dst, * author: * Paul Vixie, 1996. */ -static const char * +static char * inet_ntop4(const u_char *src, char *dst, socklen_t size) { static const char fmt[] = "%u.%u.%u.%u"; @@ -92,7 +89,7 @@ inet_ntop4(const u_char *src, char *dst, socklen_t size) * author: * Paul Vixie, 1996. */ -static const char * +static char * inet_ntop6(const u_char *src, char *dst, socklen_t size) { /* diff --git a/sys/rpc/inet_pton.c b/sys/libkern/inet_pton.c similarity index 94% rename from sys/rpc/inet_pton.c rename to sys/libkern/inet_pton.c index 943fad7c6bd..f8b7293bfa8 100644 --- a/sys/rpc/inet_pton.c +++ b/sys/libkern/inet_pton.c @@ -22,12 +22,10 @@ static const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 mar __FBSDID("$FreeBSD$"); #include -#include #include #include -#include -#include +#include #if __FreeBSD_version < 700000 #define strchr index @@ -53,7 +51,7 @@ static int inet_pton6(const char *src, u_char *dst); * Paul Vixie, 1996. */ int -__rpc_inet_pton(int af, const char * __restrict src, void * __restrict dst) +inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: @@ -218,11 +216,4 @@ inet_pton6(const char *src, u_char *dst) return (1); } -/* - * Weak aliases for applications that use certain private entry points, - * and fail to include . - */ -#undef inet_pton -__weak_reference(__inet_pton, inet_pton); - /*! \file */ diff --git a/sys/mips/adm5120/obio.c b/sys/mips/adm5120/obio.c index ad6cb6e2ea7..b89c9576579 100644 --- a/sys/mips/adm5120/obio.c +++ b/sys/mips/adm5120/obio.c @@ -101,7 +101,7 @@ int irq_priorities[NIRQS] = { static int obio_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t obio_add_child(device_t, int, const char *, int); +static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -480,7 +480,7 @@ obio_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -obio_add_child(device_t bus, int order, const char *name, int unit) +obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; diff --git a/sys/mips/alchemy/obio.c b/sys/mips/alchemy/obio.c index fb55813c581..90e41d61bfa 100644 --- a/sys/mips/alchemy/obio.c +++ b/sys/mips/alchemy/obio.c @@ -101,7 +101,7 @@ int irq_priorities[NIRQS] = { static int obio_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t obio_add_child(device_t, int, const char *, int); +static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -472,7 +472,7 @@ obio_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -obio_add_child(device_t bus, int order, const char *name, int unit) +obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; diff --git a/sys/mips/atheros/apb.c b/sys/mips/atheros/apb.c index d71b24210e0..c004741cfd8 100644 --- a/sys/mips/atheros/apb.c +++ b/sys/mips/atheros/apb.c @@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$"); static int apb_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t apb_add_child(device_t, int, const char *, int); +static device_t apb_add_child(device_t, u_int, const char *, int); static struct resource * apb_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -397,7 +397,7 @@ apb_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -apb_add_child(device_t bus, int order, const char *name, int unit) +apb_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct apb_ivar *ivar; diff --git a/sys/mips/atheros/ar71xx_chip.c b/sys/mips/atheros/ar71xx_chip.c new file mode 100644 index 00000000000..ec179a16859 --- /dev/null +++ b/sys/mips/atheros/ar71xx_chip.c @@ -0,0 +1,240 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +/* XXX these should replace the current definitions in ar71xxreg.h */ +/* XXX perhaps an ar71xx_chip.h header file? */ +#define AR71XX_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 +#define AR71XX_PLL_REG_SEC_CONFIG AR71XX_PLL_CPU_BASE + 0x04 +#define AR71XX_PLL_REG_ETH0_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x10 +#define AR71XX_PLL_REG_ETH1_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x14 + +#define AR71XX_PLL_DIV_SHIFT 3 +#define AR71XX_PLL_DIV_MASK 0x1f +#define AR71XX_CPU_DIV_SHIFT 16 +#define AR71XX_CPU_DIV_MASK 0x3 +#define AR71XX_DDR_DIV_SHIFT 18 +#define AR71XX_DDR_DIV_MASK 0x3 +#define AR71XX_AHB_DIV_SHIFT 20 +#define AR71XX_AHB_DIV_MASK 0x7 + +/* XXX these shouldn't be in here - this file is a per-chip file */ +/* XXX these should be in the top-level ar71xx type, not ar71xx -chip */ +uint32_t u_ar71xx_cpu_freq; +uint32_t u_ar71xx_ahb_freq; +uint32_t u_ar71xx_ddr_freq; + +static void +ar71xx_chip_detect_mem_size(void) +{ +} + +static void +ar71xx_chip_detect_sys_frequency(void) +{ + uint32_t pll; + uint32_t freq; + uint32_t div; + + pll = ATH_READ_REG(AR71XX_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; + freq = div * AR71XX_BASE_FREQ; + + div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; + u_ar71xx_cpu_freq = freq / div; + + div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; + u_ar71xx_ddr_freq = freq / div; + + div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; + u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; +} + +/* + * This does not lock the CPU whilst doing the work! + */ +static void +ar71xx_chip_device_stop(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR71XX_RST_RESET); + ATH_WRITE_REG(AR71XX_RST_RESET, reg | mask); +} + +static void +ar71xx_chip_device_start(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR71XX_RST_RESET); + ATH_WRITE_REG(AR71XX_RST_RESET, reg & ~mask); +} + +static int +ar71xx_chip_device_stopped(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR71XX_RST_RESET); + return ((reg & mask) == mask); +} + +/* Speed is either 10, 100 or 1000 */ +static void +ar71xx_chip_set_pll_ge0(int speed) +{ + uint32_t pll; + + switch(speed) { + case 10: + pll = PLL_ETH_INT_CLK_10; + break; + case 100: + pll = PLL_ETH_INT_CLK_100; + break; + case 1000: + pll = PLL_ETH_INT_CLK_1000; + break; + default: + printf("ar71xx_chip_set_pll_ge0: invalid speed %d\n", speed); + return; + } + + ar71xx_write_pll(AR71XX_PLL_SEC_CONFIG, AR71XX_PLL_ETH_INT0_CLK, pll, AR71XX_PLL_ETH0_SHIFT); +} + +static void +ar71xx_chip_set_pll_ge1(int speed) +{ + uint32_t pll; + + switch(speed) { + case 10: + pll = PLL_ETH_INT_CLK_10; + break; + case 100: + pll = PLL_ETH_INT_CLK_100; + break; + case 1000: + pll = PLL_ETH_INT_CLK_1000; + break; + default: + printf("ar71xx_chip_set_pll_ge1: invalid speed %d\n", speed); + return; + } + + ar71xx_write_pll(AR71XX_PLL_SEC_CONFIG, AR71XX_PLL_ETH_INT1_CLK, pll, AR71XX_PLL_ETH1_SHIFT); +} + +static void +ar71xx_chip_ddr_flush_ge0(void) +{ + ar71xx_ddr_flush(AR71XX_WB_FLUSH_GE0); +} + +static void +ar71xx_chip_ddr_flush_ge1(void) +{ + ar71xx_ddr_flush(AR71XX_WB_FLUSH_GE1); +} + +static uint32_t +ar71xx_chip_get_eth_pll(unsigned int mac, int speed) +{ + return 0; +} + +static void +ar71xx_chip_init_usb_peripheral(void) +{ + ar71xx_device_stop(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); + DELAY(1000); + + ar71xx_device_start(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); + DELAY(1000); + + ATH_WRITE_REG(AR71XX_USB_CTRL_CONFIG, + USB_CTRL_CONFIG_OHCI_DES_SWAP | USB_CTRL_CONFIG_OHCI_BUF_SWAP | + USB_CTRL_CONFIG_EHCI_DES_SWAP | USB_CTRL_CONFIG_EHCI_BUF_SWAP); + + ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ, + (32 << USB_CTRL_FLADJ_HOST_SHIFT) | (3 << USB_CTRL_FLADJ_A5_SHIFT)); + + DELAY(1000); +} + +struct ar71xx_cpu_def ar71xx_chip_def = { + &ar71xx_chip_detect_mem_size, + &ar71xx_chip_detect_sys_frequency, + &ar71xx_chip_device_stop, + &ar71xx_chip_device_start, + &ar71xx_chip_device_stopped, + &ar71xx_chip_set_pll_ge0, + &ar71xx_chip_set_pll_ge1, + &ar71xx_chip_ddr_flush_ge0, + &ar71xx_chip_ddr_flush_ge1, + &ar71xx_chip_get_eth_pll, + NULL, + &ar71xx_chip_init_usb_peripheral, +}; diff --git a/sys/dev/mii/axphyreg.h b/sys/mips/atheros/ar71xx_chip.h similarity index 84% rename from sys/dev/mii/axphyreg.h rename to sys/mips/atheros/ar71xx_chip.h index 2d9e9339bee..ccecc23294e 100644 --- a/sys/dev/mii/axphyreg.h +++ b/sys/mips/atheros/ar71xx_chip.h @@ -1,13 +1,12 @@ /*- - * Copyright (c) 2009, M. Warner Losh + * Copyright (c) 2010 Adrian Chadd * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. + * 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. @@ -23,6 +22,13 @@ * 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$ */ + +/* $FreeBSD$ */ + +#ifndef __AR71XX_CHIP_H__ +#define __AR71XX_CHIP_H__ + +extern struct ar71xx_cpu_def ar71xx_chip_def; + +#endif diff --git a/sys/mips/atheros/ar71xx_cpudef.h b/sys/mips/atheros/ar71xx_cpudef.h new file mode 100644 index 00000000000..f26c55aaadc --- /dev/null +++ b/sys/mips/atheros/ar71xx_cpudef.h @@ -0,0 +1,118 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR71XX_CPUDEF_H__ +#define __AR71XX_CPUDEF_H__ + +struct ar71xx_cpu_def { + void (* detect_mem_size) (void); + void (* detect_sys_frequency) (void); + void (* ar71xx_chip_device_stop) (uint32_t); + void (* ar71xx_chip_device_start) (uint32_t); + int (* ar71xx_chip_device_stopped) (uint32_t); + void (* ar71xx_chip_set_pll_ge0) (int); + void (* ar71xx_chip_set_pll_ge1) (int); + void (* ar71xx_chip_ddr_flush_ge0) (void); + void (* ar71xx_chip_ddr_flush_ge1) (void); + uint32_t (* ar71xx_chip_get_eth_pll) (unsigned int, int); + + /* + * From Linux - Handling this IRQ is a bit special. + * AR71xx - AR71XX_DDR_REG_FLUSH_PCI + * AR724x - AR724X_DDR_REG_FLUSH_PCIE + * AR91xx - AR91XX_DDR_REG_FLUSH_WMAC + * + * These are set when STATUSF_IP2 is set in regiser c0. + * This flush is done before the IRQ is handled to make + * sure the driver correctly sees any memory updates. + */ + void (* ar71xx_chip_irq_flush_ip2) (void); + /* + * The USB peripheral init code is subtly different for + * each chip. + */ + void (* ar71xx_chip_init_usb_peripheral) (void); +}; + +extern struct ar71xx_cpu_def * ar71xx_cpu_ops; + +static inline void ar71xx_detect_sys_frequency(void) +{ + ar71xx_cpu_ops->detect_sys_frequency(); +} + +static inline void ar71xx_device_stop(uint32_t mask) +{ + ar71xx_cpu_ops->ar71xx_chip_device_stop(mask); +} + +static inline void ar71xx_device_start(uint32_t mask) +{ + ar71xx_cpu_ops->ar71xx_chip_device_start(mask); +} + +static inline int ar71xx_device_stopped(uint32_t mask) +{ + return ar71xx_cpu_ops->ar71xx_chip_device_stopped(mask); +} + +static inline void ar71xx_device_set_pll_ge0(int speed) +{ + ar71xx_cpu_ops->ar71xx_chip_set_pll_ge0(speed); +} + +static inline void ar71xx_device_set_pll_ge1(int speed) +{ + ar71xx_cpu_ops->ar71xx_chip_set_pll_ge1(speed); +} + +static inline void ar71xx_device_flush_ddr_ge0(void) +{ + ar71xx_cpu_ops->ar71xx_chip_ddr_flush_ge0(); +} + +static inline void ar71xx_device_flush_ddr_ge1(void) +{ + ar71xx_cpu_ops->ar71xx_chip_ddr_flush_ge1(); +} + +static inline void ar71xx_init_usb_peripheral(void) +{ + ar71xx_cpu_ops->ar71xx_chip_init_usb_peripheral(); +} + +/* XXX shouldn't be here! */ +extern uint32_t u_ar71xx_cpu_freq; +extern uint32_t u_ar71xx_ahb_freq; +extern uint32_t u_ar71xx_ddr_freq; + +static inline uint64_t ar71xx_cpu_freq(void) { return u_ar71xx_cpu_freq; } +static inline uint64_t ar71xx_ahb_freq(void) { return u_ar71xx_ahb_freq; } +static inline uint64_t ar71xx_ddr_freq(void) { return u_ar71xx_ddr_freq; } + +#endif diff --git a/sys/mips/atheros/ar71xx_gpio.c b/sys/mips/atheros/ar71xx_gpio.c new file mode 100644 index 00000000000..866c72b5b74 --- /dev/null +++ b/sys/mips/atheros/ar71xx_gpio.c @@ -0,0 +1,446 @@ +/*- + * Copyright (c) 2009, Oleksandr Tymoshenko + * Copyright (c) 2009, Luiz Otavio O Souza. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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. + */ + +/* + * GPIO driver for AR71xx + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "gpio_if.h" + +#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) + +struct ar71xx_gpio_pin { + const char *name; + int pin; + int flags; +}; + +static struct ar71xx_gpio_pin ar71xx_gpio_pins[] = { + { "RFled", 2, GPIO_PIN_OUTPUT}, + { "SW4", 8, GPIO_PIN_INPUT}, + { NULL, 0, 0}, +}; + +/* + * Helpers + */ +static void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, + uint32_t mask); +static void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, + uint32_t mask); +static void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, + struct gpio_pin *pin, uint32_t flags); + +/* + * Driver stuff + */ +static int ar71xx_gpio_probe(device_t dev); +static int ar71xx_gpio_attach(device_t dev); +static int ar71xx_gpio_detach(device_t dev); +static int ar71xx_gpio_filter(void *arg); +static void ar71xx_gpio_intr(void *arg); + +/* + * GPIO interface + */ +static int ar71xx_gpio_pin_max(device_t dev, int *maxpin); +static int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); +static int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t + *flags); +static int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name); +static int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); +static int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); +static int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); +static int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin); + +static void +ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask) +{ + GPIO_LOCK(sc); + GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask); + GPIO_UNLOCK(sc); +} + +static void +ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask) +{ + GPIO_LOCK(sc); + GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask); + GPIO_UNLOCK(sc); +} + +static void +ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, + unsigned int flags) +{ + uint32_t mask; + + mask = 1 << pin->gp_pin; + GPIO_LOCK(sc); + + /* + * Manage input/output + */ + if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { + pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); + if (flags & GPIO_PIN_OUTPUT) { + pin->gp_flags |= GPIO_PIN_OUTPUT; + GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); + } + else { + pin->gp_flags |= GPIO_PIN_INPUT; + GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); + } + } + + GPIO_UNLOCK(sc); +} + +static int +ar71xx_gpio_pin_max(device_t dev, int *maxpin) +{ + + *maxpin = AR71XX_GPIO_PINS - 1; + return (0); +} + +static int +ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *caps = sc->gpio_pins[i].gp_caps; + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *flags = sc->gpio_pins[i].gp_flags; + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + int i; + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + /* Filter out unwanted flags */ + if ((flags &= sc->gpio_pins[i].gp_caps) != flags) + return (EINVAL); + + /* Can't mix input/output together */ + if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == + (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) + return (EINVAL); + + ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); + return (0); +} + +static int +ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + if (value) + GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); + else + GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + *val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin) +{ + int res, i; + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + + for (i = 0; i < sc->gpio_npins; i++) { + if (sc->gpio_pins[i].gp_pin == pin) + break; + } + + if (i >= sc->gpio_npins) + return (EINVAL); + + GPIO_LOCK(sc); + res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; + if (res) + GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); + else + GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); + GPIO_UNLOCK(sc); + + return (0); +} + +static int +ar71xx_gpio_filter(void *arg) +{ + + /* TODO: something useful */ + return (FILTER_STRAY); +} + + + +static void +ar71xx_gpio_intr(void *arg) +{ + struct ar71xx_gpio_softc *sc = arg; + GPIO_LOCK(sc); + /* TODO: something useful */ + GPIO_UNLOCK(sc); +} + +static int +ar71xx_gpio_probe(device_t dev) +{ + + device_set_desc(dev, "Atheros AR71XX GPIO driver"); + return (0); +} + +static int +ar71xx_gpio_attach(device_t dev) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + int error = 0; + struct ar71xx_gpio_pin *pinp; + int i; + + KASSERT((device_get_unit(dev) == 0), + ("ar71xx_gpio: Only one gpio module supported")); + + mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, + MTX_DEF); + + /* Map control/status registers. */ + sc->gpio_mem_rid = 0; + sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->gpio_mem_rid, RF_ACTIVE); + + if (sc->gpio_mem_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + ar71xx_gpio_detach(dev); + return(error); + } + + if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, + ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } + + sc->dev = dev; + ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS1_EN); + ar71xx_gpio_function_enable(sc, GPIO_FUNC_SPI_CS2_EN); + /* Configure all pins as input */ + /* disable interrupts for all pins */ + GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0); + pinp = ar71xx_gpio_pins; + i = 0; + while (pinp->name) { + strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME); + sc->gpio_pins[i].gp_pin = pinp->pin; + sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; + sc->gpio_pins[i].gp_flags = 0; + ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags); + pinp++; + i++; + } + + sc->gpio_npins = i; + + device_add_child(dev, "gpioc", device_get_unit(dev)); + device_add_child(dev, "gpiobus", device_get_unit(dev)); + return (bus_generic_attach(dev)); +} + +static int +ar71xx_gpio_detach(device_t dev) +{ + struct ar71xx_gpio_softc *sc = device_get_softc(dev); + + KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); + + ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS1_EN); + ar71xx_gpio_function_disable(sc, GPIO_FUNC_SPI_CS2_EN); + bus_generic_detach(dev); + + if (sc->gpio_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, + sc->gpio_mem_res); + + mtx_destroy(&sc->gpio_mtx); + + return(0); +} + +static device_method_t ar71xx_gpio_methods[] = { + DEVMETHOD(device_probe, ar71xx_gpio_probe), + DEVMETHOD(device_attach, ar71xx_gpio_attach), + DEVMETHOD(device_detach, ar71xx_gpio_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max), + DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname), + DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags), + DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps), + DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags), + DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get), + DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set), + DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle), + {0, 0}, +}; + +static driver_t ar71xx_gpio_driver = { + "gpio", + ar71xx_gpio_methods, + sizeof(struct ar71xx_gpio_softc), +}; +static devclass_t ar71xx_gpio_devclass; + +DRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0); diff --git a/sys/mips/atheros/ar71xx_gpiovar.h b/sys/mips/atheros/ar71xx_gpiovar.h new file mode 100644 index 00000000000..a9ed7e07422 --- /dev/null +++ b/sys/mips/atheros/ar71xx_gpiovar.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2009, Oleksandr Tymoshenko + * Copyright (c) 2009, Luiz Otavio O Souza. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef __AR71XX_GPIOVAR_H__ +#define __AR71XX_GPIOVAR_H__ + +#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx) +#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx) +#define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED) + +/* + * register space access macros + */ +#define GPIO_WRITE(sc, reg, val) do { \ + bus_write_4(sc->gpio_mem_res, (reg), (val)); \ + } while (0) + +#define GPIO_READ(sc, reg) bus_read_4(sc->gpio_mem_res, (reg)) + +#define GPIO_SET_BITS(sc, reg, bits) \ + GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) | (bits)) + +#define GPIO_CLEAR_BITS(sc, reg, bits) \ + GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) & ~(bits)) + +#define AR71XX_GPIO_PINS 12 + +struct ar71xx_gpio_softc { + device_t dev; + struct mtx gpio_mtx; + struct resource *gpio_mem_res; + int gpio_mem_rid; + struct resource *gpio_irq_res; + int gpio_irq_rid; + void *gpio_ih; + int gpio_npins; + struct gpio_pin gpio_pins[AR71XX_GPIO_PINS]; +}; + +#endif /* __AR71XX_GPIOVAR_H__ */ diff --git a/sys/mips/atheros/ar71xx_machdep.c b/sys/mips/atheros/ar71xx_machdep.c index 6cb68cefcca..ec355cc4ec1 100644 --- a/sys/mips/atheros/ar71xx_machdep.c +++ b/sys/mips/atheros/ar71xx_machdep.c @@ -57,6 +57,9 @@ __FBSDID("$FreeBSD$"); #include +#include +#include + extern char edata[], end[]; uint32_t ar711_base_mac[ETHER_ADDR_LEN]; @@ -118,9 +121,7 @@ platform_identify(void) void platform_reset(void) { - uint32_t reg = ATH_READ_REG(AR71XX_RST_RESET); - - ATH_WRITE_REG(AR71XX_RST_RESET, reg | RST_RESET_FULL_CHIP); + ar71xx_device_stop(RST_RESET_FULL_CHIP); /* Wait for reset */ while(1) ; @@ -143,9 +144,8 @@ platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; - uint32_t reg; int argc, i, count = 0; - char **argv, **envp; + char **argv, **envp, *var; vm_offset_t kernend; /* @@ -167,19 +167,9 @@ platform_start(__register_t a0 __unused, __register_t a1 __unused, * Protect ourselves from garbage in registers */ if (MIPS_IS_VALID_PTR(envp)) { - for (i = 0; envp[i]; i += 2) - { + for (i = 0; envp[i]; i += 2) { if (strcmp(envp[i], "memsize") == 0) realmem = btoc(strtoul(envp[i+1], NULL, 16)); - else if (strcmp(envp[i], "ethaddr") == 0) { - count = sscanf(envp[i+1], "%x.%x.%x.%x.%x.%x", - &ar711_base_mac[0], &ar711_base_mac[1], - &ar711_base_mac[2], &ar711_base_mac[3], - &ar711_base_mac[4], &ar711_base_mac[5]); - if (count < 6) - memset(ar711_base_mac, 0, - sizeof(ar711_base_mac)); - } } } @@ -202,11 +192,21 @@ platform_start(__register_t a0 __unused, __register_t a1 __unused, * should be called first. */ init_param1(); + + /* Detect the system type - this is needed for subsequent chipset-specific calls */ + ar71xx_detect_sys_type(); + ar71xx_detect_sys_frequency(); + platform_counter_freq = ar71xx_cpu_freq(); mips_timer_init_params(platform_counter_freq, 1); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); + printf("CPU platform: %s\n", ar71xx_get_system_type()); + printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000); + printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000); + printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000); + printf("platform frequency: %lld\n", platform_counter_freq); printf("arguments: \n"); printf(" a0 = %08x\n", a0); @@ -235,6 +235,22 @@ platform_start(__register_t a0 __unused, __register_t a1 __unused, else printf ("envp is invalid\n"); + /* + * "ethaddr" is passed via envp on RedBoot platforms + * "kmac" is passed via argv on RouterBOOT platforms + */ + if ((var = getenv("ethaddr")) != NULL || + (var = getenv("kmac")) != NULL) { + count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", + &ar711_base_mac[0], &ar711_base_mac[1], + &ar711_base_mac[2], &ar711_base_mac[3], + &ar711_base_mac[4], &ar711_base_mac[5]); + if (count < 6) + memset(ar711_base_mac, 0, + sizeof(ar711_base_mac)); + freeenv(var); + } + init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); @@ -244,22 +260,7 @@ platform_start(__register_t a0 __unused, __register_t a1 __unused, /* * Reset USB devices */ - reg = ATH_READ_REG(AR71XX_RST_RESET); - reg |= - RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY; - ATH_WRITE_REG(AR71XX_RST_RESET, reg); - DELAY(1000); - reg &= - ~(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); - ATH_WRITE_REG(AR71XX_RST_RESET, reg); - - ATH_WRITE_REG(AR71XX_USB_CTRL_CONFIG, - USB_CTRL_CONFIG_OHCI_DES_SWAP | USB_CTRL_CONFIG_OHCI_BUF_SWAP | - USB_CTRL_CONFIG_EHCI_DES_SWAP | USB_CTRL_CONFIG_EHCI_BUF_SWAP); - - ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ, - (32 << USB_CTRL_FLADJ_HOST_SHIFT) | (3 << USB_CTRL_FLADJ_A5_SHIFT)); - DELAY(1000); + ar71xx_init_usb_peripheral(); kdb_init(); #ifdef KDB diff --git a/sys/mips/atheros/ar71xx_pci.c b/sys/mips/atheros/ar71xx_pci.c index 2e6a5fa8091..632270cb8e6 100644 --- a/sys/mips/atheros/ar71xx_pci.c +++ b/sys/mips/atheros/ar71xx_pci.c @@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #undef AR71XX_PCI_DEBUG #ifdef AR71XX_PCI_DEBUG #define dprintf printf @@ -258,7 +260,6 @@ ar71xx_pci_attach(device_t dev) { int busno = 0; int rid = 0; - uint32_t reset; struct ar71xx_pci_softc *sc = device_get_softc(dev); sc->sc_mem_rman.rm_type = RMAN_ARRAY; @@ -295,15 +296,10 @@ ar71xx_pci_attach(device_t dev) } /* reset PCI core and PCI bus */ - reset = ATH_READ_REG(AR71XX_RST_RESET); - reset |= (RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); - ATH_WRITE_REG(AR71XX_RST_RESET, reset); - ATH_READ_REG(AR71XX_RST_RESET); + ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); DELAY(100000); - reset &= ~(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); - ATH_WRITE_REG(AR71XX_RST_RESET, reset); - ATH_READ_REG(AR71XX_RST_RESET); + ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); DELAY(100000); /* Init PCI windows */ diff --git a/sys/mips/atheros/ar71xx_setup.c b/sys/mips/atheros/ar71xx_setup.c new file mode 100644 index 00000000000..0720d52ff9d --- /dev/null +++ b/sys/mips/atheros/ar71xx_setup.c @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#define AR71XX_SYS_TYPE_LEN 128 + +static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN]; +enum ar71xx_soc_type ar71xx_soc; +struct ar71xx_cpu_def * ar71xx_cpu_ops = NULL; + +void +ar71xx_detect_sys_type(void) +{ + char *chip = "????"; + uint32_t id; + uint32_t major; + uint32_t minor; + uint32_t rev = 0; + + id = ATH_READ_REG(AR71XX_RST_RESET_REG_REV_ID); + major = id & REV_ID_MAJOR_MASK; + + switch (major) { + case REV_ID_MAJOR_AR71XX: + minor = id & AR71XX_REV_ID_MINOR_MASK; + rev = id >> AR71XX_REV_ID_REVISION_SHIFT; + rev &= AR71XX_REV_ID_REVISION_MASK; + ar71xx_cpu_ops = &ar71xx_chip_def; + switch (minor) { + case AR71XX_REV_ID_MINOR_AR7130: + ar71xx_soc = AR71XX_SOC_AR7130; + chip = "7130"; + break; + + case AR71XX_REV_ID_MINOR_AR7141: + ar71xx_soc = AR71XX_SOC_AR7141; + chip = "7141"; + break; + + case AR71XX_REV_ID_MINOR_AR7161: + ar71xx_soc = AR71XX_SOC_AR7161; + chip = "7161"; + break; + } + break; + + case REV_ID_MAJOR_AR7240: + ar71xx_soc = AR71XX_SOC_AR7240; + chip = "7240"; + ar71xx_cpu_ops = &ar724x_chip_def; + rev = (id & AR724X_REV_ID_REVISION_MASK); + break; + + case REV_ID_MAJOR_AR7241: + ar71xx_soc = AR71XX_SOC_AR7241; + chip = "7241"; + ar71xx_cpu_ops = &ar724x_chip_def; + rev = (id & AR724X_REV_ID_REVISION_MASK); + break; + + case REV_ID_MAJOR_AR7242: + ar71xx_soc = AR71XX_SOC_AR7242; + chip = "7242"; + ar71xx_cpu_ops = &ar724x_chip_def; + rev = (id & AR724X_REV_ID_REVISION_MASK); + break; + + case REV_ID_MAJOR_AR913X: + minor = id & AR91XX_REV_ID_MINOR_MASK; + rev = id >> AR91XX_REV_ID_REVISION_SHIFT; + rev &= AR91XX_REV_ID_REVISION_MASK; + ar71xx_cpu_ops = &ar91xx_chip_def; + switch (minor) { + case AR91XX_REV_ID_MINOR_AR9130: + ar71xx_soc = AR71XX_SOC_AR9130; + chip = "9130"; + break; + + case AR91XX_REV_ID_MINOR_AR9132: + ar71xx_soc = AR71XX_SOC_AR9132; + chip = "9132"; + break; + } + break; + + + default: + panic("ar71xx: unknown chip id:0x%08x\n", id); + } + + sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev); +} + +const char * +ar71xx_get_system_type(void) +{ + return ar71xx_sys_type; +} + diff --git a/sys/mips/atheros/ar71xx_setup.h b/sys/mips/atheros/ar71xx_setup.h new file mode 100644 index 00000000000..89f2490349f --- /dev/null +++ b/sys/mips/atheros/ar71xx_setup.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR71XX_SETUP_H__ +#define __AR71XX_SETUP_H__ + +enum ar71xx_soc_type { + AR71XX_SOC_UNKNOWN, + AR71XX_SOC_AR7130, + AR71XX_SOC_AR7141, + AR71XX_SOC_AR7161, + AR71XX_SOC_AR7240, + AR71XX_SOC_AR7241, + AR71XX_SOC_AR7242, + AR71XX_SOC_AR9130, + AR71XX_SOC_AR9132 +}; +extern enum ar71xx_soc_type ar71xx_soc; + +extern void ar71xx_detect_sys_type(void); +extern const char *ar71xx_get_system_type(void); + +#endif diff --git a/sys/mips/atheros/ar71xx_wdog.c b/sys/mips/atheros/ar71xx_wdog.c index 450b9ebfacb..d582f18fdc3 100644 --- a/sys/mips/atheros/ar71xx_wdog.c +++ b/sys/mips/atheros/ar71xx_wdog.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include struct ar71xx_wdog_softc { device_t dev; diff --git a/sys/mips/atheros/ar71xxreg.h b/sys/mips/atheros/ar71xxreg.h index a87151f6242..da5fc5d2ccb 100644 --- a/sys/mips/atheros/ar71xxreg.h +++ b/sys/mips/atheros/ar71xxreg.h @@ -151,16 +151,16 @@ #define AR71XX_GPIO_FUNCTION 0x28 #define GPIO_FUNC_STEREO_EN (1 << 17) #define GPIO_FUNC_SLIC_EN (1 << 16) -#define GPIO_FUNC_SPI_CS2_EN (1 << 15) +#define GPIO_FUNC_SPI_CS2_EN (1 << 13) /* CS2 is shared with GPIO_1 */ -#define GPIO_FUNC_SPI_CS1_EN (1 << 14) +#define GPIO_FUNC_SPI_CS1_EN (1 << 12) /* CS1 is shared with GPIO_0 */ -#define GPIO_FUNC_SPI_EN (1 << 13) #define GPIO_FUNC_UART_EN (1 << 8) #define GPIO_FUNC_USB_OC_EN (1 << 4) #define GPIO_FUNC_USB_CLK_EN (0) #define AR71XX_BASE_FREQ 40000000 +#define AR71XX_PLL_CPU_BASE 0x18050000 #define AR71XX_PLL_CPU_CONFIG 0x18050000 #define PLL_SW_UPDATE (1 << 31) #define PLL_LOCKED (1 << 30) @@ -181,6 +181,8 @@ #define PLL_BYPASS (1 << 1) #define PLL_POWER_DOWN (1 << 0) #define AR71XX_PLL_SEC_CONFIG 0x18050004 +#define AR71XX_PLL_ETH0_SHIFT 17 +#define AR71XX_PLL_ETH1_SHIFT 19 #define AR71XX_PLL_CPU_CLK_CTRL 0x18050008 #define AR71XX_PLL_ETH_INT0_CLK 0x18050010 #define AR71XX_PLL_ETH_INT1_CLK 0x18050014 @@ -194,6 +196,9 @@ #define AR71XX_PLL_ETH_EXT_CLK 0x18050018 #define AR71XX_PLL_PCI_CLK 0x1805001C +/* Reset block */ +#define AR71XX_RST_BLOCK_BASE 0x18060000 + #define AR71XX_RST_WDOG_CONTROL 0x18060008 #define RST_WDOG_LAST (1 << 31) #define RST_WDOG_ACTION_MASK 3 @@ -235,6 +240,33 @@ #define RST_RESET_PCI_BUS (1 << 1) #define RST_RESET_PCI_CORE (1 << 0) +/* Chipset revision details */ +#define AR71XX_RST_RESET_REG_REV_ID 0x18060090 +#define REV_ID_MAJOR_MASK 0xfff0 +#define REV_ID_MAJOR_AR71XX 0x00a0 +#define REV_ID_MAJOR_AR913X 0x00b0 +#define REV_ID_MAJOR_AR7240 0x00c0 +#define REV_ID_MAJOR_AR7241 0x0100 +#define REV_ID_MAJOR_AR7242 0x1100 + +/* AR71XX chipset revision details */ +#define AR71XX_REV_ID_MINOR_MASK 0x3 +#define AR71XX_REV_ID_MINOR_AR7130 0x0 +#define AR71XX_REV_ID_MINOR_AR7141 0x1 +#define AR71XX_REV_ID_MINOR_AR7161 0x2 +#define AR71XX_REV_ID_REVISION_MASK 0x3 +#define AR71XX_REV_ID_REVISION_SHIFT 2 + +/* AR724X chipset revision details */ +#define AR724X_REV_ID_REVISION_MASK 0x3 + +/* AR91XX chipset revision details */ +#define AR91XX_REV_ID_MINOR_MASK 0x3 +#define AR91XX_REV_ID_MINOR_AR9130 0x0 +#define AR91XX_REV_ID_MINOR_AR9132 0x1 +#define AR91XX_REV_ID_REVISION_MASK 0x3 +#define AR91XX_REV_ID_REVISION_SHIFT 2 + /* * GigE adapters region */ @@ -459,37 +491,38 @@ #define ATH_WRITE_REG(reg, val) \ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg))) = (val) -static inline uint64_t -ar71xx_cpu_freq(void) +static inline void +ar71xx_ddr_flush(uint32_t reg) +{ + ATH_WRITE_REG(reg, 1); + while ((ATH_READ_REG(reg) & 0x1)) + ; + ATH_WRITE_REG(reg, 1); + while ((ATH_READ_REG(reg) & 0x1)) + ; +} + +static inline void +ar71xx_write_pll(uint32_t cfg_reg, uint32_t pll_reg, uint32_t pll, uint32_t pll_reg_shift) { - uint32_t pll_config, div; - uint64_t freq; + uint32_t sec_cfg; - /* PLL freq */ - pll_config = ATH_READ_REG(AR71XX_PLL_CPU_CONFIG); - div = ((pll_config >> PLL_FB_SHIFT) & PLL_FB_MASK) + 1; - freq = div * AR71XX_BASE_FREQ; - /* CPU freq */ - div = ((pll_config >> PLL_CPU_DIV_SEL_SHIFT) & PLL_CPU_DIV_SEL_MASK) - + 1; - freq = freq / div; + /* set PLL registers */ + sec_cfg = ATH_READ_REG(cfg_reg); + sec_cfg &= ~(3 << pll_reg_shift); + sec_cfg |= (2 << pll_reg_shift); - return (freq); + ATH_WRITE_REG(cfg_reg, sec_cfg); + DELAY(100); + + ATH_WRITE_REG(pll_reg, pll); + sec_cfg |= (3 << pll_reg_shift); + ATH_WRITE_REG(cfg_reg, sec_cfg); + DELAY(100); + + sec_cfg &= ~(3 << pll_reg_shift); + ATH_WRITE_REG(cfg_reg, sec_cfg); + DELAY(100); } -static inline uint64_t -ar71xx_ahb_freq(void) -{ - uint32_t pll_config, div; - uint64_t freq; - - /* PLL freq */ - pll_config = ATH_READ_REG(AR71XX_PLL_CPU_CONFIG); - /* AHB freq */ - div = (((pll_config >> PLL_AHB_DIV_SHIFT) & PLL_AHB_DIV_MASK) + 1) * 2; - freq = ar71xx_cpu_freq() / div; - return (freq); -} - - #endif /* _AR71XX_REG_H_ */ diff --git a/sys/mips/atheros/ar724x_chip.c b/sys/mips/atheros/ar724x_chip.c new file mode 100644 index 00000000000..450dd19e942 --- /dev/null +++ b/sys/mips/atheros/ar724x_chip.c @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static void +ar724x_chip_detect_mem_size(void) +{ +} + +static void +ar724x_chip_detect_sys_frequency(void) +{ + uint32_t pll; + uint32_t freq; + uint32_t div; + + pll = ATH_READ_REG(AR724X_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); + freq = div * AR724X_BASE_FREQ; + + div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); + freq *= div; + + u_ar71xx_cpu_freq = freq; + + div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; + u_ar71xx_ddr_freq = freq / div; + + div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; + u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; +} + +static void +ar724x_chip_device_stop(uint32_t mask) +{ + uint32_t mask_inv, reg; + + mask_inv = mask & AR724X_RESET_MODULE_USB_OHCI_DLL; + reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); + reg |= mask; + reg &= ~mask_inv; + ATH_WRITE_REG(AR724X_RESET_REG_RESET_MODULE, reg); +} + +static void +ar724x_chip_device_start(uint32_t mask) +{ + uint32_t mask_inv, reg; + + mask_inv = mask & AR724X_RESET_MODULE_USB_OHCI_DLL; + reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); + reg &= ~mask; + reg |= mask_inv; + ATH_WRITE_REG(AR724X_RESET_REG_RESET_MODULE, reg); +} + +static int +ar724x_chip_device_stopped(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); + return ((reg & mask) == mask); +} + +static void +ar724x_chip_set_pll_ge0(int speed) +{ +} + +static void +ar724x_chip_set_pll_ge1(int speed) +{ +} + +static void +ar724x_chip_ddr_flush_ge0(void) +{ +} + +static void +ar724x_chip_ddr_flush_ge1(void) +{ +} + +static uint32_t +ar724x_chip_get_eth_pll(unsigned int mac, int speed) +{ + return 0; +} + +struct ar71xx_cpu_def ar724x_chip_def = { + &ar724x_chip_detect_mem_size, + &ar724x_chip_detect_sys_frequency, + &ar724x_chip_device_stop, + &ar724x_chip_device_start, + &ar724x_chip_device_stopped, + &ar724x_chip_set_pll_ge0, + &ar724x_chip_set_pll_ge1, + &ar724x_chip_ddr_flush_ge0, + &ar724x_chip_ddr_flush_ge1, + &ar724x_chip_get_eth_pll, + NULL, /* ar71xx_chip_irq_flush_ip2 */ + NULL /* ar71xx_chip_init_usb_peripheral */ +}; diff --git a/sys/mips/atheros/ar724x_chip.h b/sys/mips/atheros/ar724x_chip.h new file mode 100644 index 00000000000..11b30b7a217 --- /dev/null +++ b/sys/mips/atheros/ar724x_chip.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR724X_CHIP_H__ +#define __AR724X_CHIP_H__ + +extern struct ar71xx_cpu_def ar724x_chip_def; + +#endif diff --git a/sys/mips/atheros/ar724xreg.h b/sys/mips/atheros/ar724xreg.h new file mode 100644 index 00000000000..ec7ef1552c0 --- /dev/null +++ b/sys/mips/atheros/ar724xreg.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR72XX_REG_H__ +#define __AR72XX_REG_H__ + +#define AR724X_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 +#define AR724X_PLL_REG_PCIE_CONFIG AR71XX_PLL_CPU_BASE + 0x18 + +#define AR724X_PLL_DIV_SHIFT 0 +#define AR724X_PLL_DIV_MASK 0x3ff +#define AR724X_PLL_REF_DIV_SHIFT 10 +#define AR724X_PLL_REF_DIV_MASK 0xf +#define AR724X_AHB_DIV_SHIFT 19 +#define AR724X_AHB_DIV_MASK 0x1 +#define AR724X_DDR_DIV_SHIFT 22 +#define AR724X_DDR_DIV_MASK 0x3 + +#define AR724X_PLL_VAL_1000 0x00110000 +#define AR724X_PLL_VAL_100 0x00001099 +#define AR724X_PLL_VAL_10 0x00991099 + +#define AR724X_BASE_FREQ 5000000 + +#define AR724X_RESET_REG_RESET_MODULE AR71XX_RST_BLOCK_BASE + 0x1c +#define AR724X_RESET_MODULE_USB_OHCI_DLL (1 << 3) + +/* XXX so USB requires different init code? -adrian */ +#define AR7240_OHCI_BASE 0x1b000000 +#define AR7240_OHCI_SIZE 0x01000000 +#define AR724X_DDR_REG_FLUSH_USB (AR71XX_DDR_CONFIG + 0x84) + +#define AR724X_PCI_CRP_BASE (AR71XX_APB_BASE + 0x000C0000) +#define AR724X_PCI_CRP_SIZE 0x100 + +#define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000F0000) +#define AR724X_PCI_CTRL_SIZE 0x100 + +#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN (1 >> 19) +#define AR724X_GPIO_FUNC_SPI_EN (1 >> 18) +#define AR724X_GPIO_FUNC_SPI_CS_EN2 (1 >> 14) +#define AR724X_GPIO_FUNC_SPI_CS_EN1 (1 >> 13) +#define AR724X_GPIO_FUNC_CLK_OBS5_EN (1 >> 12) +#define AR724X_GPIO_FUNC_CLK_OBS4_EN (1 >> 11) +#define AR724X_GPIO_FUNC_CLK_OBS3_EN (1 >> 10) +#define AR724X_GPIO_FUNC_CLK_OBS2_EN (1 >> 9) +#define AR724X_GPIO_FUNC_CLK_OBS1_EN (1 >> 8) +#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN (1 >> 7) +#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN (1 >> 6) +#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN (1 >> 5) +#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN (1 >> 4) +#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN (1 >> 3) +#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN (1 >> 2) +#define AR724X_GPIO_FUNC_UART_EN (1 >> 1) +#define AR724X_GPIO_FUNC_JTAG_DISABLE (1 >> 0) + +#define AR724X_GPIO_COUNT 18 + +#endif diff --git a/sys/mips/atheros/ar91xx_chip.c b/sys/mips/atheros/ar91xx_chip.c new file mode 100644 index 00000000000..ae221561f52 --- /dev/null +++ b/sys/mips/atheros/ar91xx_chip.c @@ -0,0 +1,205 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static void +ar91xx_chip_detect_mem_size(void) +{ +} + +static void +ar91xx_chip_detect_sys_frequency(void) +{ + uint32_t pll; + uint32_t freq; + uint32_t div; + + pll = ATH_READ_REG(AR91XX_PLL_REG_CPU_CONFIG); + + div = ((pll >> AR91XX_PLL_DIV_SHIFT) & AR91XX_PLL_DIV_MASK); + freq = div * AR91XX_BASE_FREQ; + + u_ar71xx_cpu_freq = freq; + + div = ((pll >> AR91XX_DDR_DIV_SHIFT) & AR91XX_DDR_DIV_MASK) + 1; + u_ar71xx_ddr_freq = freq / div; + + div = (((pll >> AR91XX_AHB_DIV_SHIFT) & AR91XX_AHB_DIV_MASK) + 1) * 2; + u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; +} + +static void +ar91xx_chip_device_stop(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); + ATH_WRITE_REG(AR91XX_RESET_REG_RESET_MODULE, reg | mask); +} + +static void +ar91xx_chip_device_start(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); + ATH_WRITE_REG(AR91XX_RESET_REG_RESET_MODULE, reg & ~mask); +} + +static int +ar91xx_chip_device_stopped(uint32_t mask) +{ + uint32_t reg; + + reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); + return ((reg & mask) == mask); +} + +static void +ar91xx_chip_set_pll_ge0(int speed) +{ + uint32_t pll; + + switch(speed) { + case 10: + pll = AR91XX_PLL_VAL_10; + break; + case 100: + pll = AR91XX_PLL_VAL_100; + break; + case 1000: + pll = AR91XX_PLL_VAL_1000; + break; + default: + printf("ar91xx_chip_set_pll_ge0: invalid speed %d\n", speed); + return; + } + ar71xx_write_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK, pll, AR91XX_ETH0_PLL_SHIFT); +} + +static void +ar91xx_chip_set_pll_ge1(int speed) +{ + uint32_t pll; + + switch(speed) { + case 10: + pll = AR91XX_PLL_VAL_10; + break; + case 100: + pll = AR91XX_PLL_VAL_100; + break; + case 1000: + pll = AR91XX_PLL_VAL_1000; + break; + default: + printf("ar91xx_chip_set_pll_ge0: invalid speed %d\n", speed); + return; + } + ar71xx_write_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK, pll, AR91XX_ETH1_PLL_SHIFT); +} + +static void +ar91xx_chip_ddr_flush_ge0(void) +{ + ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE0); +} + +static void +ar91xx_chip_ddr_flush_ge1(void) +{ + ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE1); +} + +static uint32_t +ar91xx_chip_get_eth_pll(unsigned int mac, int speed) +{ + return 0; +} + +static void +ar91xx_chip_init_usb_peripheral(void) +{ + ar71xx_device_stop(AR91XX_RST_RESET_MODULE_USBSUS_OVERRIDE); + DELAY(100); + + ar71xx_device_start(RST_RESET_USB_HOST); + DELAY(100); + + ar71xx_device_start(RST_RESET_USB_PHY); + DELAY(100); +} + +struct ar71xx_cpu_def ar91xx_chip_def = { + &ar91xx_chip_detect_mem_size, + &ar91xx_chip_detect_sys_frequency, + &ar91xx_chip_device_stop, + &ar91xx_chip_device_start, + &ar91xx_chip_device_stopped, + &ar91xx_chip_set_pll_ge0, + &ar91xx_chip_set_pll_ge1, + &ar91xx_chip_ddr_flush_ge0, + &ar91xx_chip_ddr_flush_ge1, + &ar91xx_chip_get_eth_pll, + NULL, + &ar91xx_chip_init_usb_peripheral, +}; diff --git a/sys/mips/atheros/ar91xx_chip.h b/sys/mips/atheros/ar91xx_chip.h new file mode 100644 index 00000000000..a98c2649fef --- /dev/null +++ b/sys/mips/atheros/ar91xx_chip.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR91XX_CHIP_H__ +#define __AR91XX_CHIP_H__ + +extern struct ar71xx_cpu_def ar91xx_chip_def; + +#endif diff --git a/sys/mips/atheros/ar91xxreg.h b/sys/mips/atheros/ar91xxreg.h new file mode 100644 index 00000000000..8fecddff071 --- /dev/null +++ b/sys/mips/atheros/ar91xxreg.h @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2010 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef __AR91XX_REG_H__ +#define __AR91XX_REG_H__ + +#define AR91XX_BASE_FREQ 5000000 + +/* reset block */ +#define AR91XX_RESET_REG_RESET_MODULE AR71XX_RST_BLOCK_BASE + 0x1c + +#define AR91XX_RST_RESET_MODULE_USBSUS_OVERRIDE (1 << 10) + +/* PLL block */ +#define AR91XX_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 +#define AR91XX_PLL_REG_ETH_CONFIG AR71XX_PLL_CPU_BASE + 0x04 +#define AR91XX_PLL_REG_ETH0_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x14 +#define AR91XX_PLL_REG_ETH1_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x18 + +#define AR91XX_PLL_DIV_SHIFT 0 +#define AR91XX_PLL_DIV_MASK 0x3ff +#define AR91XX_DDR_DIV_SHIFT 22 +#define AR91XX_DDR_DIV_MASK 0x3 +#define AR91XX_AHB_DIV_SHIFT 19 +#define AR91XX_AHB_DIV_MASK 0x1 + +#define AR91XX_ETH0_PLL_SHIFT 20 +#define AR91XX_ETH1_PLL_SHIFT 22 + +#define AR91XX_PLL_VAL_1000 0x1a000000 +#define AR91XX_PLL_VAL_100 0x13000a44 +#define AR91XX_PLL_VAL_10 0x00441099 + +/* DDR block */ +#define AR91XX_DDR_CTRLBASE (AR71XX_APB_BASE + 0) +#define AR91XX_DDR_CTRL_SIZE 0x10000 +#define AR91XX_DDR_REG_FLUSH_GE0 AR91XX_DDR_CTRLBASE + 0x7c +#define AR91XX_DDR_REG_FLUSH_GE1 AR91XX_DDR_CTRLBASE + 0x80 +#define AR91XX_DDR_REG_FLUSH_USB AR91XX_DDR_CTRLBASE + 0x84 +#define AR91XX_DDR_REG_FLUSH_WMAC AR91XX_DDR_CTRLBASE + 0x88 + +/* WMAC stuff */ +#define AR91XX_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) +#define AR91XX_WMAC_SIZE 0x30000 + +/* GPIO stuff */ +#define AR91XX_GPIO_FUNC_WMAC_LED_EN (1 << 22) +#define AR91XX_GPIO_FUNC_EXP_PORT_CS_EN (1 << 21) +#define AR91XX_GPIO_FUNC_I2S_REFCLKEN (1 << 20) +#define AR91XX_GPIO_FUNC_I2S_MCKEN (1 << 19) +#define AR91XX_GPIO_FUNC_I2S1_EN (1 << 18) +#define AR91XX_GPIO_FUNC_I2S0_EN (1 << 17) +#define AR91XX_GPIO_FUNC_SLIC_EN (1 << 16) +#define AR91XX_GPIO_FUNC_UART_RTSCTS_EN (1 << 9) +#define AR91XX_GPIO_FUNC_UART_EN (1 << 8) +#define AR91XX_GPIO_FUNC_USB_CLK_EN (1 << 4) + +#define AR91XX_GPIO_COUNT 22 + +#endif diff --git a/sys/mips/atheros/files.ar71xx b/sys/mips/atheros/files.ar71xx index fed21afc83b..d3630fdf05a 100644 --- a/sys/mips/atheros/files.ar71xx +++ b/sys/mips/atheros/files.ar71xx @@ -1,6 +1,7 @@ # $FreeBSD$ mips/atheros/apb.c standard +mips/atheros/ar71xx_gpio.c optional gpio mips/atheros/ar71xx_machdep.c standard mips/atheros/ar71xx_ehci.c optional ehci mips/atheros/ar71xx_ohci.c optional ohci @@ -15,3 +16,7 @@ mips/atheros/uart_cpu_ar71xx.c optional uart mips/atheros/ar71xx_bus_space_reversed.c standard mips/mips/intr_machdep.c standard mips/mips/tick.c standard +mips/atheros/ar71xx_setup.c standard +mips/atheros/ar71xx_chip.c standard +mips/atheros/ar724x_chip.c standard +mips/atheros/ar91xx_chip.c standard diff --git a/sys/mips/atheros/if_arge.c b/sys/mips/atheros/if_arge.c index 807173d92b1..a12ace85581 100644 --- a/sys/mips/atheros/if_arge.c +++ b/sys/mips/atheros/if_arge.c @@ -79,6 +79,7 @@ MODULE_DEPEND(arge, miibus, 1, 1, 1); #include #include +#include #undef ARGE_DEBUG #ifdef ARGE_DEBUG @@ -181,14 +182,10 @@ MTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF); static void arge_flush_ddr(struct arge_softc *sc) { - - ATH_WRITE_REG(sc->arge_ddr_flush_reg, 1); - while (ATH_READ_REG(sc->arge_ddr_flush_reg) & 1) - ; - - ATH_WRITE_REG(sc->arge_ddr_flush_reg, 1); - while (ATH_READ_REG(sc->arge_ddr_flush_reg) & 1) - ; + if (sc->arge_mac_unit == 0) + ar71xx_device_flush_ddr_ge0(); + else + ar71xx_device_flush_ddr_ge1(); } static int @@ -236,15 +233,6 @@ arge_attach(device_t dev) KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)), ("if_arge: Only MAC0 and MAC1 supported")); - if (sc->arge_mac_unit == 0) { - sc->arge_ddr_flush_reg = AR71XX_WB_FLUSH_GE0; - sc->arge_pll_reg = AR71XX_PLL_ETH_INT0_CLK; - sc->arge_pll_reg_shift = 17; - } else { - sc->arge_ddr_flush_reg = AR71XX_WB_FLUSH_GE1; - sc->arge_pll_reg = AR71XX_PLL_ETH_INT1_CLK; - sc->arge_pll_reg_shift = 19; - } /* * Get which PHY of 5 available we should use for this unit @@ -381,19 +369,9 @@ arge_attach(device_t dev) DELAY(20); /* Step 2. Punt the MAC core from the central reset register */ - reg = ATH_READ_REG(AR71XX_RST_RESET); - if (sc->arge_mac_unit == 0) - reg |= RST_RESET_GE0_MAC; - else if (sc->arge_mac_unit == 1) - reg |= RST_RESET_GE1_MAC; - ATH_WRITE_REG(AR71XX_RST_RESET, reg); + ar71xx_device_stop(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC); DELAY(100); - reg = ATH_READ_REG(AR71XX_RST_RESET); - if (sc->arge_mac_unit == 0) - reg &= ~RST_RESET_GE0_MAC; - else if (sc->arge_mac_unit == 1) - reg &= ~RST_RESET_GE1_MAC; - ATH_WRITE_REG(AR71XX_RST_RESET, reg); + ar71xx_device_start(sc->arge_mac_unit == 0 ? RST_RESET_GE0_MAC : RST_RESET_GE1_MAC); /* Step 3. Reconfigure MAC block */ ARGE_WRITE(sc, AR71XX_MAC_CFG1, @@ -446,10 +424,11 @@ arge_attach(device_t dev) if (phys_total == 1) { /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->arge_miibus, - arge_ifmedia_upd, arge_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->arge_miibus, ifp, + arge_ifmedia_upd, arge_ifmedia_sts, BMSR_DEFCAPMASK, + MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } } @@ -683,7 +662,8 @@ arge_link_task(void *arg, int pending) static void arge_set_pll(struct arge_softc *sc, int media, int duplex) { - uint32_t cfg, ifcontrol, rx_filtmask, pll, sec_cfg; + uint32_t cfg, ifcontrol, rx_filtmask; + int if_speed; cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); cfg &= ~(MAC_CFG2_IFACE_MODE_1000 @@ -702,21 +682,21 @@ arge_set_pll(struct arge_softc *sc, int media, int duplex) switch(media) { case IFM_10_T: cfg |= MAC_CFG2_IFACE_MODE_10_100; - pll = PLL_ETH_INT_CLK_10; + if_speed = 10; break; case IFM_100_TX: cfg |= MAC_CFG2_IFACE_MODE_10_100; ifcontrol |= MAC_IFCONTROL_SPEED; - pll = PLL_ETH_INT_CLK_100; + if_speed = 100; break; case IFM_1000_T: case IFM_1000_SX: cfg |= MAC_CFG2_IFACE_MODE_1000; rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; - pll = PLL_ETH_INT_CLK_1000; + if_speed = 1000; break; default: - pll = PLL_ETH_INT_CLK_100; + if_speed = 100; device_printf(sc->arge_dev, "Unknown media %d\n", media); } @@ -730,22 +710,10 @@ arge_set_pll(struct arge_softc *sc, int media, int duplex) rx_filtmask); /* set PLL registers */ - sec_cfg = ATH_READ_REG(AR71XX_PLL_SEC_CONFIG); - sec_cfg &= ~(3 << sc->arge_pll_reg_shift); - sec_cfg |= (2 << sc->arge_pll_reg_shift); - - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); - - ATH_WRITE_REG(sc->arge_pll_reg, pll); - - sec_cfg |= (3 << sc->arge_pll_reg_shift); - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); - - sec_cfg &= ~(3 << sc->arge_pll_reg_shift); - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); + if (sc->arge_mac_unit == 0) + ar71xx_device_set_pll_ge0(if_speed); + else + ar71xx_device_set_pll_ge1(if_speed); } diff --git a/sys/mips/atheros/if_argevar.h b/sys/mips/atheros/if_argevar.h index df1c34dd018..4c336afdbbe 100644 --- a/sys/mips/atheros/if_argevar.h +++ b/sys/mips/atheros/if_argevar.h @@ -150,9 +150,6 @@ struct arge_softc { uint32_t arge_intr_status; int arge_mac_unit; int arge_phymask; - uint32_t arge_ddr_flush_reg; - uint32_t arge_pll_reg; - uint32_t arge_pll_reg_shift; int arge_if_flags; uint32_t arge_debug; struct { diff --git a/sys/mips/atheros/uart_bus_ar71xx.c b/sys/mips/atheros/uart_bus_ar71xx.c index 8d83291c271..4c04aba360f 100644 --- a/sys/mips/atheros/uart_bus_ar71xx.c +++ b/sys/mips/atheros/uart_bus_ar71xx.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include "uart_if.h" diff --git a/sys/mips/atheros/uart_cpu_ar71xx.c b/sys/mips/atheros/uart_cpu_ar71xx.c index 4528ac68142..8465c26d650 100644 --- a/sys/mips/atheros/uart_cpu_ar71xx.c +++ b/sys/mips/atheros/uart_cpu_ar71xx.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include bus_space_tag_t uart_bus_space_io; diff --git a/sys/mips/cavium/ciu.c b/sys/mips/cavium/ciu.c index ee1dd4dbf1d..eb58928ca95 100644 --- a/sys/mips/cavium/ciu.c +++ b/sys/mips/cavium/ciu.c @@ -78,6 +78,8 @@ static struct resource *ciu_alloc_resource(device_t, device_t, int, int *, static int ciu_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); +static int ciu_teardown_intr(device_t, device_t, + struct resource *, void *); static void ciu_hinted_child(device_t, const char *, int); static void ciu_en0_intr_mask(void *); @@ -230,6 +232,19 @@ ciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags, return (0); } +static int +ciu_teardown_intr(device_t bus, device_t child, struct resource *res, + void *cookie) +{ + int error; + + error = intr_event_remove_handler(cookie); + if (error != 0) + return (error); + + return (0); +} + static void ciu_hinted_child(device_t bus, const char *dname, int dunit) { @@ -342,7 +357,7 @@ static device_method_t ciu_methods[] = { DEVMETHOD(bus_alloc_resource, ciu_alloc_resource), DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), DEVMETHOD(bus_setup_intr, ciu_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_teardown_intr, ciu_teardown_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_hinted_child, ciu_hinted_child), diff --git a/sys/mips/cavium/files.octeon1 b/sys/mips/cavium/files.octeon1 index c8dc43ca3a3..9bd88375125 100644 --- a/sys/mips/cavium/files.octeon1 +++ b/sys/mips/cavium/files.octeon1 @@ -21,6 +21,7 @@ mips/cavium/cryptocteon/cavium_crypto.c optional cryptocteon mips/cavium/cryptocteon/cryptocteon.c optional cryptocteon mips/cavium/octe/ethernet.c optional octe +mips/cavium/octe/ethernet-mv88e61xx.c optional octe octeon_vendor_lanner mips/cavium/octe/ethernet-common.c optional octe mips/cavium/octe/ethernet-mdio.c optional octe mips/cavium/octe/ethernet-mem.c optional octe @@ -30,6 +31,7 @@ mips/cavium/octe/ethernet-sgmii.c optional octe mips/cavium/octe/ethernet-spi.c optional octe mips/cavium/octe/ethernet-tx.c optional octe mips/cavium/octe/ethernet-xaui.c optional octe +mips/cavium/octe/mv88e61xxphy.c optional octe mv88e61xxphy mips/cavium/octe/octe.c optional octe mips/cavium/octe/octebus.c optional octe @@ -39,30 +41,29 @@ mips/cavium/octopci_bus_space.c optional pci mips/cavium/usb/octusb.c optional usb octusb mips/cavium/usb/octusb_octeon.c optional usb octusb -contrib/octeon-sdk/cvmx-cmd-queue.c optional octe -contrib/octeon-sdk/cvmx-fpa.c optional octe -contrib/octeon-sdk/cvmx-helper.c optional octe -contrib/octeon-sdk/cvmx-helper-board.c optional octe -contrib/octeon-sdk/cvmx-helper-errata.c optional octe -contrib/octeon-sdk/cvmx-helper-fpa.c optional octe -contrib/octeon-sdk/cvmx-helper-loop.c optional octe -contrib/octeon-sdk/cvmx-helper-npi.c optional octe -contrib/octeon-sdk/cvmx-helper-rgmii.c optional octe -contrib/octeon-sdk/cvmx-helper-sgmii.c optional octe -contrib/octeon-sdk/cvmx-helper-spi.c optional octe -contrib/octeon-sdk/cvmx-helper-util.c optional octe -contrib/octeon-sdk/cvmx-helper-xaui.c optional octe -contrib/octeon-sdk/cvmx-pko.c optional octe -contrib/octeon-sdk/cvmx-spi.c optional octe -contrib/octeon-sdk/cvmx-spi4000.c optional octe -contrib/octeon-sdk/cvmx-twsi.c optional octe - contrib/octeon-sdk/cvmx-usb.c optional octusb # XXX Some files could be excluded in some configurations. Making them # optional but on in the default config would seem reasonable. +contrib/octeon-sdk/cvmx-cmd-queue.c standard contrib/octeon-sdk/cvmx-bootmem.c standard +contrib/octeon-sdk/cvmx-fpa.c standard +contrib/octeon-sdk/cvmx-helper.c standard +contrib/octeon-sdk/cvmx-helper-board.c standard +contrib/octeon-sdk/cvmx-helper-errata.c standard +contrib/octeon-sdk/cvmx-helper-fpa.c standard +contrib/octeon-sdk/cvmx-helper-loop.c standard +contrib/octeon-sdk/cvmx-helper-npi.c standard +contrib/octeon-sdk/cvmx-helper-rgmii.c standard +contrib/octeon-sdk/cvmx-helper-sgmii.c standard +contrib/octeon-sdk/cvmx-helper-spi.c standard +contrib/octeon-sdk/cvmx-helper-util.c standard +contrib/octeon-sdk/cvmx-helper-xaui.c standard +contrib/octeon-sdk/cvmx-pko.c standard +contrib/octeon-sdk/cvmx-spi.c standard +contrib/octeon-sdk/cvmx-spi4000.c standard contrib/octeon-sdk/cvmx-sysinfo.c standard contrib/octeon-sdk/cvmx-thunder.c standard +contrib/octeon-sdk/cvmx-twsi.c standard contrib/octeon-sdk/cvmx-warn.c standard contrib/octeon-sdk/octeon-model.c standard diff --git a/sys/mips/cavium/obio.c b/sys/mips/cavium/obio.c index f1ceab4fe68..47057303c07 100644 --- a/sys/mips/cavium/obio.c +++ b/sys/mips/cavium/obio.c @@ -192,6 +192,8 @@ static device_method_t obio_methods[] = { DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_add_child, bus_generic_add_child), + {0, 0}, }; diff --git a/sys/mips/cavium/octe/cavium-ethernet.h b/sys/mips/cavium/octe/cavium-ethernet.h index 0ab2680c999..dce2d2bcfa7 100644 --- a/sys/mips/cavium/octe/cavium-ethernet.h +++ b/sys/mips/cavium/octe/cavium-ethernet.h @@ -72,9 +72,14 @@ typedef struct { uint8_t mac[6]; int phy_id; + const char *phy_device; + int (*mdio_read)(struct ifnet *, int, int); + void (*mdio_write)(struct ifnet *, int, int, int); struct ifqueue tx_free_queue[16]; + int need_link_update; + struct task link_task; struct ifmedia media; int if_flags; diff --git a/sys/mips/cavium/octe/ethernet-common.c b/sys/mips/cavium/octe/ethernet-common.c index 2ebbb09a017..9db9830915e 100644 --- a/sys/mips/cavium/octe/ethernet-common.c +++ b/sys/mips/cavium/octe/ethernet-common.c @@ -266,6 +266,20 @@ int cvm_oct_common_init(struct ifnet *ifp) memset(ifp->get_stats(ifp), 0, sizeof(struct ifnet_stats)); #endif + /* + * Do any last-minute board-specific initialization. + */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR320: + if (priv->phy_id == 16) + cvm_oct_mv88e61xx_setup_device(ifp); + break; +#endif + default: + break; + } + device_attach(priv->dev); return 0; diff --git a/sys/mips/cavium/octe/ethernet-headers.h b/sys/mips/cavium/octe/ethernet-headers.h index ec87c456288..3945e13ac67 100644 --- a/sys/mips/cavium/octe/ethernet-headers.h +++ b/sys/mips/cavium/octe/ethernet-headers.h @@ -40,4 +40,11 @@ AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR W #include "ethernet-tx.h" #include "ethernet-util.h" +/* + * Any board- or vendor-specific includes. + */ +#ifdef OCTEON_VENDOR_LANNER +#include "ethernet-mv88e61xx.h" +#endif + #endif diff --git a/sys/mips/cavium/octe/ethernet-mdio.c b/sys/mips/cavium/octe/ethernet-mdio.c index 0aff27e6f72..19b4d43c70d 100644 --- a/sys/mips/cavium/octe/ethernet-mdio.c +++ b/sys/mips/cavium/octe/ethernet-mdio.c @@ -132,6 +132,9 @@ int cvm_oct_mdio_setup_device(struct ifnet *ifp) cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; priv->phy_id = cvmx_helper_board_get_mii_address(priv->port); + priv->phy_device = NULL; + priv->mdio_read = NULL; + priv->mdio_write = NULL; return 0; } diff --git a/sys/mips/cavium/octe/ethernet-mv88e61xx.c b/sys/mips/cavium/octe/ethernet-mv88e61xx.c new file mode 100644 index 00000000000..31dbd74ecd2 --- /dev/null +++ b/sys/mips/cavium/octe/ethernet-mv88e61xx.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2010 Juli Mallett + * 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$ + */ + +/* + * Interface to the Marvell 88E61XX SMI/MDIO. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "wrapper-cvmx-includes.h" +#include "ethernet-headers.h" + +#define MV88E61XX_SMI_REG_CMD 0x00 /* Indirect command register. */ +#define MV88E61XX_SMI_CMD_BUSY 0x8000 /* Busy bit. */ +#define MV88E61XX_SMI_CMD_22 0x1000 /* Clause 22 (default 45.) */ +#define MV88E61XX_SMI_CMD_READ 0x0800 /* Read command. */ +#define MV88E61XX_SMI_CMD_WRITE 0x0400 /* Write command. */ +#define MV88E61XX_SMI_CMD_PHY(phy) (((phy) & 0x1f) << 5) +#define MV88E61XX_SMI_CMD_REG(reg) ((reg) & 0x1f) + +#define MV88E61XX_SMI_REG_DAT 0x01 /* Indirect data register. */ + +static int cvm_oct_mv88e61xx_smi_read(struct ifnet *, int, int); +static void cvm_oct_mv88e61xx_smi_write(struct ifnet *, int, int, int); +static int cvm_oct_mv88e61xx_smi_wait(struct ifnet *); + +int +cvm_oct_mv88e61xx_setup_device(struct ifnet *ifp) +{ + cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; + + priv->mdio_read = cvm_oct_mv88e61xx_smi_read; + priv->mdio_write = cvm_oct_mv88e61xx_smi_write; + priv->phy_device = "mv88e61xxphy"; + + return (0); +} + +static int +cvm_oct_mv88e61xx_smi_read(struct ifnet *ifp, int phy_id, int location) +{ + cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; + int error; + + error = cvm_oct_mv88e61xx_smi_wait(ifp); + if (error != 0) + return (0); + + cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD, + MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 | + MV88E61XX_SMI_CMD_READ | MV88E61XX_SMI_CMD_PHY(phy_id) | + MV88E61XX_SMI_CMD_REG(location)); + + error = cvm_oct_mv88e61xx_smi_wait(ifp); + if (error != 0) + return (0); + + return (cvm_oct_mdio_read(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT)); +} + +static void +cvm_oct_mv88e61xx_smi_write(struct ifnet *ifp, int phy_id, int location, int val) +{ + cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; + + cvm_oct_mv88e61xx_smi_wait(ifp); + cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT, val); + cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD, + MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 | + MV88E61XX_SMI_CMD_WRITE | MV88E61XX_SMI_CMD_PHY(phy_id) | + MV88E61XX_SMI_CMD_REG(location)); + cvm_oct_mv88e61xx_smi_wait(ifp); +} + +static int +cvm_oct_mv88e61xx_smi_wait(struct ifnet *ifp) +{ + cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; + uint16_t cmd; + unsigned i; + + for (i = 0; i < 10000; i++) { + cmd = cvm_oct_mdio_read(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD); + if ((cmd & MV88E61XX_SMI_CMD_BUSY) == 0) + return (0); + } + return (ETIMEDOUT); +} diff --git a/sys/mips/rmi/clock.h b/sys/mips/cavium/octe/ethernet-mv88e61xx.h similarity index 69% rename from sys/mips/rmi/clock.h rename to sys/mips/cavium/octe/ethernet-mv88e61xx.h index c0675810fc8..b61c05494d9 100644 --- a/sys/mips/rmi/clock.h +++ b/sys/mips/cavium/octe/ethernet-mv88e61xx.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2009 RMI Corporation + * Copyright (c) 2010 Juli Mallett * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,9 +10,6 @@ * 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 RMI Corporation, 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,16 +23,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ -#ifndef _RMI_CLOCK_H_ -#define _RMI_CLOCK_H_ + * $FreeBSD$ + */ -#define XLR_PIC_HZ 66000000U -#define XLR_CPU_HZ (xlr_boot1_info.cpu_frequency) +#ifndef _CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ +#define _CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ -int count_compare_clockhandler(struct trapframe *); -int pic_hardclockhandler(struct trapframe *); -int pic_timecounthandler(struct trapframe *); -void rmi_early_counter_init(void); +int cvm_oct_mv88e61xx_setup_device(struct ifnet *ifp); -#endif /* _RMI_CLOCK_H_ */ +#endif /* !_CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ */ diff --git a/sys/mips/cavium/octe/ethernet-rgmii.c b/sys/mips/cavium/octe/ethernet-rgmii.c index d5d704cc67b..ac55de8a705 100644 --- a/sys/mips/cavium/octe/ethernet-rgmii.c +++ b/sys/mips/cavium/octe/ethernet-rgmii.c @@ -136,27 +136,8 @@ static void cvm_oct_rgmii_poll(struct ifnet *ifp) link_info = cvmx_helper_link_autoconf(priv->port); priv->link_info = link_info.u64; + priv->need_link_update = 1; mtx_unlock_spin(&global_register_lock); - - /* Tell Linux */ - if (link_info.s.link_up) { - - if_link_state_change(ifp, LINK_STATE_UP); - if (priv->queue != -1) - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port, priv->queue); - else - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port); - } else { - - if_link_state_change(ifp, LINK_STATE_DOWN); - DEBUGPRINT("%s: Link down\n", if_name(ifp)); - } } diff --git a/sys/mips/cavium/octe/ethernet-rx.c b/sys/mips/cavium/octe/ethernet-rx.c index c6cc14c5440..2f8f0a8fbae 100644 --- a/sys/mips/cavium/octe/ethernet-rx.c +++ b/sys/mips/cavium/octe/ethernet-rx.c @@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include @@ -167,7 +169,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) */ void cvm_oct_tasklet_rx(void *context, int pending) { - const int coreid = cvmx_get_core_num(); + int coreid; uint64_t old_group_mask; uint64_t old_scratch; int rx_count = 0; @@ -175,6 +177,9 @@ void cvm_oct_tasklet_rx(void *context, int pending) int num_freed; int packet_not_copied; + sched_pin(); + coreid = cvmx_get_core_num(); + /* Prefetch cvm_oct_device since we know we need it soon */ CVMX_PREFETCH(cvm_oct_device, 0); @@ -388,6 +393,7 @@ void cvm_oct_tasklet_rx(void *context, int pending) } } } + sched_unpin(); } diff --git a/sys/mips/cavium/octe/ethernet-sgmii.c b/sys/mips/cavium/octe/ethernet-sgmii.c index 69549a11898..17e6be712bc 100644 --- a/sys/mips/cavium/octe/ethernet-sgmii.c +++ b/sys/mips/cavium/octe/ethernet-sgmii.c @@ -93,25 +93,7 @@ static void cvm_oct_sgmii_poll(struct ifnet *ifp) link_info = cvmx_helper_link_autoconf(priv->port); priv->link_info = link_info.u64; - - /* Tell Linux */ - if (link_info.s.link_up) { - - if_link_state_change(ifp, LINK_STATE_UP); - if (priv->queue != -1) - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port, priv->queue); - else - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port); - } else { - if_link_state_change(ifp, LINK_STATE_DOWN); - DEBUGPRINT("%s: Link down\n", if_name(ifp)); - } + priv->need_link_update = 1; } int cvm_oct_sgmii_init(struct ifnet *ifp) diff --git a/sys/mips/cavium/octe/ethernet-tx.c b/sys/mips/cavium/octe/ethernet-tx.c index fc4e273fa14..8866f120344 100644 --- a/sys/mips/cavium/octe/ethernet-tx.c +++ b/sys/mips/cavium/octe/ethernet-tx.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -239,6 +240,9 @@ int cvm_oct_xmit(struct mbuf *m, struct ifnet *ifp) } else { /* Put this packet on the queue to be freed later */ _IF_ENQUEUE(&priv->tx_free_queue[qos], m); + + /* Pass it to any BPF listeners. */ + ETHER_BPF_MTAP(ifp, m); } if (work != NULL) cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1)); diff --git a/sys/mips/cavium/octe/ethernet-xaui.c b/sys/mips/cavium/octe/ethernet-xaui.c index 4eb4be72c9e..455aec67e03 100644 --- a/sys/mips/cavium/octe/ethernet-xaui.c +++ b/sys/mips/cavium/octe/ethernet-xaui.c @@ -92,25 +92,7 @@ static void cvm_oct_xaui_poll(struct ifnet *ifp) link_info = cvmx_helper_link_autoconf(priv->port); priv->link_info = link_info.u64; - - /* Tell Linux */ - if (link_info.s.link_up) { - - if_link_state_change(ifp, LINK_STATE_UP); - if (priv->queue != -1) - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port, priv->queue); - else - DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", - if_name(ifp), link_info.s.speed, - (link_info.s.full_duplex) ? "Full" : "Half", - priv->port); - } else { - if_link_state_change(ifp, LINK_STATE_DOWN); - DEBUGPRINT("%s: Link down\n", if_name(ifp)); - } + priv->need_link_update = 1; } diff --git a/sys/mips/cavium/octe/ethernet.c b/sys/mips/cavium/octe/ethernet.c index 1f7901ff6e2..1463c8ad4c9 100644 --- a/sys/mips/cavium/octe/ethernet.c +++ b/sys/mips/cavium/octe/ethernet.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -129,6 +130,40 @@ static struct callout cvm_oct_poll_timer; */ struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; +/** + * Task to handle link status changes. + */ +static struct taskqueue *cvm_oct_link_taskq; + +/** + * Function to update link status. + */ +static void cvm_oct_update_link(void *context, int pending) +{ + cvm_oct_private_t *priv = (cvm_oct_private_t *)context; + struct ifnet *ifp = priv->ifp; + cvmx_helper_link_info_t link_info; + + link_info.u64 = priv->link_info; + + if (link_info.s.link_up) { + if_link_state_change(ifp, LINK_STATE_UP); + if (priv->queue != -1) + DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n", + if_name(ifp), link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port, priv->queue); + else + DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n", + if_name(ifp), link_info.s.speed, + (link_info.s.full_duplex) ? "Full" : "Half", + priv->port); + } else { + if_link_state_change(ifp, LINK_STATE_DOWN); + DEBUGPRINT("%s: Link down\n", if_name(ifp)); + } + priv->need_link_update = 0; +} /** * Periodic timer tick for slow management operations @@ -138,6 +173,7 @@ struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS]; static void cvm_do_timer(void *arg) { static int port; + static int updated; if (port < CVMX_PIP_NUM_INPUT_PORTS) { if (cvm_oct_device[port]) { int queues_per_port; @@ -149,6 +185,11 @@ static void cvm_do_timer(void *arg) if (MDIO_TRYLOCK()) { priv->poll(cvm_oct_device[port]); MDIO_UNLOCK(); + + if (priv->need_link_update) { + updated++; + taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task); + } } } @@ -181,9 +222,19 @@ static void cvm_do_timer(void *arg) callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); } else { port = 0; - /* All ports have been polled. Start the next iteration through - the ports in one second */ - callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); + /* If any updates were made in this run, continue iterating at + * 1/50th of a second, so that if a link has merely gone down + * temporarily (e.g. because of interface reinitialization) it + * will not be forced to stay down for an entire second. + */ + if (updated > 0) { + updated = 0; + callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL); + } else { + /* All ports have been polled. Start the next iteration through + the ports in one second */ + callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL); + } } } @@ -323,6 +374,11 @@ int cvm_oct_init_module(device_t bus) memset(cvm_oct_device, 0, sizeof(cvm_oct_device)); + cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT, + taskqueue_thread_enqueue, &cvm_oct_link_taskq); + taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET, + "octe link taskq"); + /* Initialize the FAU used for counting packet buffers that need to be freed */ cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0); @@ -345,6 +401,7 @@ int cvm_oct_init_module(device_t bus) priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED; priv->port = CVMX_PIP_NUM_INPUT_PORTS; priv->queue = -1; + TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv); device_set_desc(dev, "Cavium Octeon POW Ethernet\n"); @@ -398,6 +455,7 @@ int cvm_oct_init_module(device_t bus) priv->fau = fau - cvmx_pko_get_num_queues(port) * 4; for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++) cvmx_fau_atomic_write32(priv->fau+qos*4, 0); + TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv); switch (priv->imode) { diff --git a/sys/mips/cavium/octe/mv88e61xxphy.c b/sys/mips/cavium/octe/mv88e61xxphy.c new file mode 100644 index 00000000000..6d018c7cb74 --- /dev/null +++ b/sys/mips/cavium/octe/mv88e61xxphy.c @@ -0,0 +1,630 @@ +/*- + * Copyright (c) 2010 Juli Mallett + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Driver for the Marvell 88E61xx family of switch PHYs + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "miibus_if.h" + +#include "mv88e61xxphyreg.h" + +struct mv88e61xxphy_softc; + +struct mv88e61xxphy_port_softc { + struct mv88e61xxphy_softc *sc_switch; + unsigned sc_port; + unsigned sc_domain; + unsigned sc_vlan; + unsigned sc_priority; + unsigned sc_flags; +}; + +#define MV88E61XXPHY_PORT_FLAG_VTU_UPDATE (0x0001) + +struct mv88e61xxphy_softc { + device_t sc_dev; + struct mv88e61xxphy_port_softc sc_ports[MV88E61XX_PORTS]; +}; + +enum mv88e61xxphy_vtu_membership_type { + MV88E61XXPHY_VTU_UNMODIFIED, + MV88E61XXPHY_VTU_UNTAGGED, + MV88E61XXPHY_VTU_TAGGED, + MV88E61XXPHY_VTU_DISCARDED, +}; + +enum mv88e61xxphy_sysctl_link_type { + MV88E61XXPHY_LINK_SYSCTL_DUPLEX, + MV88E61XXPHY_LINK_SYSCTL_LINK, + MV88E61XXPHY_LINK_SYSCTL_MEDIA, +}; + +enum mv88e61xxphy_sysctl_port_type { + MV88E61XXPHY_PORT_SYSCTL_DOMAIN, + MV88E61XXPHY_PORT_SYSCTL_VLAN, + MV88E61XXPHY_PORT_SYSCTL_PRIORITY, +}; + +/* + * Register access macros. + */ +#define MV88E61XX_READ(sc, phy, reg) \ + MIIBUS_READREG(device_get_parent((sc)->sc_dev), (phy), (reg)) + +#define MV88E61XX_WRITE(sc, phy, reg, val) \ + MIIBUS_WRITEREG(device_get_parent((sc)->sc_dev), (phy), (reg), (val)) + +#define MV88E61XX_READ_PORT(psc, reg) \ + MV88E61XX_READ((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), (reg)) + +#define MV88E61XX_WRITE_PORT(psc, reg, val) \ + MV88E61XX_WRITE((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), (reg), (val)) + +static int mv88e61xxphy_probe(device_t); +static int mv88e61xxphy_attach(device_t); + +static void mv88e61xxphy_init(struct mv88e61xxphy_softc *); +static void mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *); +static void mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *); +static int mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS); +static int mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS); +static void mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *, uint16_t); +static void mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *, unsigned, enum mv88e61xxphy_vtu_membership_type); +static void mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *); + +static int +mv88e61xxphy_probe(device_t dev) +{ + uint16_t val; + + val = MIIBUS_READREG(device_get_parent(dev), MV88E61XX_PORT(0), + MV88E61XX_PORT_REVISION); + switch (val >> 4) { + case 0x121: + device_set_desc(dev, "Marvell Link Street 88E6123 3-Port Gigabit Switch"); + return (0); + case 0x161: + device_set_desc(dev, "Marvell Link Street 88E6161 6-Port Gigabit Switch"); + return (0); + case 0x165: + device_set_desc(dev, "Marvell Link Street 88E6161 6-Port Advanced Gigabit Switch"); + return (0); + default: + return (ENXIO); + } +} + +static int +mv88e61xxphy_attach(device_t dev) +{ + char portbuf[] = "N"; + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + struct sysctl_oid *port_node, *portN_node; + struct sysctl_oid_list *port_tree, *portN_tree; + struct mv88e61xxphy_softc *sc; + unsigned port; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + /* + * Initialize port softcs. + */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + psc->sc_switch = sc; + psc->sc_port = port; + psc->sc_domain = 0; /* One broadcast domain by default. */ + psc->sc_vlan = port + 1; /* Tag VLANs by default. */ + psc->sc_priority = 0; /* No default special priority. */ + psc->sc_flags = 0; + } + + /* + * Add per-port sysctl tree/handlers. + */ + port_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "port", + CTLFLAG_RD, NULL, "Switch Ports"); + port_tree = SYSCTL_CHILDREN(port_node); + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + + portbuf[0] = '0' + port; + portN_node = SYSCTL_ADD_NODE(ctx, port_tree, OID_AUTO, portbuf, + CTLFLAG_RD, NULL, "Switch Port"); + portN_tree = SYSCTL_CHILDREN(portN_node); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "duplex", + CTLFLAG_RD | CTLTYPE_INT, psc, + MV88E61XXPHY_LINK_SYSCTL_DUPLEX, + mv88e61xxphy_sysctl_link_proc, "IU", + "Media duplex status (0 = half duplex; 1 = full duplex)"); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "link", + CTLFLAG_RD | CTLTYPE_INT, psc, + MV88E61XXPHY_LINK_SYSCTL_LINK, + mv88e61xxphy_sysctl_link_proc, "IU", + "Link status (0 = down; 1 = up)"); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "media", + CTLFLAG_RD | CTLTYPE_INT, psc, + MV88E61XXPHY_LINK_SYSCTL_MEDIA, + mv88e61xxphy_sysctl_link_proc, "IU", + "Media speed (0 = unknown; 10 = 10Mbps; 100 = 100Mbps; 1000 = 1Gbps)"); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "domain", + CTLFLAG_RW | CTLTYPE_INT, psc, + MV88E61XXPHY_PORT_SYSCTL_DOMAIN, + mv88e61xxphy_sysctl_port_proc, "IU", + "Broadcast domain (ports can only talk to other ports in the same domain)"); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "vlan", + CTLFLAG_RW | CTLTYPE_INT, psc, + MV88E61XXPHY_PORT_SYSCTL_VLAN, + mv88e61xxphy_sysctl_port_proc, "IU", + "Tag packets from/for this port with a given VLAN."); + + SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "priority", + CTLFLAG_RW | CTLTYPE_INT, psc, + MV88E61XXPHY_PORT_SYSCTL_PRIORITY, + mv88e61xxphy_sysctl_port_proc, "IU", + "Default packet priority for this port."); + } + + mv88e61xxphy_init(sc); + + return (0); +} + +static void +mv88e61xxphy_init(struct mv88e61xxphy_softc *sc) +{ + unsigned port; + uint16_t val; + unsigned i; + + /* Disable all ports. */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + + val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL); + val &= ~0x3; + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val); + } + + DELAY(2000); + + /* Reset the switch. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0xc400); + for (i = 0; i < 100; i++) { + val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_STATUS); + if ((val & 0xc800) == 0xc800) + break; + DELAY(10); + } + if (i == 100) { + device_printf(sc->sc_dev, "%s: switch reset timed out.\n", __func__); + return; + } + + /* Disable PPU. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0x0000); + + /* Configure host port and send monitor frames to it. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_MONITOR, + (MV88E61XX_HOST_PORT << 12) | (MV88E61XX_HOST_PORT << 8) | + (MV88E61XX_HOST_PORT << 4)); + + /* Disable remote management. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_REMOTE_MGMT, 0x0000); + + /* Send all specifically-addressed frames to the host port. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_2X, 0xffff); + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_0X, 0xffff); + + /* Remove provider-supplied tag and use it for switching. */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_CONTROL2, + MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG); + + /* Configure all ports. */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + mv88e61xxphy_init_port(psc); + } + + /* Reprogram VLAN table (VTU.) */ + mv88e61xxphy_init_vtu(sc); + + /* Enable all ports. */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + + val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL); + val |= 0x3; + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val); + } +} + +static void +mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *psc) +{ + struct mv88e61xxphy_softc *sc; + unsigned allow_mask; + + sc = psc->sc_switch; + + /* Set media type and flow control. */ + if (psc->sc_port != MV88E61XX_HOST_PORT) { + /* Don't force any media type or flow control. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x0003); + } else { + /* Make CPU port 1G FDX. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x003e); + } + + /* Don't limit flow control pauses. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PAUSE_CONTROL, 0x0000); + + /* Set various port functions per Linux. */ + if (psc->sc_port != MV88E61XX_HOST_PORT) { + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x04bc); + } else { + /* + * Send frames for unknown unicast and multicast groups to + * host, too. + */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x063f); + } + + if (psc->sc_port != MV88E61XX_HOST_PORT) { + /* Disable trunking. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x0000); + } else { + /* Disable trunking and send learn messages to host. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x8000); + } + + /* + * Port-based VLAN map; isolates MAC tables and forces ports to talk + * only to the host. + * + * Always allow the host to send to all ports and allow all ports to + * send to the host. + */ + if (psc->sc_port != MV88E61XX_HOST_PORT) { + allow_mask = 1 << MV88E61XX_HOST_PORT; + } else { + allow_mask = (1 << MV88E61XX_PORTS) - 1; + allow_mask &= ~(1 << MV88E61XX_HOST_PORT); + } + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN_MAP, + (psc->sc_domain << 12) | allow_mask); + + /* VLAN tagging. Set default priority and VLAN tag (or none.) */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN, + (psc->sc_priority << 14) | psc->sc_vlan); + + if (psc->sc_port == MV88E61XX_HOST_PORT) { + /* Set provider ingress tag. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PROVIDER_PROTO, + ETHERTYPE_VLAN); + + /* Set provider egress tag. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_ETHER_PROTO, + ETHERTYPE_VLAN); + + /* Use secure 802.1q mode and accept only tagged frames. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER, + MV88E61XX_PORT_FILTER_MAP_DEST | + MV88E61XX_PORT_FILTER_8021Q_SECURE | + MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED); + } else { + /* Don't allow tagged frames. */ + MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER, + MV88E61XX_PORT_FILTER_MAP_DEST | + MV88E61XX_PORT_FILTER_DISCARD_TAGGED); + } +} + +static void +mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *sc) +{ + unsigned port; + + /* + * Start flush of the VTU. + */ + mv88e61xxphy_vtu_wait(sc); + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP, + MV88E61XX_GLOBAL_VTU_OP_BUSY | MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH); + + /* + * Queue each port's VLAN to be programmed. + */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; + if (psc->sc_vlan == 0) + continue; + psc->sc_flags |= MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; + } + + /* + * Program each VLAN that is in use. + */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + if ((psc->sc_flags & MV88E61XXPHY_PORT_FLAG_VTU_UPDATE) == 0) + continue; + mv88e61xxphy_vtu_load(sc, psc->sc_vlan); + } + + /* + * Wait for last pending VTU operation to complete. + */ + mv88e61xxphy_vtu_wait(sc); +} + +static int +mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS) +{ + struct mv88e61xxphy_port_softc *psc = arg1; + enum mv88e61xxphy_sysctl_link_type type = arg2; + uint16_t val; + unsigned out; + + val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_STATUS); + switch (type) { + case MV88E61XXPHY_LINK_SYSCTL_DUPLEX: + if ((val & MV88E61XX_PORT_STATUS_DUPLEX) != 0) + out = 1; + else + out = 0; + break; + case MV88E61XXPHY_LINK_SYSCTL_LINK: + if ((val & MV88E61XX_PORT_STATUS_LINK) != 0) + out = 1; + else + out = 0; + break; + case MV88E61XXPHY_LINK_SYSCTL_MEDIA: + switch (val & MV88E61XX_PORT_STATUS_MEDIA) { + case MV88E61XX_PORT_STATUS_MEDIA_10M: + out = 10; + break; + case MV88E61XX_PORT_STATUS_MEDIA_100M: + out = 100; + break; + case MV88E61XX_PORT_STATUS_MEDIA_1G: + out = 1000; + break; + default: + out = 0; + break; + } + break; + default: + return (EINVAL); + } + return (sysctl_handle_int(oidp, NULL, out, req)); +} + +static int +mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS) +{ + struct mv88e61xxphy_port_softc *psc = arg1; + enum mv88e61xxphy_sysctl_port_type type = arg2; + struct mv88e61xxphy_softc *sc = psc->sc_switch; + unsigned max, val, *valp; + int error; + + switch (type) { + case MV88E61XXPHY_PORT_SYSCTL_DOMAIN: + valp = &psc->sc_domain; + max = 0xf; + break; + case MV88E61XXPHY_PORT_SYSCTL_VLAN: + valp = &psc->sc_vlan; + max = 0x1000; + break; + case MV88E61XXPHY_PORT_SYSCTL_PRIORITY: + valp = &psc->sc_priority; + max = 3; + break; + default: + return (EINVAL); + } + + val = *valp; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + /* Bounds check value. */ + if (val >= max) + return (EINVAL); + + /* Reinitialize switch with new value. */ + *valp = val; + mv88e61xxphy_init(sc); + + return (0); +} + +static void +mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *sc, uint16_t vid) +{ + unsigned port; + + /* + * Wait for previous operation to complete. + */ + mv88e61xxphy_vtu_wait(sc); + + /* + * Set VID. + */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_VID, + MV88E61XX_GLOBAL_VTU_VID_VALID | vid); + + /* + * Add ports to this VTU. + */ + for (port = 0; port < MV88E61XX_PORTS; port++) { + struct mv88e61xxphy_port_softc *psc; + + psc = &sc->sc_ports[port]; + if (psc->sc_vlan == vid) { + /* + * Send this port its VLAN traffic untagged. + */ + psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; + mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_UNTAGGED); + } else if (psc->sc_port == MV88E61XX_HOST_PORT) { + /* + * The host sees all VLANs tagged. + */ + mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_TAGGED); + } else { + /* + * This port isn't on this VLAN. + */ + mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_DISCARDED); + } + } + + /* + * Start adding this entry. + */ + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP, + MV88E61XX_GLOBAL_VTU_OP_BUSY | + MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD); +} + +static void +mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *sc, unsigned port, + enum mv88e61xxphy_vtu_membership_type type) +{ + unsigned shift, reg; + uint16_t bits; + uint16_t val; + + switch (type) { + case MV88E61XXPHY_VTU_UNMODIFIED: + bits = 0; + break; + case MV88E61XXPHY_VTU_UNTAGGED: + bits = 1; + break; + case MV88E61XXPHY_VTU_TAGGED: + bits = 2; + break; + case MV88E61XXPHY_VTU_DISCARDED: + bits = 3; + break; + default: + return; + } + + if (port < 4) { + reg = MV88E61XX_GLOBAL_VTU_DATA_P0P3; + shift = port * 4; + } else { + reg = MV88E61XX_GLOBAL_VTU_DATA_P4P5; + shift = (port - 4) * 4; + } + + val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, reg); + val |= bits << shift; + MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, reg, val); +} + +static void +mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *sc) +{ + uint16_t val; + + for (;;) { + val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP); + if ((val & MV88E61XX_GLOBAL_VTU_OP_BUSY) == 0) + return; + } +} + +static device_method_t mv88e61xxphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, mv88e61xxphy_probe), + DEVMETHOD(device_attach, mv88e61xxphy_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + { 0, 0 } +}; + +static devclass_t mv88e61xxphy_devclass; + +static driver_t mv88e61xxphy_driver = { + "mv88e61xxphy", + mv88e61xxphy_methods, + sizeof(struct mv88e61xxphy_softc) +}; + +DRIVER_MODULE(mv88e61xxphy, octe, mv88e61xxphy_driver, mv88e61xxphy_devclass, 0, 0); diff --git a/sys/mips/cavium/octe/mv88e61xxphyreg.h b/sys/mips/cavium/octe/mv88e61xxphyreg.h new file mode 100644 index 00000000000..420741f2fe2 --- /dev/null +++ b/sys/mips/cavium/octe/mv88e61xxphyreg.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2010 Juli Mallett + * 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$ + */ + +/* + * Register definitions for Marvell MV88E61XX + * + * Note that names and definitions were gleaned from Linux and U-Boot patches + * released by Marvell, often by looking at contextual use of the registers + * involved, and may not be representative of the full functionality of those + * registers and are certainly not an exhaustive enumeration of registers. + * + * For an exhaustive enumeration of registers, check out the QD-DSDT package + * included in the Marvell ARM Feroceon Board Support Package for Linux. + */ + +#ifndef _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ +#define _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ + +/* + * Port addresses & per-port registers. + */ +#define MV88E61XX_PORT(x) (0x10 + (x)) +#define MV88E61XX_HOST_PORT (5) +#define MV88E61XX_PORTS (6) + +#define MV88E61XX_PORT_STATUS (0x00) +#define MV88E61XX_PORT_FORCE_MAC (0x01) +#define MV88E61XX_PORT_PAUSE_CONTROL (0x02) +#define MV88E61XX_PORT_REVISION (0x03) +#define MV88E61XX_PORT_CONTROL (0x04) +#define MV88E61XX_PORT_CONTROL2 (0x05) +#define MV88E61XX_PORT_VLAN_MAP (0x06) +#define MV88E61XX_PORT_VLAN (0x07) +#define MV88E61XX_PORT_FILTER (0x08) +#define MV88E61XX_PORT_EGRESS_CONTROL (0x09) +#define MV88E61XX_PORT_EGRESS_CONTROL2 (0x0a) +#define MV88E61XX_PORT_PORT_LEARN (0x0b) +#define MV88E61XX_PORT_ATU_CONTROL (0x0c) +#define MV88E61XX_PORT_PRIORITY_CONTROL (0x0d) +#define MV88E61XX_PORT_ETHER_PROTO (0x0f) +#define MV88E61XX_PORT_PROVIDER_PROTO (0x1a) +#define MV88E61XX_PORT_PRIORITY_MAP (0x18) +#define MV88E61XX_PORT_PRIORITY_MAP2 (0x19) + +/* + * Fields and values in each register. + */ +#define MV88E61XX_PORT_STATUS_MEDIA (0x0300) +#define MV88E61XX_PORT_STATUS_MEDIA_10M (0x0000) +#define MV88E61XX_PORT_STATUS_MEDIA_100M (0x0100) +#define MV88E61XX_PORT_STATUS_MEDIA_1G (0x0200) +#define MV88E61XX_PORT_STATUS_DUPLEX (0x0400) +#define MV88E61XX_PORT_STATUS_LINK (0x0800) +#define MV88E61XX_PORT_STATUS_FC (0x8000) + +#define MV88E61XX_PORT_CONTROL_DOUBLE_TAG (0x0200) + +#define MV88E61XX_PORT_FILTER_MAP_DEST (0x0080) +#define MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED (0x0100) +#define MV88E61XX_PORT_FILTER_DISCARD_TAGGED (0x0200) +#define MV88E61XX_PORT_FILTER_8021Q_MODE (0x0c00) +#define MV88E61XX_PORT_FILTER_8021Q_DISABLED (0x0000) +#define MV88E61XX_PORT_FILTER_8021Q_FALLBACK (0x0400) +#define MV88E61XX_PORT_FILTER_8021Q_CHECK (0x0800) +#define MV88E61XX_PORT_FILTER_8021Q_SECURE (0x0c00) + +/* + * Global address & global registers. + */ +#define MV88E61XX_GLOBAL (0x1b) + +#define MV88E61XX_GLOBAL_STATUS (0x00) +#define MV88E61XX_GLOBAL_CONTROL (0x04) +#define MV88E61XX_GLOBAL_VTU_OP (0x05) +#define MV88E61XX_GLOBAL_VTU_VID (0x06) +#define MV88E61XX_GLOBAL_VTU_DATA_P0P3 (0x07) +#define MV88E61XX_GLOBAL_VTU_DATA_P4P5 (0x08) +#define MV88E61XX_GLOBAL_ATU_CONTROL (0x0a) +#define MV88E61XX_GLOBAL_PRIORITY_MAP (0x18) +#define MV88E61XX_GLOBAL_MONITOR (0x1a) +#define MV88E61XX_GLOBAL_REMOTE_MGMT (0x1c) +#define MV88E61XX_GLOBAL_STATS (0x1d) + +/* + * Fields and values in each register. + */ +#define MV88E61XX_GLOBAL_VTU_OP_BUSY (0x8000) +#define MV88E61XX_GLOBAL_VTU_OP_OP (0x7000) +#define MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH (0x1000) +#define MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD (0x3000) + +#define MV88E61XX_GLOBAL_VTU_VID_VALID (0x1000) + +/* + * Second global address & second global registers. + */ +#define MV88E61XX_GLOBAL2 (0x1c) + +#define MV88E61XX_GLOBAL2_MANAGE_2X (0x02) +#define MV88E61XX_GLOBAL2_MANAGE_0X (0x03) +#define MV88E61XX_GLOBAL2_CONTROL2 (0x05) +#define MV88E61XX_GLOBAL2_TRUNK_MASK (0x07) +#define MV88E61XX_GLOBAL2_TRUNK_MAP (0x08) +#define MV88E61XX_GLOBAL2_RATELIMIT (0x09) +#define MV88E61XX_GLOBAL2_VLAN_CONTROL (0x0b) +#define MV88E61XX_GLOBAL2_MAC_ADDRESS (0x0d) + +/* + * Fields and values in each register. + */ +#define MV88E61XX_GLOBAL2_CONTROL2_DOUBLE_USE (0x8000) +#define MV88E61XX_GLOBAL2_CONTROL2_LOOP_PREVENT (0x4000) +#define MV88E61XX_GLOBAL2_CONTROL2_FLOW_MESSAGE (0x2000) +#define MV88E61XX_GLOBAL2_CONTROL2_FLOOD_BC (0x1000) +#define MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG (0x0800) +#define MV88E61XX_GLOBAL2_CONTROL2_AGE_INT (0x0400) +#define MV88E61XX_GLOBAL2_CONTROL2_FLOW_TAG (0x0200) +#define MV88E61XX_GLOBAL2_CONTROL2_ALWAYS_VTU (0x0100) +#define MV88E61XX_GLOBAL2_CONTROL2_FORCE_FC_PRI (0x0080) +#define MV88E61XX_GLOBAL2_CONTROL2_FC_PRI (0x0070) +#define MV88E61XX_GLOBAL2_CONTROL2_MGMT_TO_HOST (0x0008) +#define MV88E61XX_GLOBAL2_CONTROL2_MGMT_PRI (0x0007) + +#endif /* !_MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ */ diff --git a/sys/mips/cavium/octe/octe.c b/sys/mips/cavium/octe/octe.c index 312598d9a2c..daccb369eeb 100644 --- a/sys/mips/cavium/octe/octe.c +++ b/sys/mips/cavium/octe/octe.c @@ -146,6 +146,7 @@ octe_attach(device_t dev) { struct ifnet *ifp; cvm_oct_private_t *priv; + device_t child; unsigned qos; int error; @@ -155,10 +156,16 @@ octe_attach(device_t dev) if_initname(ifp, device_get_name(dev), device_get_unit(dev)); if (priv->phy_id != -1) { - error = mii_phy_probe(dev, &priv->miibus, octe_mii_medchange, - octe_mii_medstat); - if (error != 0) { - device_printf(dev, "missing phy %u\n", priv->phy_id); + if (priv->phy_device == NULL) { + error = mii_attach(dev, &priv->miibus, ifp, + octe_mii_medchange, octe_mii_medstat, + BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0); + if (error != 0) + device_printf(dev, "attaching PHYs failed\n"); + } else { + child = device_add_child(dev, priv->phy_device, -1); + if (child == NULL) + device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device); } } @@ -202,7 +209,7 @@ octe_attach(device_t dev) IFQ_SET_READY(&ifp->if_snd); OCTE_TX_UNLOCK(priv); - return (0); + return (bus_generic_attach(dev)); } static int @@ -224,9 +231,17 @@ octe_miibus_readreg(device_t dev, int phy, int reg) priv = device_get_softc(dev); - if (phy != priv->phy_id) - return (0); + /* + * Try interface-specific MII routine. + */ + if (priv->mdio_read != NULL) + return (priv->mdio_read(priv->ifp, phy, reg)); + /* + * Try generic MII routine. + */ + KASSERT(phy == priv->phy_id, + ("read from phy %u but our phy is %u", phy, priv->phy_id)); return (cvm_oct_mdio_read(priv->ifp, phy, reg)); } @@ -237,9 +252,19 @@ octe_miibus_writereg(device_t dev, int phy, int reg, int val) priv = device_get_softc(dev); + /* + * Try interface-specific MII routine. + */ + if (priv->mdio_write != NULL) { + priv->mdio_write(priv->ifp, phy, reg, val); + return (0); + } + + /* + * Try generic MII routine. + */ KASSERT(phy == priv->phy_id, ("write to phy %u but our phy is %u", phy, priv->phy_id)); - cvm_oct_mdio_write(priv->ifp, phy, reg, val); return (0); @@ -310,24 +335,6 @@ octe_start(struct ifnet *ifp) OCTE_TX_UNLOCK(priv); - /* - * XXX - * - * We may not be able to pass the mbuf up to BPF for one of - * two very good reasons: - * (1) immediately after our inserting it another CPU may be - * kind enough to free it for us. - * (2) m_collapse gets called on m and we don't get back the - * modified pointer. - * - * We have some options other than an m_dup route: - * (1) use a mutex or spinlock to prevent another CPU from - * freeing it. We could lock the tx_free_list's lock, - * that would make sense. - * (2) get back the new mbuf pointer. - * (3) do the collapse here. - */ - if (priv->queue != -1) { error = cvm_oct_xmit(m, ifp); } else { diff --git a/sys/mips/cavium/octeon_machdep.c b/sys/mips/cavium/octeon_machdep.c index 5321a78cb86..0a1480e5be9 100644 --- a/sys/mips/cavium/octeon_machdep.c +++ b/sys/mips/cavium/octeon_machdep.c @@ -286,6 +286,18 @@ octeon_memory_init(void) if (addr == -1) break; + /* + * The SDK needs to be able to easily map any memory that might + * come to it e.g. in the form of an mbuf. Because on !n64 we + * can't direct-map some addresses and we don't want to manage + * temporary mappings within the SDK, don't feed memory that + * can't be direct-mapped to the kernel. + */ +#if !defined(__mips_n64) + if (!MIPS_DIRECT_MAPPABLE(addr + (1 << 20) - 1)) + continue; +#endif + physmem += btoc(1 << 20); if (i > 0 && phys_avail[i - 1] == addr) { diff --git a/sys/mips/cavium/octeon_mp.c b/sys/mips/cavium/octeon_mp.c index a0eae2c095f..34de442eedb 100644 --- a/sys/mips/cavium/octeon_mp.c +++ b/sys/mips/cavium/octeon_mp.c @@ -96,7 +96,7 @@ platform_init_ap(int cpuid) */ clock_int_mask = hard_int_mask(5); ipi_int_mask = hard_int_mask(platform_ipi_intrnum()); - set_intr_mask(MIPS_SR_INT_MASK & ~(ipi_int_mask | clock_int_mask)); + set_intr_mask(ipi_int_mask | clock_int_mask); mips_wbflush(); } diff --git a/sys/mips/cavium/octopci.c b/sys/mips/cavium/octopci.c index 00907907779..b8a3ac0ccef 100644 --- a/sys/mips/cavium/octopci.c +++ b/sys/mips/cavium/octopci.c @@ -61,13 +61,19 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" +#define NPI_WRITE(addr, value) cvmx_write64_uint32((addr) ^ 4, (value)) +#define NPI_READ(addr) cvmx_read64_uint32((addr) ^ 4) + struct octopci_softc { device_t sc_dev; unsigned sc_domain; unsigned sc_bus; + unsigned sc_io_next; struct rman sc_io; + + unsigned sc_mem1_next; struct rman sc_mem1; }; @@ -86,6 +92,9 @@ static void octopci_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int octopci_route_interrupt(device_t, device_t, int); +static void octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *); +static unsigned octopci_init_device(device_t, unsigned, unsigned, unsigned, unsigned); +static unsigned octopci_init_bus(device_t, unsigned); static uint64_t octopci_cs_addr(unsigned, unsigned, unsigned, unsigned); static void @@ -108,13 +117,206 @@ static int octopci_attach(device_t dev) { struct octopci_softc *sc; + cvmx_npi_mem_access_subid_t npi_mem_access_subid; + cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg; + cvmx_npi_ctl_status_t npi_ctl_status; + cvmx_pci_ctl_status_2_t pci_ctl_status_2; + cvmx_pci_cfg56_t pci_cfg56; + cvmx_pci_cfg22_t pci_cfg22; + cvmx_pci_cfg16_t pci_cfg16; + cvmx_pci_cfg19_t pci_cfg19; + cvmx_pci_cfg01_t pci_cfg01; + unsigned subbus; + unsigned i; int error; /* - * XXX - * We currently rely on U-Boot to set up the PCI in host state. We - * should properly initialize the PCI bus here. + * Reset the PCI bus. */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1); + cvmx_read_csr(CVMX_CIU_SOFT_PRST); + + DELAY(2000); + + npi_ctl_status.u64 = 0; + npi_ctl_status.s.max_word = 1; + npi_ctl_status.s.timer = 1; + cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64); + + /* + * Set host mode. + */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR320: + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + /* 32-bit PCI-X */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0); + break; +#endif + default: + /* 64-bit PCI-X */ + cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); + break; + } + cvmx_read_csr(CVMX_CIU_SOFT_PRST); + + DELAY(2000); + + /* + * Enable BARs and configure big BAR mode. + */ + pci_ctl_status_2.u32 = 0; + pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */ + pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */ + pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */ + pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */ + pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */ + pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */ + pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */ + pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */ + pci_ctl_status_2.s.tsr_hwm = 1; + pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */ + pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */ + pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */ + + NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32); + + DELAY(2000); + + pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2); + + device_printf(dev, "%u-bit PCI%s bus.\n", + pci_ctl_status_2.s.ap_64ad ? 64 : 32, + pci_ctl_status_2.s.ap_pcix ? "-X" : ""); + + /* + * Set up transaction splitting, etc., parameters. + */ + pci_cfg19.u32 = 0; + pci_cfg19.s.mrbcm = 1; + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg19.s.mdrrmc = 0; + pci_cfg19.s.tdomc = 4; + } else { + pci_cfg19.s.mdrrmc = 2; + pci_cfg19.s.tdomc = 1; + } + NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32); + NPI_READ(CVMX_NPI_PCI_CFG19); + + /* + * Set up PCI error handling and memory access. + */ + pci_cfg01.u32 = 0; + pci_cfg01.s.fbbe = 1; + pci_cfg01.s.see = 1; + pci_cfg01.s.pee = 1; + pci_cfg01.s.me = 1; + pci_cfg01.s.msae = 1; + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg01.s.fbb = 0; + } else { + pci_cfg01.s.fbb = 1; + } + NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32); + NPI_READ(CVMX_NPI_PCI_CFG01); + + /* + * Enable the Octeon bus arbiter. + */ + npi_pci_int_arb_cfg.u64 = 0; + npi_pci_int_arb_cfg.s.en = 1; + cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64); + + /* + * Disable master latency timer. + */ + pci_cfg16.u32 = 0; + pci_cfg16.s.mltd = 1; + NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32); + NPI_READ(CVMX_NPI_PCI_CFG16); + + /* + * Configure master arbiter. + */ + pci_cfg22.u32 = 0; + pci_cfg22.s.flush = 1; + pci_cfg22.s.mrv = 255; + NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32); + NPI_READ(CVMX_NPI_PCI_CFG22); + + /* + * Set up PCI-X capabilities. + */ + if (pci_ctl_status_2.s.ap_pcix) { + pci_cfg56.u32 = 0; + pci_cfg56.s.most = 3; + pci_cfg56.s.roe = 1; /* Enable relaxed ordering */ + pci_cfg56.s.dpere = 1; + pci_cfg56.s.ncp = 0xe8; + pci_cfg56.s.pxcid = 7; + NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32); + NPI_READ(CVMX_NPI_PCI_CFG56); + } + + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22); + NPI_READ(CVMX_NPI_PCI_READ_CMD_6); + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33); + NPI_READ(CVMX_NPI_PCI_READ_CMD_C); + NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33); + NPI_READ(CVMX_NPI_PCI_READ_CMD_E); + + /* + * Configure MEM1 sub-DID access. + */ + npi_mem_access_subid.u64 = 0; + npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */ + npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + npi_mem_access_subid.s.shortl = 1; + break; +#endif + default: + break; + } + cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64); + + /* + * Configure BAR2. Linux says this has to come first. + */ + NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG08); + NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080); + NPI_READ(CVMX_NPI_PCI_CFG09); + + /* + * Disable BAR1 IndexX. + */ + for (i = 0; i < 32; i++) { + NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0); + NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i)); + } + + /* + * Configure BAR0 and BAR1. + */ + NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG04); + NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG05); + + NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000); + NPI_READ(CVMX_NPI_PCI_CFG06); + NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000); + NPI_READ(CVMX_NPI_PCI_CFG07); + + /* + * Clear PCI interrupts. + */ + cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull); sc = device_get_softc(dev); sc->sc_dev = dev; @@ -143,6 +345,19 @@ octopci_attach(device_t dev) if (error != 0) return (error); + /* + * Next offsets for resource allocation in octopci_init_bar. + */ + sc->sc_io_next = 0; + sc->sc_mem1_next = 0; + + /* + * Configure devices. + */ + octopci_write_config(dev, 0, 0, 0, PCIR_SUBBUS_1, 0xff, 1); + subbus = octopci_init_bus(dev, 0); + octopci_write_config(dev, 0, 0, 0, PCIR_SUBBUS_1, subbus, 1); + device_add_child(dev, "pci", 0); return (bus_generic_attach(dev)); @@ -208,14 +423,14 @@ octopci_alloc_resource(device_t bus, device_t child, int type, int *rid, break; case SYS_RES_IOPORT: rman_set_bushandle(res, CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO)) + rman_get_start(res)); +#if __mips_n64 + rman_set_virtual(res, (void *)rman_get_bushandle(res)); +#else /* * XXX - * We should just disallow use of io ports on !n64 since without - * 64-bit PTEs we can't even do a 32-bit virtual address - * mapped to them. + * We can't access ports via a 32-bit pointer. */ -#if 0 - rman_set_virtual(res, (void *)rman_get_bushandle(res)); + rman_set_virtual(res, NULL); #endif break; } @@ -335,21 +550,283 @@ octopci_route_interrupt(device_t dev, device_t child, int pin) slot = pci_get_slot(child); func = pci_get_function(child); -#if defined(OCTEON_VENDOR_LANNER) - if (slot < 32) { - if (slot == 3 || slot == 9) - irq = pin; - else - irq = pin - 1; - return (CVMX_IRQ_PCI_INT0 + (irq & 3)); - } + /* + * Board types we have to know at compile-time. + */ +#if defined(OCTEON_BOARD_CAPK_0100ND) + if (bus == 0 && slot == 12 && func == 0) + return (CVMX_IRQ_PCI_INT2); #endif + /* + * For board types we can determine at runtime. + */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + return (CVMX_IRQ_PCI_INT0 + pin - 1); + case CVMX_BOARD_TYPE_CUST_LANNER_MR320: + if (slot < 32) { + if (slot == 3 || slot == 9) + irq = pin; + else + irq = pin - 1; + return (CVMX_IRQ_PCI_INT0 + (irq & 3)); + } + break; +#endif + default: + break; + } + irq = slot + pin - 3; return (CVMX_IRQ_PCI_INT0 + (irq & 3)); } +static void +octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barnum, uint8_t *commandp) +{ + struct octopci_softc *sc; + uint32_t bar; + unsigned size; + + sc = device_get_softc(dev); + + octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 0xffffffff, 4); + bar = octopci_read_config(dev, b, s, f, PCIR_BAR(barnum), 4); + + if (bar == 0) { + /* Bar not implemented. */ + return; + } + + /* XXX Some of this is wrong for 64-bit busses. */ + + if (PCI_BAR_IO(bar)) { + size = ~(bar & PCIM_BAR_IO_BASE) + 1; + + sc->sc_io_next = (sc->sc_io_next + size - 1) & ~(size - 1); + if (sc->sc_io_next + size > CVMX_OCT_PCI_IO_SIZE) { + device_printf(dev, "%02x.%02x:%02x: no ports for BAR%u.\n", + b, s, f, barnum); + return; + } + octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), + CVMX_OCT_PCI_IO_BASE + sc->sc_io_next, 4); + sc->sc_io_next += size; + + /* + * Enable I/O ports. + */ + *commandp |= PCIM_CMD_PORTEN; + } else { + size = ~(bar & (uint32_t)PCIM_BAR_MEM_BASE) + 1; + + sc->sc_mem1_next = (sc->sc_mem1_next + size - 1) & ~(size - 1); + if (sc->sc_mem1_next + size > CVMX_OCT_PCI_MEM1_SIZE) { + device_printf(dev, "%02x.%02x:%02x: no memory for BAR%u.\n", + b, s, f, barnum); + return; + } + octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), + CVMX_OCT_PCI_MEM1_BASE + sc->sc_mem1_next, 4); + sc->sc_mem1_next += size; + + /* + * Enable memory access. + */ + *commandp |= PCIM_CMD_MEMEN; + } +} + +static unsigned +octopci_init_device(device_t dev, unsigned b, unsigned s, unsigned f, unsigned secbus) +{ + unsigned barnum, bars; + uint8_t brctl; + uint8_t class, subclass; + uint8_t command; + uint8_t hdrtype; + + /* Read header type (again.) */ + hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); + + /* + * Disable memory and I/O while programming BARs. + */ + command = octopci_read_config(dev, b, s, f, PCIR_COMMAND, 1); + command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); + octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); + + DELAY(10000); + + /* Program BARs. */ + switch (hdrtype & PCIM_HDRTYPE) { + case PCIM_HDRTYPE_NORMAL: + bars = 6; + break; + case PCIM_HDRTYPE_BRIDGE: + bars = 2; + break; + case PCIM_HDRTYPE_CARDBUS: + bars = 0; + break; + default: + device_printf(dev, "%02x.%02x:%02x: invalid header type %#x\n", + b, s, f, hdrtype); + return (secbus); + } + + for (barnum = 0; barnum < bars; barnum++) + octopci_init_bar(dev, b, s, f, barnum, &command); + + /* Enable bus mastering. */ + command |= PCIM_CMD_BUSMASTEREN; + + /* Enable whatever facilities the BARs require. */ + octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); + + DELAY(10000); + + /* + * Set cache line size. On Octeon it should be 128 bytes, + * but according to Linux some Intel bridges have trouble + * with values over 64 bytes, so use 64 bytes. + */ + octopci_write_config(dev, b, s, f, PCIR_CACHELNSZ, 16, 1); + + /* Set latency timer. */ + octopci_write_config(dev, b, s, f, PCIR_LATTIMER, 48, 1); + + /* Board-specific or device-specific fixups and workarounds. */ + switch (cvmx_sysinfo_get()->board_type) { +#if defined(OCTEON_VENDOR_LANNER) + case CVMX_BOARD_TYPE_CUST_LANNER_MR955: + if (b == 1 && s == 7 && f == 0) { + bus_addr_t busaddr, unitbusaddr; + uint32_t bar; + uint32_t tmp; + unsigned unit; + + /* + * Set Tx DMA power. + */ + bar = octopci_read_config(dev, b, s, f, + PCIR_BAR(3), 4); + busaddr = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, + CVMX_OCT_SUBDID_PCI_MEM1)); + busaddr += (bar & (uint32_t)PCIM_BAR_MEM_BASE); + for (unit = 0; unit < 4; unit++) { + unitbusaddr = busaddr + 0x430 + (unit << 8); + tmp = le32toh(cvmx_read64_uint32(unitbusaddr)); + tmp &= ~0x700; + tmp |= 0x300; + cvmx_write64_uint32(unitbusaddr, htole32(tmp)); + } + } + break; +#endif + default: + break; + } + + /* Configure PCI-PCI bridges. */ + class = octopci_read_config(dev, b, s, f, PCIR_CLASS, 1); + if (class != PCIC_BRIDGE) + return (secbus); + + subclass = octopci_read_config(dev, b, s, f, PCIR_SUBCLASS, 1); + if (subclass != PCIS_BRIDGE_PCI) + return (secbus); + + /* Enable memory and I/O access. */ + command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; + octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); + + /* Enable errors and parity checking. Do a bus reset. */ + brctl = octopci_read_config(dev, b, s, f, PCIR_BRIDGECTL_1, 1); + brctl |= PCIB_BCR_PERR_ENABLE | PCIB_BCR_SERR_ENABLE; + + /* Perform a secondary bus reset. */ + brctl |= PCIB_BCR_SECBUS_RESET; + octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); + DELAY(100000); + brctl &= ~PCIB_BCR_SECBUS_RESET; + octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); + + secbus++; + + /* Program memory and I/O ranges. */ + octopci_write_config(dev, b, s, f, PCIR_MEMBASE_1, + CVMX_OCT_PCI_MEM1_BASE >> 16, 2); + octopci_write_config(dev, b, s, f, PCIR_MEMLIMIT_1, + (CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE - 1) >> 16, 2); + + octopci_write_config(dev, b, s, f, PCIR_IOBASEL_1, + CVMX_OCT_PCI_IO_BASE >> 8, 1); + octopci_write_config(dev, b, s, f, PCIR_IOBASEH_1, + CVMX_OCT_PCI_IO_BASE >> 16, 2); + + octopci_write_config(dev, b, s, f, PCIR_IOLIMITL_1, + (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 8, 1); + octopci_write_config(dev, b, s, f, PCIR_IOLIMITH_1, + (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 16, 2); + + /* Program prefetchable memory decoder. */ + /* XXX */ + + /* Probe secondary/subordinate buses. */ + octopci_write_config(dev, b, s, f, PCIR_PRIBUS_1, b, 1); + octopci_write_config(dev, b, s, f, PCIR_SECBUS_1, secbus, 1); + octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, 0xff, 1); + + /* Perform a secondary bus reset. */ + brctl |= PCIB_BCR_SECBUS_RESET; + octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); + DELAY(100000); + brctl &= ~PCIB_BCR_SECBUS_RESET; + octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); + + /* Give the bus time to settle now before reading configspace. */ + DELAY(100000); + + secbus = octopci_init_bus(dev, secbus); + + octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, secbus, 1); + + return (secbus); +} + +static unsigned +octopci_init_bus(device_t dev, unsigned b) +{ + unsigned s, f; + uint8_t hdrtype; + unsigned secbus; + + secbus = b; + + for (s = 0; s <= PCI_SLOTMAX; s++) { + for (f = 0; f <= PCI_FUNCMAX; f++) { + hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); + + if (hdrtype == 0xff) { + if (f == 0) + break; /* Next slot. */ + continue; /* Next function. */ + } + + secbus = octopci_init_device(dev, b, s, f, secbus); + + if (f == 0 && (hdrtype & PCIM_MFDEV) == 0) + break; /* Next slot. */ + } + } + + return (secbus); +} + static uint64_t octopci_cs_addr(unsigned bus, unsigned slot, unsigned func, unsigned reg) { @@ -383,6 +860,9 @@ static device_method_t octopci_methods[] = { DEVMETHOD(bus_activate_resource,octopci_activate_resource), DEVMETHOD(bus_deactivate_resource,bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + DEVMETHOD(bus_add_child, bus_generic_add_child), /* pcib interface */ DEVMETHOD(pcib_maxslots, octopci_maxslots), diff --git a/sys/mips/cavium/octopcireg.h b/sys/mips/cavium/octopcireg.h index 23abf1c3b64..2250309b87a 100644 --- a/sys/mips/cavium/octopcireg.h +++ b/sys/mips/cavium/octopcireg.h @@ -96,10 +96,10 @@ typedef union #define CVMX_OCT_SUBDID_PCI_MEM3 5 #define CVMX_OCT_SUBDID_PCI_MEM4 6 -#define CVMX_OCT_PCI_IO_BASE 0x00001000 +#define CVMX_OCT_PCI_IO_BASE 0x00004000 #define CVMX_OCT_PCI_IO_SIZE 0x08000000 -#define CVMX_OCT_PCI_MEM1_BASE 0x80000000 -#define CVMX_OCT_PCI_MEM1_SIZE 0x40000000 +#define CVMX_OCT_PCI_MEM1_BASE 0xf0000000 +#define CVMX_OCT_PCI_MEM1_SIZE 0x0f000000 #endif /* !_CAVIUM_OCTOPCIREG_H_ */ diff --git a/sys/mips/cavium/std.octeon1 b/sys/mips/cavium/std.octeon1 index 3a1f3ed5762..7b3152f361b 100644 --- a/sys/mips/cavium/std.octeon1 +++ b/sys/mips/cavium/std.octeon1 @@ -5,15 +5,3 @@ # $FreeBSD$ # files "../cavium/files.octeon1" - -# -# -# -cpu CPU_MIPS4KC -#device pci -#device ata -#device atadisk - -#device clock -#device obio -#device uart diff --git a/sys/mips/cavium/uart_bus_octeonusart.c b/sys/mips/cavium/uart_bus_octeonusart.c index c845ae70115..f6855a7c098 100644 --- a/sys/mips/cavium/uart_bus_octeonusart.c +++ b/sys/mips/cavium/uart_bus_octeonusart.c @@ -105,11 +105,10 @@ uart_octeon_probe(device_t dev) sc->sc_bas.bst = uart_bus_space_mem; /* * XXX - * RBR isn't really a great base address and it'd be great to not have - * a hard-coded 1024. + * RBR isn't really a great base address. */ - if (bus_space_map(sc->sc_bas.bst, CVMX_MIO_UARTX_RBR(0), 1024, - 0, &sc->sc_bas.bsh) != 0) + if (bus_space_map(sc->sc_bas.bst, CVMX_MIO_UARTX_RBR(0), + uart_getrange(sc->sc_class), 0, &sc->sc_bas.bsh) != 0) return (ENXIO); return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, unit)); } diff --git a/sys/mips/cavium/uart_cpu_octeonusart.c b/sys/mips/cavium/uart_cpu_octeonusart.c index c03708e071a..e5d0e4410ce 100644 --- a/sys/mips/cavium/uart_cpu_octeonusart.c +++ b/sys/mips/cavium/uart_cpu_octeonusart.c @@ -58,56 +58,56 @@ static uint8_t ou_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset) { - return (oct_read64(handle + (offset << 3))); + return (oct_read64(handle + offset)); } static uint16_t ou_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { - return (oct_read64(handle + (offset << 3))); + return (oct_read64(handle + offset)); } static uint32_t ou_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { - return (oct_read64(handle + (offset << 3))); + return (oct_read64(handle + offset)); } static uint64_t ou_bs_r_8(void *t, bus_space_handle_t handle, bus_size_t offset) { - return (oct_read64(handle + (offset << 3))); + return (oct_read64(handle + offset)); } static void ou_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value) { - oct_write64(bsh + (offset << 3), value); + oct_write64(bsh + offset, value); } static void ou_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { - oct_write64(bsh + (offset << 3), value); + oct_write64(bsh + offset, value); } static void ou_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { - oct_write64(bsh + (offset << 3), value); + oct_write64(bsh + offset, value); } static void ou_bs_w_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value) { - oct_write64(bsh + (offset << 3), value); + oct_write64(bsh + offset, value); } struct bus_space octeon_uart_tag = { @@ -160,10 +160,10 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) di->ops = uart_getops(class); di->bas.chan = 0; /* XXX */ - if (bus_space_map(di->bas.bst, CVMX_MIO_UARTX_RBR(0), 1024, - 0, &di->bas.bsh) != 0) + if (bus_space_map(di->bas.bst, CVMX_MIO_UARTX_RBR(0), + uart_getrange(class), 0, &di->bas.bsh) != 0) return (ENXIO); - di->bas.regshft = 0; + di->bas.regshft = 3; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; diff --git a/sys/mips/cavium/uart_dev_oct16550.c b/sys/mips/cavium/uart_dev_oct16550.c index b9bfe294708..a7a54b3eae6 100644 --- a/sys/mips/cavium/uart_dev_oct16550.c +++ b/sys/mips/cavium/uart_dev_oct16550.c @@ -420,7 +420,7 @@ struct uart_class uart_oct16550_class = { oct16550_methods, sizeof(struct oct16550_softc), .uc_ops = &uart_oct16550_ops, - .uc_range = 8, + .uc_range = 8 << 3, .uc_rclk = 0 }; diff --git a/sys/mips/cavium/usb/octusb.c b/sys/mips/cavium/usb/octusb.c index d090f120f77..598a304d8f3 100644 --- a/sys/mips/cavium/usb/octusb.c +++ b/sys/mips/cavium/usb/octusb.c @@ -1885,7 +1885,7 @@ octusb_xfer_unsetup(struct usb_xfer *xfer) } static void -octusb_get_dma_delay(struct usb_bus *bus, uint32_t *pus) +octusb_get_dma_delay(struct usb_device *udev, uint32_t *pus) { /* DMA delay - wait until any use of memory is finished */ *pus = (2125); /* microseconds */ diff --git a/sys/mips/conf/AR71XX b/sys/mips/conf/AR71XX index 12c73daa5b8..bec8120fed3 100644 --- a/sys/mips/conf/AR71XX +++ b/sys/mips/conf/AR71XX @@ -74,6 +74,9 @@ options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order device ohci device ehci +device gpio +device gpioled + device spibus device ar71xx_spi device mx25l diff --git a/sys/mips/conf/AR71XX.hints b/sys/mips/conf/AR71XX.hints index c68d6bc8efc..6719d163918 100644 --- a/sys/mips/conf/AR71XX.hints +++ b/sys/mips/conf/AR71XX.hints @@ -47,6 +47,18 @@ hint.arge.1.fduplex=1 # Uncomment this hint for RS (not PRO) # hint.arge.0.phymask=70000 +# GPIO +hint.gpio.0.at="apb0" +hint.gpio.0.maddr=0x18040000 +hint.gpio.0.msize=0x1000 +hint.gpio.0.irq=2 + +# RF led +hint.gpioled.0.at="gpiobus0" +hint.gpioled.0.name="rf" +# pin 2 +hint.gpioled.0.pins=0x0004 + # SPI flash hint.spi.0.at="nexus0" hint.spi.0.maddr=0x1f000000 diff --git a/sys/mips/conf/MALTA64 b/sys/mips/conf/MALTA64 index e7f01c7093b..65b1e986779 100644 --- a/sys/mips/conf/MALTA64 +++ b/sys/mips/conf/MALTA64 @@ -21,7 +21,6 @@ ident MALTA makeoptions ARCH_FLAGS="-march=mips64 -mabi=64" makeoptions MIPS_LITTLE_ENDIAN=defined -makeoptions TARGET_64BIT=t makeoptions LDSCRIPT_NAME= ldscript.mips.mips64 options YAMON diff --git a/sys/mips/conf/OCTEON1 b/sys/mips/conf/OCTEON1 index 3c8b3f2b7f7..a00e95daf88 100644 --- a/sys/mips/conf/OCTEON1 +++ b/sys/mips/conf/OCTEON1 @@ -1,7 +1,8 @@ -# OCTEON1 -- Configuration kernel for all Octeon1 SoCs from Cavium Networks # -# For more information on this file, please read the handbook section on -# Kernel Configuration Files: +# OCTEON1 -- Generic kernel configuration file for FreeBSD/MIPS on Cavium Octeon +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # @@ -11,19 +12,12 @@ # latest information. # # An exhaustive list of options and more detailed explanations of the -# device lines is also present in the ../../conf/NOTES and NOTES files. -# If you are in doubt as to the purpose or necessity of a line, check first +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ -############################################################################## -### ### -### PLEASE NOTE: This file is the experimental 64-bit kernel. If you want ### -### a stable kernel, please use the 32-bit OCTEON1-32 instead. ### -### ### -############################################################################## - machine mips cpu CPU_CNMIPS ident OCTEON1 @@ -34,7 +28,6 @@ makeoptions LDSCRIPT_NAME=ldscript.mips.octeon1.64 # Don't build any modules yet. makeoptions MODULES_OVERRIDE="" makeoptions TARGET_BIG_ENDIAN=defined -makeoptions TARGET_64BIT=defined makeoptions KERNLOADADDR=0xffffffff80100000 include "../cavium/std.octeon1" @@ -43,61 +36,265 @@ hints "OCTEON1.hints" #Default places to look for devices. makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -#XXXimp: Need to make work with 64-bit too -options ISA_MIPS64 - -options DDB -options KDB - -options SCHED_4BSD #4BSD scheduler -options INET #InterNETworking -options NFSCLIENT #Network Filesystem Client -#options NFS_ROOT #NFS usable as /, requires NFSCLIENT -options PSEUDOFS #Pseudo-filesystem framework -options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions -#options ROOTDEVNAME=\"ufs:ad0s1a\" # Original -options NO_SWAPPING - - -options FFS #Berkeley Fast Filesystem -options SOFTUPDATES #Enable FFS soft updates support -options UFS_ACL #Support for access control lists -options UFS_DIRHASH #Improve performance on big directories - - -# Debugging for use in -current -#options DEADLKRES #Enable the deadlock resolver -options INVARIANTS #Enable calls of extra sanity checking -options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS -#options WITNESS #Enable checks to detect deadlocks and cycles -#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed - -options SMP - # Board-specific support that cannot be auto-detected at runtime. #options OCTEON_VENDOR_LANNER # Support for Lanner boards. #options OCTEON_BOARD_CAPK_0100ND # Support for CAPK-0100nd. -device loop -device ether -device md -device uart -nodevice uart_ns8250 -device miibus -device octe -#options VERBOSE_SYSINIT +# XXX This option is very nearly irrelevant. +options ISA_MIPS64 -device bpf -device random +options SCHED_ULE # ULE scheduler +options PREEMPTION # Enable kernel thread preemption +options INET # InterNETworking +options INET6 # IPv6 communications protocols +options SCTP # Stream Control Transmission Protocol +options FFS # Berkeley Fast Filesystem +options SOFTUPDATES # Enable FFS soft updates support +options UFS_ACL # Support for access control lists +options UFS_DIRHASH # Improve performance on big directories +options UFS_GJOURNAL # Enable gjournal-based UFS journaling +options MD_ROOT # MD is a potential root device +options NFSCLIENT # Network Filesystem Client +options NFSSERVER # Network Filesystem Server +options NFSLOCKD # Network Lock Manager +options NFS_ROOT # NFS usable as /, requires NFSCLIENT +options MSDOSFS # MSDOS Filesystem +options CD9660 # ISO 9660 Filesystem +options PROCFS # Process filesystem (requires PSEUDOFS) +options PSEUDOFS # Pseudo-filesystem framework +options GEOM_PART_GPT # GUID Partition Tables. +options GEOM_LABEL # Provides labelization +#options COMPAT_FREEBSD32 # Compatible with o32 binaries (not yet) +options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI +options KTRACE # ktrace(1) support +options STACK # stack(9) support +options SYSVSHM # SYSV-style shared memory +options SYSVMSG # SYSV-style message queues +options SYSVSEM # SYSV-style semaphores +options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions +options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. +options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) +options AUDIT # Security event auditing +options MAC # TrustedBSD MAC Framework +options FLOWTABLE # per-cpu routing cache +#options KDTRACE_FRAME # Ensure frames are compiled in +#options KDTRACE_HOOKS # Kernel DTrace hooks +options INCLUDE_CONFIG_FILE # Include this file in kernel +options NO_SWAPPING # Disable support for paging -# -# Use the following for Compact Flash file-system -device cf -options ROOTDEVNAME=\"ufs:cf0s2a\" # Unmask if compact flash is needed as RFS +# Debugging for use in -current +options KDB # Enable kernel debugger support. +options DDB # Support DDB. +options GDB # Support remote GDB. +options DEADLKRES # Enable the deadlock resolver +options INVARIANTS # Enable calls of extra sanity checking +options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS +options WITNESS # Enable checks to detect deadlocks and cycles +options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed +options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones -# -# Use the following for RFS in mem-device -#options MD_ROOT -#options ROOTDEVNAME=\"ufs:md0\" +# Make an SMP-capable kernel by default +options SMP # Symmetric MultiProcessor Kernel -#options MD_ROOT_SIZE=21264 +# Bus support. +device pci + +# ATA and ATAPI devices +device ata +device atadisk # ATA disk drives +device ataraid # ATA RAID drives +device atapicd # ATAPI CDROM drives +device atapifd # ATAPI floppy drives +device atapist # ATAPI tape drives +options ATA_STATIC_ID # Static device numbering + +# On-board Compact Flash driver. +device cf +options ROOTDEVNAME=\"ufs:cf0s2a\" # Default root filesystem. + +# SCSI Controllers +device ahc # AHA2940 and onboard AIC7xxx devices +options AHC_REG_PRETTY_PRINT # Print register bitfields in debug + # output. Adds ~128k to driver. +device ahd # AHA39320/29320 and onboard AIC79xx devices +options AHD_REG_PRETTY_PRINT # Print register bitfields in debug + # output. Adds ~215k to driver. +device amd # AMD 53C974 (Tekram DC-390(T)) +device hptiop # Highpoint RocketRaid 3xxx series +device isp # Qlogic family +#device ispfw # Firmware for QLogic HBAs- normally a module +device mpt # LSI-Logic MPT-Fusion +device mps # LSI-Logic MPT-Fusion 2 +#device ncr # NCR/Symbios Logic +device trm # Tekram DC395U/UW/F DC315U adapters + +device adv # Advansys SCSI adapters +device adw # Advansys wide SCSI adapters +device aic # Adaptec 15[012]x SCSI adapters, AIC-6[23]60. +device bt # Buslogic/Mylex MultiMaster SCSI adapters + +# SCSI peripherals +device scbus # SCSI bus (required for SCSI) +device ch # SCSI media changers +device da # Direct Access (disks) +device sa # Sequential Access (tape etc) +device cd # CD +device pass # Passthrough device (direct SCSI access) +device ses # SCSI Environmental Services (and SAF-TE) + +# RAID controllers interfaced to the SCSI subsystem +device amr # AMI MegaRAID +#XXX it is not 64-bit clean, -scottl +#device asr # DPT SmartRAID V, VI and Adaptec SCSI RAID +device ciss # Compaq Smart RAID 5* +device dpt # DPT Smartcache III, IV - See NOTES for options +device iir # Intel Integrated RAID +device ips # IBM (Adaptec) ServeRAID +device mly # Mylex AcceleRAID/eXtremeRAID + +# RAID controllers +device aac # Adaptec FSA RAID +device aacp # SCSI passthrough for aac (requires CAM) +device ida # Compaq Smart RAID +device mfi # LSI MegaRAID SAS +device mlx # Mylex DAC960 family +#XXX pointer/int warnings +#device pst # Promise Supertrak SX6000 +device twe # 3ware ATA RAID + +# PCCARD (PCMCIA) support +# PCMCIA and cardbus bridge support +device cbb # cardbus (yenta) bridge +device pccard # PC Card (16-bit) bus +device cardbus # CardBus (32-bit) bus + +# Serial (COM) ports +device uart # Generic UART driver + +# If you've got a "dumb" serial or parallel PCI card that is +# supported by the puc(4) glue driver, uncomment the following +# line to enable it (connects to sio, uart and/or ppc drivers): +#device puc + +# On-board Cavium Octeon Ethernet. +# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! +device octe + +# Switch PHY support for the octe driver. These currently present a VLAN per +# physical port, but may eventually provide support for DSA or similar instead. +#device mv88e61xxphy # Marvell 88E61XX + +# PCI Ethernet NICs. +device de # DEC/Intel DC21x4x (``Tulip'') +device em # Intel PRO/1000 Gigabit Ethernet Family +device igb # Intel PRO/1000 PCIE Server Gigabit Family +device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device le # AMD Am7900 LANCE and Am79C9xx PCnet +device ti # Alteon Networks Tigon I/II gigabit Ethernet +device txp # 3Com 3cR990 (``Typhoon'') +device vx # 3Com 3c590, 3c595 (``Vortex'') + +# PCI Ethernet NICs that use the common MII bus controller code. +# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! +device miibus # MII bus support +device ae # Attansic/Atheros L2 FastEthernet +device age # Attansic/Atheros L1 Gigabit Ethernet +device alc # Atheros AR8131/AR8132 Ethernet +device ale # Atheros AR8121/AR8113/AR8114 Ethernet +device bce # Broadcom BCM5706/BCM5708 Gigabit Ethernet +device bfe # Broadcom BCM440x 10/100 Ethernet +device bge # Broadcom BCM570xx Gigabit Ethernet +device dc # DEC/Intel 21143 and various workalikes +device et # Agere ET1310 10/100/Gigabit Ethernet +device fxp # Intel EtherExpress PRO/100B (82557, 82558) +device jme # JMicron JMC250 Gigabit/JMC260 Fast Ethernet +device lge # Level 1 LXT1001 gigabit Ethernet +device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet +device nge # NatSemi DP83820 gigabit Ethernet +#device nve # nVidia nForce MCP on-board Ethernet Networking +device pcn # AMD Am79C97x PCI 10/100 (precedence over 'le') +device re # RealTek 8139C+/8169/8169S/8110S +device rl # RealTek 8129/8139 +device sf # Adaptec AIC-6915 (``Starfire'') +device sge # Silicon Integrated Systems SiS190/191 +device sis # Silicon Integrated Systems SiS 900/SiS 7016 +device sk # SysKonnect SK-984x & SK-982x gigabit Ethernet +device ste # Sundance ST201 (D-Link DFE-550TX) +device stge # Sundance/Tamarack TC9021 gigabit Ethernet +device tl # Texas Instruments ThunderLAN +device tx # SMC EtherPower II (83c170 ``EPIC'') +device vge # VIA VT612x gigabit Ethernet +device vr # VIA Rhine, Rhine II +device wb # Winbond W89C840F +device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') + +# Wireless NIC cards +device wlan # 802.11 support +options IEEE80211_DEBUG # enable debug msgs +options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's +options IEEE80211_SUPPORT_MESH # enable 802.11s draft support +device wlan_wep # 802.11 WEP support +device wlan_ccmp # 802.11 CCMP support +device wlan_tkip # 802.11 TKIP support +device wlan_amrr # AMRR transmit rate control algorithm +device an # Aironet 4500/4800 802.11 wireless NICs. +device ath # Atheros pci/cardbus NIC's +device ath_hal # pci/cardbus chip support +options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors +device ath_rate_sample # SampleRate tx rate control for ath +device ral # Ralink Technology RT2500 wireless NICs. +device wi # WaveLAN/Intersil/Symbol 802.11 wireless NICs. + +# Pseudo devices. +device loop # Network loopback +device random # Entropy device +device ether # Ethernet support +device vlan # 802.1Q VLAN support +device tun # Packet tunnel. +device pty # BSD-style compatibility pseudo ttys +device md # Memory "disks" +device gif # IPv6 and IPv4 tunneling +device faith # IPv6-to-IPv4 relaying (translation) +device firmware # firmware assist module + +# The `bpf' device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +# Note that 'bpf' is required for DHCP. +device bpf # Berkeley packet filter + +# USB support +options USB_DEBUG # enable debug msgs +device octusb # Cavium Octeon on-board USB interface (USB 2.0) +device uhci # UHCI PCI->USB interface +device ohci # OHCI PCI->USB interface +device ehci # EHCI PCI->USB interface (USB 2.0) +device usb # USB Bus (required) +#device udbp # USB Double Bulk Pipe devices +device uhid # "Human Interface Devices" +device ulpt # Printer +device umass # Disks/Mass storage - Requires scbus and da +device ums # Mouse +device urio # Diamond Rio 500 MP3 player +# USB Serial devices +device u3g # USB-based 3G modems (Option, Huawei, Sierra) +device uark # Technologies ARK3116 based serial adapters +device ubsa # Belkin F5U103 and compatible serial adapters +device uftdi # For FTDI usb serial adapters +device uipaq # Some WinCE based devices +device uplcom # Prolific PL-2303 serial adapters +device uslcom # SI Labs CP2101/CP2102 serial adapters +device uvisor # Visor and Palm devices +device uvscom # USB serial support for DDI pocket's PHS +# USB Ethernet, requires miibus +device aue # ADMtek USB Ethernet +device axe # ASIX Electronics USB Ethernet +device cdce # Generic USB over Ethernet +device cue # CATC USB Ethernet +device kue # Kawasaki LSI USB Ethernet +device rue # RealTek RTL8150 USB Ethernet +device udav # Davicom DM9601E USB +# USB Wireless +device rum # Ralink Technology RT2501USB wireless NICs +device uath # Atheros AR5523 wireless NICs +device ural # Ralink Technology RT2500USB wireless NICs +device zyd # ZyDAS zb1211/zb1211b wireless NICs diff --git a/sys/mips/conf/SWARM b/sys/mips/conf/SWARM index 041c94da983..d4950cb1776 100644 --- a/sys/mips/conf/SWARM +++ b/sys/mips/conf/SWARM @@ -2,69 +2,11 @@ # $FreeBSD$ # +include SWARM_COMMON + ident SWARM -options CPU_SB1 -files "../sibyte/files.sibyte" -hints "SWARM.hints" - -options CFE -options CFE_CONSOLE -options CFE_ENV -options ALT_BREAK_TO_DEBUGGER +options ISA_MIPS32 +makeoptions ARCH_FLAGS="-mabi=32 -march=mips32" makeoptions LDSCRIPT_NAME= ldscript.mips.cfe - -#cpu CPU_MIPS64 -#options ISA_MIPS64 -#makeoptions ARCH_FLAGS="-march=mips64 -mgp64 -mabi=o64" -cpu CPU_MIPS32 -options ISA_MIPS32 -makeoptions ARCH_FLAGS="-march=mips32" - -makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="" - -options DDB -options KDB - -options SCHED_4BSD #4BSD scheduler -options INET #InterNETworking -options NFSCLIENT #Network Filesystem Client -options NFS_ROOT #NFS usable as /, requires NFSCLIENT -options PSEUDOFS #Pseudo-filesystem framework -options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions - -# Debugging for use in -current -#options DEADLKRES -options INVARIANTS -options INVARIANT_SUPPORT -options WITNESS - -options FFS #Fast filesystem - -options KTRACE - -device pci -device miibus -device bge -device loop -device ether -device md -device random - -options USB_DEBUG -device usb -device ohci -device uhci -device ehci - -device umass - -device scbus -device da - -device ata -device atadisk -device atapicd -options ATA_STATIC_ID diff --git a/sys/mips/conf/SWARM64 b/sys/mips/conf/SWARM64 new file mode 100644 index 00000000000..72931b5acc7 --- /dev/null +++ b/sys/mips/conf/SWARM64 @@ -0,0 +1,20 @@ +# +# $FreeBSD$ +# + +include SWARM_COMMON + +ident SWARM64 + +makeoptions ARCH_FLAGS="-mabi=64 -march=mips64" +makeoptions LDSCRIPT_NAME=ldscript.mips.64.cfe +makeoptions KERNLOADADDR=0xffffffff80001000 + +# +# XXX restrict memory to maximum 4GB because page table entries in pmap +# are still 32 bits wide + +# +# MAXMEM is specified in units of KB +# +options MAXMEM=0x400000 diff --git a/sys/mips/conf/SWARM64_SMP b/sys/mips/conf/SWARM64_SMP new file mode 100644 index 00000000000..863c0f0f3ab --- /dev/null +++ b/sys/mips/conf/SWARM64_SMP @@ -0,0 +1,23 @@ +# +# $FreeBSD$ +# + +include SWARM_COMMON + +ident SWARM64_SMP + +options SMP +options PRINTF_BUFR_SIZE=128 + +makeoptions ARCH_FLAGS="-mabi=64 -march=mips64" +makeoptions LDSCRIPT_NAME=ldscript.mips.64.cfe +makeoptions KERNLOADADDR=0xffffffff80001000 + +# +# XXX restrict memory to maximum 4GB because page table entries in pmap +# are still 32 bits wide + +# +# MAXMEM is specified in units of KB +# +options MAXMEM=0x400000 diff --git a/sys/mips/conf/SWARM_COMMON b/sys/mips/conf/SWARM_COMMON new file mode 100644 index 00000000000..1d22e3cea18 --- /dev/null +++ b/sys/mips/conf/SWARM_COMMON @@ -0,0 +1,60 @@ +# +# $FreeBSD$ +# + +files "../sibyte/files.sibyte" +hints "SWARM.hints" + +options CFE +options CFE_CONSOLE +options CFE_ENV +options ALT_BREAK_TO_DEBUGGER + +cpu CPU_SB1 + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +makeoptions MODULES_OVERRIDE="" + +options DDB +options KDB + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options NFSCLIENT #Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options PSEUDOFS #Pseudo-filesystem framework +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions + +# Debugging for use in -current +#options DEADLKRES +options INVARIANTS +options INVARIANT_SUPPORT +options WITNESS + +options FFS #Fast filesystem + +options KTRACE + +device pci +device miibus +device bge +device loop +device ether +device md +device random + +options USB_DEBUG +device usb +device ohci +device uhci +device ehci + +device umass + +device scbus +device da + +device ata +device atadisk +device atapicd +options ATA_STATIC_ID diff --git a/sys/mips/conf/SWARM_SMP b/sys/mips/conf/SWARM_SMP index ec76ce4ac17..534d0856d75 100644 --- a/sys/mips/conf/SWARM_SMP +++ b/sys/mips/conf/SWARM_SMP @@ -1,7 +1,15 @@ # # $FreeBSD$ # + +include SWARM_COMMON + +ident SWARM_SMP + options SMP options PRINTF_BUFR_SIZE=128 -include SWARM +options ISA_MIPS32 + +makeoptions ARCH_FLAGS="-mabi=32 -march=mips32" +makeoptions LDSCRIPT_NAME= ldscript.mips.cfe diff --git a/sys/mips/idt/if_kr.c b/sys/mips/idt/if_kr.c index bbc800fd3e1..edba95057d0 100644 --- a/sys/mips/idt/if_kr.c +++ b/sys/mips/idt/if_kr.c @@ -265,10 +265,10 @@ kr_attach(device_t dev) CSR_WRITE_4(sc, KR_MIIMCFG, 0); /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->kr_miibus, - kr_ifmedia_upd, kr_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + error = mii_attach(dev, &sc->kr_miibus, ifp, kr_ifmedia_upd, + kr_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } diff --git a/sys/mips/idt/obio.c b/sys/mips/idt/obio.c index 44e9bfa6ea4..034b93ab644 100644 --- a/sys/mips/idt/obio.c +++ b/sys/mips/idt/obio.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); static int obio_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t obio_add_child(device_t, int, const char *, int); +static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -422,7 +422,7 @@ obio_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -obio_add_child(device_t bus, int order, const char *name, int unit) +obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; diff --git a/sys/mips/include/atomic.h b/sys/mips/include/atomic.h index 4b87738cf90..7b4a82cb06a 100644 --- a/sys/mips/include/atomic.h +++ b/sys/mips/include/atomic.h @@ -48,7 +48,7 @@ static __inline void mips_sync(void) { - __asm __volatile (".set noreorder\n\t" + __asm __volatile (".set noreorder\n\t" "sync\n\t" "nop\n\t" "nop\n\t" diff --git a/sys/mips/include/cpufunc.h b/sys/mips/include/cpufunc.h index 11109e7ae36..a1715c9fdf4 100644 --- a/sys/mips/include/cpufunc.h +++ b/sys/mips/include/cpufunc.h @@ -266,6 +266,24 @@ intr_restore(register_t ie) } } +static __inline uint32_t +set_intr_mask(uint32_t mask) +{ + uint32_t ostatus; + + ostatus = mips_rd_status(); + mask = (ostatus & ~MIPS_SR_INT_MASK) | (mask & MIPS_SR_INT_MASK); + mips_wr_status(mask); + return (ostatus); +} + +static __inline uint32_t +get_intr_mask(void) +{ + + return (mips_rd_status() & MIPS_SR_INT_MASK); +} + static __inline void breakpoint(void) { diff --git a/sys/mips/include/cpuregs.h b/sys/mips/include/cpuregs.h index ee6a47a83c9..bc55a7eb2e9 100644 --- a/sys/mips/include/cpuregs.h +++ b/sys/mips/include/cpuregs.h @@ -58,10 +58,6 @@ #ifndef _MIPS_CPUREGS_H_ #define _MIPS_CPUREGS_H_ -#if defined(_KERNEL_OPT) -#include "opt_cputype.h" -#endif - /* * Address space. * 32-bit mips CPUS partition their 32-bit address space into four segments: @@ -71,13 +67,13 @@ * kseg1 0xa0000000 - 0xbfffffff Physical memory, uncached, unmapped * kseg2 0xc0000000 - 0xffffffff kernel-virtual, mapped * - * mips1 physical memory is limited to 512Mbytes, which is - * doubly mapped in kseg0 (cached) and kseg1 (uncached.) * Caching of mapped addresses is controlled by bits in the TLB entry. */ -#define MIPS_KSEG0_LARGEST_PHYS (0x20000000) -#define MIPS_PHYS_MASK (0x1fffffff) +#define MIPS_KSEG0_LARGEST_PHYS (0x20000000) +#define MIPS_KSEG0_PHYS_MASK (0x1fffffff) +#define MIPS_XKPHYS_LARGEST_PHYS (0x10000000000) /* 40 bit PA */ +#define MIPS_XKPHYS_PHYS_MASK (0x0ffffffffff) #ifndef LOCORE #define MIPS_KUSEG_START 0x00000000 @@ -95,8 +91,8 @@ #define MIPS_PHYS_TO_KSEG0(x) ((uintptr_t)(x) | MIPS_KSEG0_START) #define MIPS_PHYS_TO_KSEG1(x) ((uintptr_t)(x) | MIPS_KSEG1_START) -#define MIPS_KSEG0_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) -#define MIPS_KSEG1_TO_PHYS(x) ((uintptr_t)(x) & MIPS_PHYS_MASK) +#define MIPS_KSEG0_TO_PHYS(x) ((uintptr_t)(x) & MIPS_KSEG0_PHYS_MASK) +#define MIPS_KSEG1_TO_PHYS(x) ((uintptr_t)(x) & MIPS_KSEG0_PHYS_MASK) #define MIPS_IS_KSEG0_ADDR(x) \ (((vm_offset_t)(x) >= MIPS_KSEG0_START) && \ @@ -107,9 +103,6 @@ #define MIPS_IS_VALID_PTR(x) (MIPS_IS_KSEG0_ADDR(x) || \ MIPS_IS_KSEG1_ADDR(x)) -#define MIPS_XKPHYS_START 0x8000000000000000 -#define MIPS_XKPHYS_END 0xbfffffffffffffff - /* * Cache Coherency Attributes: * UC: Uncached. @@ -180,19 +173,34 @@ #define MIPS_PHYS_TO_XKPHYS_UNCACHED(x) \ ((0x2ULL << 62) | ((unsigned long long)(MIPS_CCA_UNCACHED) << 59) | (x)) -#define MIPS_XKPHYS_TO_PHYS(x) ((x) & 0x07ffffffffffffffULL) +#define MIPS_XKPHYS_TO_PHYS(x) ((uintptr_t)(x) & MIPS_XKPHYS_PHYS_MASK) +#define MIPS_XKPHYS_START 0x8000000000000000 +#define MIPS_XKPHYS_END 0xbfffffffffffffff #define MIPS_XUSEG_START 0x0000000000000000 #define MIPS_XUSEG_END 0x0000010000000000 - #define MIPS_XKSEG_START 0xc000000000000000 #define MIPS_XKSEG_END 0xc00000ff80000000 +#ifdef __mips_n64 +#define MIPS_DIRECT_MAPPABLE(pa) 1 +#define MIPS_PHYS_TO_DIRECT(pa) MIPS_PHYS_TO_XKPHYS_CACHED(pa) +#define MIPS_PHYS_TO_DIRECT_UNCACHED(pa) MIPS_PHYS_TO_XKPHYS_UNCACHED(pa) +#define MIPS_DIRECT_TO_PHYS(va) MIPS_XKPHYS_TO_PHYS(va) +#else +#define MIPS_DIRECT_MAPPABLE(pa) ((pa) < MIPS_KSEG0_LARGEST_PHYS) +#define MIPS_PHYS_TO_DIRECT(pa) MIPS_PHYS_TO_KSEG0(pa) +#define MIPS_PHYS_TO_DIRECT_UNCACHED(pa) MIPS_PHYS_TO_KSEG1(pa) +#define MIPS_DIRECT_TO_PHYS(va) MIPS_KSEG0_TO_PHYS(va) +#endif + /* CPU dependent mtc0 hazard hook */ #ifdef CPU_CNMIPS #define COP0_SYNC nop; nop; nop; nop; nop; #elif defined(CPU_SB1) #define COP0_SYNC ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop; ssnop +#elif defined(CPU_RMI) +#define COP0_SYNC #else /* * Pick a reasonable default based on the "typical" spacing described in the @@ -329,29 +337,6 @@ #define MIPS_SR_INT_IE 0x00010001 /* XXX */ #endif -/* - * These definitions are for MIPS32 processors. - */ -#define MIPS32_SR_RP 0x08000000 /* reduced power mode */ -#define MIPS32_SR_FR 0x04000000 /* 64-bit capable fpu */ -#define MIPS32_SR_RE 0x02000000 /* reverse user endian */ -#define MIPS32_SR_MX 0x01000000 /* MIPS64 */ -#define MIPS32_SR_PX 0x00800000 /* MIPS64 */ -#define MIPS32_SR_BEV 0x00400000 /* Use boot exception vector */ -#define MIPS32_SR_TS 0x00200000 /* TLB multiple match */ -#define MIPS32_SR_SOFT_RESET 0x00100000 /* soft reset occurred */ -#define MIPS32_SR_NMI 0x00080000 /* NMI occurred */ -#define MIPS32_SR_INT_MASK 0x0000ff00 -#define MIPS32_SR_KX 0x00000080 /* MIPS64 */ -#define MIPS32_SR_SX 0x00000040 /* MIPS64 */ -#define MIPS32_SR_UX 0x00000020 /* MIPS64 */ -#define MIPS32_SR_KSU_MASK 0x00000018 /* privilege mode */ -#define MIPS32_SR_KSU_USER 0x00000010 -#define MIPS32_SR_KSU_SUPER 0x00000008 -#define MIPS32_SR_KSU_KERNEL 0x00000000 -#define MIPS32_SR_ERL 0x00000004 /* error level */ -#define MIPS32_SR_EXL 0x00000002 /* exception level */ - #define MIPS_SR_SOFT_RESET MIPS3_SR_SR #define MIPS_SR_DIAG_CH MIPS3_SR_DIAG_CH #define MIPS_SR_DIAG_CE MIPS3_SR_DIAG_CE diff --git a/sys/mips/include/elf.h b/sys/mips/include/elf.h index 2d6ca3e9038..2646181ca04 100644 --- a/sys/mips/include/elf.h +++ b/sys/mips/include/elf.h @@ -251,8 +251,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ #define ET_DYN_LOAD_ADDR 0x0120000 diff --git a/sys/mips/include/locore.h b/sys/mips/include/locore.h index 7cc72c7ceff..34c9afc5975 100644 --- a/sys/mips/include/locore.h +++ b/sys/mips/include/locore.h @@ -24,15 +24,13 @@ */ #ifndef _MIPS_LOCORE_H -#define _MIPS_LOCORE_H +#define _MIPS_LOCORE_H #include #include #include #include -struct tlb; - /* * CPU identification, from PRID register. */ @@ -47,22 +45,22 @@ typedef int mips_prid_t; #define MIPS_PRID_REV_MAJ(x) ((MIPS_PRID_REV(x) >> 4) & 0x0f) /* MIPS32/64 */ -#define MIPS_PRID_CID(x) (((x) >> 16) & 0x00ff) /* Company ID */ -#define MIPS_PRID_CID_PREHISTORIC 0x00 /* Not MIPS32/64 */ -#define MIPS_PRID_CID_MTI 0x01 /* MIPS Technologies, Inc. */ -#define MIPS_PRID_CID_BROADCOM 0x02 /* Broadcom */ -#define MIPS_PRID_CID_ALCHEMY 0x03 /* Alchemy Semiconductor */ -#define MIPS_PRID_CID_SIBYTE 0x04 /* SiByte */ -#define MIPS_PRID_CID_SANDCRAFT 0x05 /* SandCraft */ -#define MIPS_PRID_CID_PHILIPS 0x06 /* Philips */ -#define MIPS_PRID_CID_TOSHIBA 0x07 /* Toshiba */ -#define MIPS_PRID_CID_LSI 0x08 /* LSI */ +#define MIPS_PRID_CID(x) (((x) >> 16) & 0x00ff) /* Company ID */ +#define MIPS_PRID_CID_PREHISTORIC 0x00 /* Not MIPS32/64 */ +#define MIPS_PRID_CID_MTI 0x01 /* MIPS Technologies, Inc. */ +#define MIPS_PRID_CID_BROADCOM 0x02 /* Broadcom */ +#define MIPS_PRID_CID_ALCHEMY 0x03 /* Alchemy Semiconductor */ +#define MIPS_PRID_CID_SIBYTE 0x04 /* SiByte */ +#define MIPS_PRID_CID_SANDCRAFT 0x05 /* SandCraft */ +#define MIPS_PRID_CID_PHILIPS 0x06 /* Philips */ +#define MIPS_PRID_CID_TOSHIBA 0x07 /* Toshiba */ +#define MIPS_PRID_CID_LSI 0x08 /* LSI */ /* 0x09 unannounced */ /* 0x0a unannounced */ -#define MIPS_PRID_CID_LEXRA 0x0b /* Lexra */ -#define MIPS_PRID_CID_RMI 0x0c /* RMI */ -#define MIPS_PRID_CID_CAVIUM 0x0d /* Cavium */ -#define MIPS_PRID_COPTS(x) (((x) >> 24) & 0x00ff) /* Company Options */ +#define MIPS_PRID_CID_LEXRA 0x0b /* Lexra */ +#define MIPS_PRID_CID_RMI 0x0c /* RMI */ +#define MIPS_PRID_CID_CAVIUM 0x0d /* Cavium */ +#define MIPS_PRID_COPTS(x) (((x) >> 24) & 0x00ff) /* Company Options */ #ifdef _KERNEL #ifdef __HAVE_MIPS_MACHDEP_CACHE_CONFIG diff --git a/sys/mips/include/md_var.h b/sys/mips/include/md_var.h index 33171bff80f..fee2e44b31e 100644 --- a/sys/mips/include/md_var.h +++ b/sys/mips/include/md_var.h @@ -52,11 +52,9 @@ void cpu_swapin(struct proc *); uintptr_t MipsEmulateBranch(struct trapframe *, uintptr_t, int, uintptr_t); void MipsSwitchFPState(struct thread *, struct trapframe *); u_long kvtop(void *addr); -int is_physical_memory(vm_offset_t addr); +int is_cacheable_mem(vm_offset_t addr); void mips_generic_reset(void); -#define is_cacheable_mem(pa) is_physical_memory((pa)) - #define MIPS_DEBUG 0 #if MIPS_DEBUG @@ -75,9 +73,5 @@ void mips_postboot_fixup(void); void platform_identify(void); extern int busdma_swi_pending; -void busdma_swi(void); - -u_int32_t set_intr_mask(u_int32_t); -u_int32_t get_intr_mask(void); - +void busdma_swi(void); #endif /* !_MACHINE_MD_VAR_H_ */ diff --git a/sys/mips/include/memdev.h b/sys/mips/include/memdev.h index 2872fb07298..8cca4610093 100644 --- a/sys/mips/include/memdev.h +++ b/sys/mips/include/memdev.h @@ -28,7 +28,7 @@ */ #define CDEV_MINOR_MEM 0 -#define CDEV_MINOR_KMEM 1 +#define CDEV_MINOR_KMEM 1 d_open_t memopen; d_read_t memrw; diff --git a/sys/mips/include/pcb.h b/sys/mips/include/pcb.h index e0982e35f24..99113396277 100644 --- a/sys/mips/include/pcb.h +++ b/sys/mips/include/pcb.h @@ -58,20 +58,20 @@ struct pcb /* these match the regnum's in regnum.h * used by switch.S */ -#define PCB_REG_S0 0 -#define PCB_REG_S1 1 -#define PCB_REG_S2 2 -#define PCB_REG_S3 3 -#define PCB_REG_S4 4 -#define PCB_REG_S5 5 -#define PCB_REG_S6 6 -#define PCB_REG_S7 7 -#define PCB_REG_SP 8 -#define PCB_REG_S8 9 -#define PCB_REG_RA 10 -#define PCB_REG_SR 11 -#define PCB_REG_GP 12 -#define PCB_REG_PC 13 +#define PCB_REG_S0 0 +#define PCB_REG_S1 1 +#define PCB_REG_S2 2 +#define PCB_REG_S3 3 +#define PCB_REG_S4 4 +#define PCB_REG_S5 5 +#define PCB_REG_S6 6 +#define PCB_REG_S7 7 +#define PCB_REG_SP 8 +#define PCB_REG_S8 9 +#define PCB_REG_RA 10 +#define PCB_REG_SR 11 +#define PCB_REG_GP 12 +#define PCB_REG_PC 13 #ifdef _KERNEL diff --git a/sys/mips/include/pmap.h b/sys/mips/include/pmap.h index 543251995fd..558a0182ce8 100644 --- a/sys/mips/include/pmap.h +++ b/sys/mips/include/pmap.h @@ -126,11 +126,6 @@ typedef struct pv_entry { vm_page_t pv_ptem; /* VM page for pte */ } *pv_entry_t; - -#if defined(DIAGNOSTIC) -#define PMAP_DIAGNOSTIC -#endif - /* * physmem_desc[] is a superset of phys_avail[] and describes all the * memory present in the system. @@ -159,6 +154,7 @@ void pmap_unmapdev(vm_offset_t, vm_size_t); vm_offset_t pmap_steal_memory(vm_size_t size); int page_is_managed(vm_offset_t pa); void pmap_kenter(vm_offset_t va, vm_paddr_t pa); +void pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int attr); void pmap_kremove(vm_offset_t va); void *pmap_kenter_temporary(vm_paddr_t pa, int i); void pmap_kenter_temporary_free(vm_paddr_t pa); diff --git a/sys/mips/include/pte.h b/sys/mips/include/pte.h index 0765eb33a6f..a8926da8b5b 100644 --- a/sys/mips/include/pte.h +++ b/sys/mips/include/pte.h @@ -130,9 +130,6 @@ typedef pt_entry_t *pd_entry_t; /* * PTE management functions for bits defined above. - * - * XXX Can make these atomics, but some users of them are using PTEs in local - * registers and such and don't need the overhead. */ #define pte_clear(pte, bit) (*(pte) &= ~(bit)) #define pte_set(pte, bit) (*(pte) |= (bit)) diff --git a/sys/mips/include/regnum.h b/sys/mips/include/regnum.h index 1c22bb96961..ae7cf4bc112 100644 --- a/sys/mips/include/regnum.h +++ b/sys/mips/include/regnum.h @@ -46,20 +46,20 @@ * in pcb.h and is used by * swtch.S */ -#define PREG_S0 0 -#define PREG_S1 1 -#define PREG_S2 2 -#define PREG_S3 3 -#define PREG_S4 4 -#define PREG_S5 5 -#define PREG_S6 6 -#define PREG_S7 7 -#define PREG_SP 8 -#define PREG_S8 9 -#define PREG_RA 10 -#define PREG_SR 11 -#define PREG_GP 12 -#define PREG_PC 13 +#define PREG_S0 0 +#define PREG_S1 1 +#define PREG_S2 2 +#define PREG_S3 3 +#define PREG_S4 4 +#define PREG_S5 5 +#define PREG_S6 6 +#define PREG_S7 7 +#define PREG_SP 8 +#define PREG_S8 9 +#define PREG_RA 10 +#define PREG_SR 11 +#define PREG_GP 12 +#define PREG_PC 13 /* * Location of the saved registers relative to ZERO. diff --git a/sys/mips/include/smp.h b/sys/mips/include/smp.h index 28efd4c8caf..58aaf03165b 100644 --- a/sys/mips/include/smp.h +++ b/sys/mips/include/smp.h @@ -28,7 +28,6 @@ #define IPI_STOP_HARD 0x0008 #define IPI_PREEMPT 0x0010 #define IPI_HARDCLOCK 0x0020 -#define IPI_STATCLOCK 0x0040 #ifndef LOCORE diff --git a/sys/mips/include/ucontext.h b/sys/mips/include/ucontext.h index 7d4c2e46d4a..72f07b402e2 100644 --- a/sys/mips/include/ucontext.h +++ b/sys/mips/include/ucontext.h @@ -48,13 +48,13 @@ typedef struct __mcontext { int mc_onstack; /* sigstack state to restore */ register_t mc_pc; /* pc at time of signal */ register_t mc_regs[32]; /* processor regs 0 to 31 */ - register_t sr; /* status register */ - register_t mullo, mulhi; /* mullo and mulhi registers... */ + register_t sr; /* status register */ + register_t mullo, mulhi; /* mullo and mulhi registers... */ int mc_fpused; /* fp has been used */ f_register_t mc_fpregs[33]; /* fp regs 0 to 31 and csr */ register_t mc_fpc_eir; /* fp exception instruction reg */ void *mc_tls; /* pointer to TLS area */ - int __spare__[8]; /* XXX reserved */ + int __spare__[8]; /* XXX reserved */ } mcontext_t; #endif @@ -101,7 +101,7 @@ typedef struct __mcontext { #define UCR_SP UCTX_REG(29) #define UCR_S8 UCTX_REG(30) #define UCR_RA UCTX_REG(31) -#define UCR_SR UCTX_REG(32) +#define UCR_SR UCTX_REG(32) #define UCR_MDLO UCTX_REG(33) #define UCR_MDHI UCTX_REG(34) diff --git a/sys/mips/include/vmparam.h b/sys/mips/include/vmparam.h index a1e5e843fcc..3050a9151ee 100644 --- a/sys/mips/include/vmparam.h +++ b/sys/mips/include/vmparam.h @@ -96,7 +96,7 @@ #define VM_MINUSER_ADDRESS ((vm_offset_t)0x00000000) #define VM_MAX_MMAP_ADDR VM_MAXUSER_ADDRESS -#if defined(__mips_n64) +#ifdef __mips_n64 #define VM_MAXUSER_ADDRESS (VM_MINUSER_ADDRESS + (NPDEPG * NBSEG)) #define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)0xc000000000000000) #define VM_MAX_KERNEL_ADDRESS (VM_MIN_KERNEL_ADDRESS + (NPDEPG * NBSEG)) @@ -185,7 +185,7 @@ * allocations use HIGHMEM if available, and then DEFAULT. * - HIGHMEM for other pages */ -#if 0 /* Not yet, change n64 to use xkphys */ +#ifdef __mips_n64 #define VM_NFREELIST 1 #define VM_FREELIST_DEFAULT 0 #define VM_FREELIST_DIRECT VM_FREELIST_DEFAULT diff --git a/sys/mips/mips/busdma_machdep.c b/sys/mips/mips/busdma_machdep.c index a6a7419747c..93ae8d29dab 100644 --- a/sys/mips/mips/busdma_machdep.c +++ b/sys/mips/mips/busdma_machdep.c @@ -133,7 +133,7 @@ struct bus_dmamap { struct bp_list bpages; int pagesneeded; int pagesreserved; - bus_dma_tag_t dmat; + bus_dma_tag_t dmat; int flags; void *buffer; void *origbuffer; @@ -142,7 +142,7 @@ struct bus_dmamap { int len; STAILQ_ENTRY(bus_dmamap) links; bus_dmamap_callback_t *callback; - void *callback_arg; + void *callback_arg; }; @@ -310,11 +310,11 @@ _busdma_free_dmamap(bus_dmamap_t map) int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, - bus_size_t boundary, bus_addr_t lowaddr, - bus_addr_t highaddr, bus_dma_filter_t *filter, - void *filterarg, bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, - void *lockfuncarg, bus_dma_tag_t *dmat) + bus_size_t boundary, bus_addr_t lowaddr, + bus_addr_t highaddr, bus_dma_filter_t *filter, + void *filterarg, bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, + void *lockfuncarg, bus_dma_tag_t *dmat) { bus_dma_tag_t newtag; int error = 0; @@ -337,8 +337,8 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1); newtag->filter = filter; newtag->filterarg = filterarg; - newtag->maxsize = maxsize; - newtag->nsegments = nsegments; + newtag->maxsize = maxsize; + newtag->nsegments = nsegments; newtag->maxsegsz = maxsegsz; newtag->flags = flags; if (cpuinfo.cache_coherent_dma) @@ -352,28 +352,28 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, newtag->lockfunc = dflt_lock; newtag->lockfuncarg = NULL; } - /* + /* * Take into account any restrictions imposed by our parent tag */ - if (parent != NULL) { - newtag->lowaddr = min(parent->lowaddr, newtag->lowaddr); - newtag->highaddr = max(parent->highaddr, newtag->highaddr); + if (parent != NULL) { + newtag->lowaddr = min(parent->lowaddr, newtag->lowaddr); + newtag->highaddr = max(parent->highaddr, newtag->highaddr); if (newtag->boundary == 0) newtag->boundary = parent->boundary; else if (parent->boundary != 0) - newtag->boundary = min(parent->boundary, - newtag->boundary); + newtag->boundary = + min(parent->boundary, newtag->boundary); if ((newtag->filter != NULL) || ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0)) newtag->flags |= BUS_DMA_COULD_BOUNCE; - if (newtag->filter == NULL) { - /* - * Short circuit looking at our parent directly - * since we have encapsulated all of its information - */ - newtag->filter = parent->filter; - newtag->filterarg = parent->filterarg; - newtag->parent = parent->parent; + if (newtag->filter == NULL) { + /* + * Short circuit looking at our parent directly + * since we have encapsulated all of its information + */ + newtag->filter = parent->filter; + newtag->filterarg = parent->filterarg; + newtag->parent = parent->parent; } if (newtag->parent != NULL) atomic_add_int(&parent->ref_count, 1); @@ -425,30 +425,29 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat) #endif if (dmat != NULL) { + if (dmat->map_count != 0) + return (EBUSY); - if (dmat->map_count != 0) - return (EBUSY); - - while (dmat != NULL) { - bus_dma_tag_t parent; + while (dmat != NULL) { + bus_dma_tag_t parent; - parent = dmat->parent; - atomic_subtract_int(&dmat->ref_count, 1); - if (dmat->ref_count == 0) { - free(dmat, M_DEVBUF); - /* - * Last reference count, so - * release our reference - * count on our parent. - */ - dmat = parent; - } else - dmat = NULL; - } - } + parent = dmat->parent; + atomic_subtract_int(&dmat->ref_count, 1); + if (dmat->ref_count == 0) { + free(dmat, M_DEVBUF); + /* + * Last reference count, so + * release our reference + * count on our parent. + */ + dmat = parent; + } else + dmat = NULL; + } + } CTR2(KTR_BUSDMA, "%s tag %p", __func__, dmat_copy); - return (0); + return (0); } #include @@ -554,7 +553,7 @@ bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) */ int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, - bus_dmamap_t *mapp) + bus_dmamap_t *mapp) { bus_dmamap_t newmap = NULL; @@ -590,50 +589,37 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, if (flags & BUS_DMA_COHERENT) newmap->flags |= DMAMAP_UNCACHEABLE; - if (dmat->maxsize <= PAGE_SIZE && + if (dmat->maxsize <= PAGE_SIZE && (dmat->alignment < dmat->maxsize) && !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr) && !(newmap->flags & DMAMAP_UNCACHEABLE)) { *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags); newmap->flags |= DMAMAP_MALLOCUSED; - } else { - /* - * XXX Use Contigmalloc until it is merged into this facility - * and handles multi-seg allocations. Nobody is doing - * multi-seg allocations yet though. - */ - vm_paddr_t maxphys; - if((uint32_t)dmat->lowaddr >= MIPS_KSEG0_LARGEST_PHYS) { - /* Note in the else case I just put in what was already - * being passed in dmat->lowaddr. I am not sure - * how this would have worked. Since lowaddr is in the - * max address postion. I would have thought that the - * caller would have wanted dmat->highaddr. That is - * presuming they are asking for physical addresses - * which is what contigmalloc takes. - RRS - */ - maxphys = MIPS_KSEG0_LARGEST_PHYS - 1; - } else { - maxphys = dmat->lowaddr; - } - *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags, - 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, - dmat->boundary); - } - if (*vaddr == NULL) { + } else { + /* + * XXX Use Contigmalloc until it is merged into this facility + * and handles multi-seg allocations. Nobody is doing + * multi-seg allocations yet though. + */ + *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags, + 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, + dmat->boundary); + } + if (*vaddr == NULL) { if (newmap != NULL) { _busdma_free_dmamap(newmap); dmat->map_count--; } *mapp = NULL; - return (ENOMEM); + return (ENOMEM); } if (newmap->flags & DMAMAP_UNCACHEABLE) { void *tmpaddr = (void *)*vaddr; if (tmpaddr) { - tmpaddr = (void *)MIPS_PHYS_TO_KSEG1(vtophys(tmpaddr)); + tmpaddr = (void *)pmap_mapdev(vtophys(tmpaddr), + dmat->maxsize); newmap->origbuffer = *vaddr; newmap->allocbuffer = tmpaddr; mips_dcache_wbinv_range((vm_offset_t)*vaddr, @@ -644,7 +630,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, } else newmap->origbuffer = newmap->allocbuffer = NULL; - return (0); + return (0); } /* @@ -660,9 +646,11 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) vaddr = map->origbuffer; } - if (map->flags & DMAMAP_MALLOCUSED) + if (map->flags & DMAMAP_UNCACHEABLE) + pmap_unmapdev((vm_offset_t)map->allocbuffer, dmat->maxsize); + if (map->flags & DMAMAP_MALLOCUSED) free(vaddr, M_DEVBUF); - else + else contigfree(vaddr, dmat->maxsize, M_DEVBUF); dmat->map_count--; @@ -831,10 +819,10 @@ segdone: */ int bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, - bus_size_t buflen, bus_dmamap_callback_t *callback, - void *callback_arg, int flags) + bus_size_t buflen, bus_dmamap_callback_t *callback, + void *callback_arg, int flags) { - vm_offset_t lastaddr = 0; + vm_offset_t lastaddr = 0; int error, nsegs = -1; #ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT bus_dma_segment_t dm_segments[dmat->nsegments]; @@ -871,8 +859,8 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, */ int bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, - bus_dmamap_callback2_t *callback, void *callback_arg, - int flags) + bus_dmamap_callback2_t *callback, void *callback_arg, + int flags) { #ifdef __CC_SUPPORTS_DYNAMIC_ARRAY_INIT bus_dma_segment_t dm_segments[dmat->nsegments]; @@ -1360,7 +1348,7 @@ alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages) } bpage->busaddr = pmap_kextract(bpage->vaddr); bpage->vaddr_nocache = - (vm_offset_t)MIPS_PHYS_TO_KSEG1(bpage->busaddr); + (vm_offset_t)pmap_mapdev(bpage->busaddr, PAGE_SIZE); mtx_lock(&bounce_lock); STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links); total_bpages++; diff --git a/sys/mips/mips/exception.S b/sys/mips/mips/exception.S index 1baf2b22e81..fdd0a02e02d 100644 --- a/sys/mips/mips/exception.S +++ b/sys/mips/mips/exception.S @@ -1167,7 +1167,7 @@ eintrcnt: .text VECTOR(MipsCache, unknown) PTR_LA k0, _C_LABEL(MipsCacheException) - li k1, MIPS_PHYS_MASK + li k1, MIPS_KSEG0_PHYS_MASK and k0, k1 PTR_LI k1, MIPS_KSEG1_START or k0, k1 diff --git a/sys/mips/mips/locore.S b/sys/mips/mips/locore.S index e45e2398b3c..9f685ebfee4 100644 --- a/sys/mips/mips/locore.S +++ b/sys/mips/mips/locore.S @@ -161,11 +161,11 @@ VECTOR(_locore, unknown) /* * Initialize stack and call machine startup. */ - PTR_LA sp, _C_LABEL(pcpu_space) - addiu sp, (PAGE_SIZE * 2) - CALLFRAME_SIZ + PTR_LA sp, _C_LABEL(pcpu_space) + PTR_ADDU sp, (PAGE_SIZE * 2) - CALLFRAME_SIZ - sw zero, CALLFRAME_SIZ - 4(sp) # Zero out old ra for debugger - sw zero, CALLFRAME_SIZ - 8(sp) # Zero out old fp for debugger + REG_S zero, CALLFRAME_RA(sp) # Zero out old ra for debugger + REG_S zero, CALLFRAME_SP(sp) # Zero out old fp for debugger PTR_LA gp, _C_LABEL(_gp) diff --git a/sys/mips/mips/machdep.c b/sys/mips/mips/machdep.c index 8c16051f3ad..435b9b4d67a 100644 --- a/sys/mips/mips/machdep.c +++ b/sys/mips/mips/machdep.c @@ -356,7 +356,7 @@ mips_vector_init(void) * Mask all interrupts. Each interrupt will be enabled * when handler is installed for it */ - set_intr_mask(MIPS_SR_INT_MASK); + set_intr_mask(0); /* Clear BEV in SR so we start handling our own exceptions */ mips_wr_status(mips_rd_status() & ~MIPS_SR_BEV); @@ -497,7 +497,7 @@ cpu_idle_wakeup(int cpu) } int -is_physical_memory(vm_offset_t addr) +is_cacheable_mem(vm_offset_t addr) { int i; diff --git a/sys/mips/mips/mainbus.c b/sys/mips/mips/mainbus.c index 3e1e66ac5f5..587b409a3be 100644 --- a/sys/mips/mips/mainbus.c +++ b/sys/mips/mips/mainbus.c @@ -67,7 +67,7 @@ static struct rman irq_rman, port_rman, mem_rman; static int mainbus_probe(device_t); static int mainbus_attach(device_t); static int mainbus_print_child(device_t, device_t); -static device_t mainbus_add_child(device_t bus, int order, const char *name, +static device_t mainbus_add_child(device_t bus, u_int order, const char *name, int unit); static struct resource *mainbus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); @@ -178,7 +178,7 @@ mainbus_print_child(device_t bus, device_t child) } static device_t -mainbus_add_child(device_t bus, int order, const char *name, int unit) +mainbus_add_child(device_t bus, u_int order, const char *name, int unit) { return device_add_child_ordered(bus, order, name, unit); } diff --git a/sys/mips/mips/mp_machdep.c b/sys/mips/mips/mp_machdep.c index c7ff3d8560b..2b993cb9937 100644 --- a/sys/mips/mips/mp_machdep.c +++ b/sys/mips/mips/mp_machdep.c @@ -164,11 +164,7 @@ mips_ipi_handler(void *arg) break; case IPI_HARDCLOCK: CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__); - hardclockintr(arg);; - break; - case IPI_STATCLOCK: - CTR1(KTR_SMP, "%s: IPI_STATCLOCK", __func__); - statclockintr(arg);; + hardclockintr();; break; default: panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu); @@ -314,8 +310,6 @@ smp_init_secondary(u_int32_t cpuid) while (smp_started == 0) ; /* nothing */ - intr_enable(); - /* Start per-CPU event timers. */ cpu_initclocks_ap(); diff --git a/sys/mips/mips/nexus.c b/sys/mips/mips/nexus.c index 10b38b5ff86..227446618e0 100644 --- a/sys/mips/mips/nexus.c +++ b/sys/mips/mips/nexus.c @@ -82,7 +82,7 @@ static struct resource * u_long, u_long, u_int); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); -static device_t nexus_add_child(device_t, int, const char *, int); +static device_t nexus_add_child(device_t, u_int, const char *, int); static int nexus_attach(device_t); static int nexus_deactivate_resource(device_t, device_t, int, int, struct resource *); @@ -282,7 +282,7 @@ nexus_hinted_child(device_t bus, const char *dname, int dunit) } static device_t -nexus_add_child(device_t bus, int order, const char *name, int unit) +nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index de191f7c3d2..c39554fd3b4 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -105,17 +105,13 @@ __FBSDID("$FreeBSD$"); #include #include -#if defined(DIAGNOSTIC) -#define PMAP_DIAGNOSTIC -#endif - #undef PMAP_DEBUG #ifndef PMAP_SHPGPERPROC #define PMAP_SHPGPERPROC 200 #endif -#if !defined(PMAP_DIAGNOSTIC) +#if !defined(DIAGNOSTIC) #define PMAP_INLINE __inline #else #define PMAP_INLINE @@ -198,68 +194,135 @@ static void pmap_invalidate_all_action(void *arg); static void pmap_update_page_action(void *arg); #endif -#if !defined(__mips_n64) -struct local_sysmaps { - vm_offset_t base; - uint16_t valid1, valid2; -}; - -/* This structure is for large memory - * above 512Meg. We can't (in 32 bit mode) - * just use the direct mapped MIPS_KSEG0_TO_PHYS() - * macros since we can't see the memory and must - * map it in when we need to access it. In 64 - * bit mode this goes away. +#ifndef __mips_n64 +/* + * This structure is for high memory (memory above 512Meg in 32 bit) + * This memory area does not have direct mapping, so we a mechanism to do + * temporary per-CPU mapping to access these addresses. + * + * At bootup we reserve 2 virtual pages per CPU for mapping highmem pages, to + * access a highmem physical address on a CPU, we will disable interrupts and + * add the mapping from the reserved virtual address for the CPU to the physical + * address in the kernel pagetable. */ +struct local_sysmaps { + vm_offset_t base; + uint32_t saved_intr; + uint16_t valid1, valid2; +}; static struct local_sysmaps sysmap_lmem[MAXCPU]; -#define PMAP_LMEM_MAP1(va, phys) \ - int cpu; \ - struct local_sysmaps *sysm; \ - pt_entry_t *pte, npte; \ - \ - intr = intr_disable(); \ - cpu = PCPU_GET(cpuid); \ - sysm = &sysmap_lmem[cpu]; \ - va = sysm->base; \ - npte = TLBLO_PA_TO_PFN(phys) | \ - PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; \ - pte = pmap_pte(kernel_pmap, va); \ - *pte = npte; \ - sysm->valid1 = 1 +static __inline void +pmap_alloc_lmem_map(void) +{ + int i; -#define PMAP_LMEM_MAP2(va1, phys1, va2, phys2) \ - int cpu; \ - struct local_sysmaps *sysm; \ - pt_entry_t *pte, npte; \ - \ - intr = intr_disable(); \ - cpu = PCPU_GET(cpuid); \ - sysm = &sysmap_lmem[cpu]; \ - va1 = sysm->base; \ - va2 = sysm->base + PAGE_SIZE; \ - npte = TLBLO_PA_TO_PFN(phys1) | \ - PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; \ - pte = pmap_pte(kernel_pmap, va1); \ - *pte = npte; \ - npte = TLBLO_PA_TO_PFN(phys2) | \ - PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; \ - pte = pmap_pte(kernel_pmap, va2); \ - *pte = npte; \ - sysm->valid1 = 1; \ + for (i = 0; i < MAXCPU; i++) { + sysmap_lmem[i].base = virtual_avail; + virtual_avail += PAGE_SIZE * 2; + sysmap_lmem[i].valid1 = sysmap_lmem[i].valid2 = 0; + } +} + +static __inline vm_offset_t +pmap_lmem_map1(vm_paddr_t phys) +{ + struct local_sysmaps *sysm; + pt_entry_t *pte, npte; + vm_offset_t va; + uint32_t intr; + int cpu; + + intr = intr_disable(); + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + sysm->saved_intr = intr; + va = sysm->base; + npte = TLBLO_PA_TO_PFN(phys) | + PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; + pte = pmap_pte(kernel_pmap, va); + *pte = npte; + sysm->valid1 = 1; + return (va); +} + +static __inline vm_offset_t +pmap_lmem_map2(vm_paddr_t phys1, vm_paddr_t phys2) +{ + struct local_sysmaps *sysm; + pt_entry_t *pte, npte; + vm_offset_t va1, va2; + uint32_t intr; + int cpu; + + intr = intr_disable(); + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + sysm->saved_intr = intr; + va1 = sysm->base; + va2 = sysm->base + PAGE_SIZE; + npte = TLBLO_PA_TO_PFN(phys1) | + PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; + pte = pmap_pte(kernel_pmap, va1); + *pte = npte; + npte = TLBLO_PA_TO_PFN(phys2) | + PTE_D | PTE_V | PTE_G | PTE_W | PTE_C_CACHE; + pte = pmap_pte(kernel_pmap, va2); + *pte = npte; + sysm->valid1 = 1; sysm->valid2 = 1; + return (va1); +} -#define PMAP_LMEM_UNMAP() \ - pte = pmap_pte(kernel_pmap, sysm->base); \ - *pte = PTE_G; \ - tlb_invalidate_address(kernel_pmap, sysm->base); \ - sysm->valid1 = 0; \ - pte = pmap_pte(kernel_pmap, sysm->base + PAGE_SIZE); \ - *pte = PTE_G; \ - tlb_invalidate_address(kernel_pmap, sysm->base + PAGE_SIZE); \ - sysm->valid2 = 0; \ - intr_restore(intr) -#endif +static __inline void +pmap_lmem_unmap(void) +{ + struct local_sysmaps *sysm; + pt_entry_t *pte; + int cpu; + + cpu = PCPU_GET(cpuid); + sysm = &sysmap_lmem[cpu]; + pte = pmap_pte(kernel_pmap, sysm->base); + *pte = PTE_G; + tlb_invalidate_address(kernel_pmap, sysm->base); + sysm->valid1 = 0; + if (sysm->valid2) { + pte = pmap_pte(kernel_pmap, sysm->base + PAGE_SIZE); + *pte = PTE_G; + tlb_invalidate_address(kernel_pmap, sysm->base + PAGE_SIZE); + sysm->valid2 = 0; + } + intr_restore(sysm->saved_intr); +} +#else /* __mips_n64 */ + +static __inline void +pmap_alloc_lmem_map(void) +{ +} + +static __inline vm_offset_t +pmap_lmem_map1(vm_paddr_t phys) +{ + + return (0); +} + +static __inline vm_offset_t +pmap_lmem_map2(vm_paddr_t phys1, vm_paddr_t phys2) +{ + + return (0); +} + +static __inline vm_offset_t +pmap_lmem_unmap(void) +{ + + return (0); +} +#endif /* !__mips_n64 */ /* * Page table entry lookup routines. @@ -267,6 +330,7 @@ static struct local_sysmaps sysmap_lmem[MAXCPU]; static __inline pd_entry_t * pmap_segmap(pmap_t pmap, vm_offset_t va) { + return (&pmap->pm_segtab[pmap_seg_index(va)]); } @@ -295,13 +359,15 @@ pmap_pde(pmap_t pmap, vm_offset_t va) static __inline pd_entry_t * pmap_pdpe_to_pde(pd_entry_t *pdpe, vm_offset_t va) { - return pdpe; + + return (pdpe); } static __inline pd_entry_t *pmap_pde(pmap_t pmap, vm_offset_t va) { - return pmap_segmap(pmap, va); + + return (pmap_segmap(pmap, va)); } #endif @@ -351,12 +417,11 @@ pmap_steal_memory(vm_size_t size) pa = phys_avail[0]; phys_avail[0] += size; - if (pa >= MIPS_KSEG0_LARGEST_PHYS) { + if (MIPS_DIRECT_MAPPABLE(pa) == 0) panic("Out of memory below 512Meg?"); - } - va = MIPS_PHYS_TO_KSEG0(pa); + va = MIPS_PHYS_TO_DIRECT(pa); bzero((caddr_t)va, size); - return va; + return (va); } /* @@ -426,9 +491,7 @@ void pmap_bootstrap(void) { int i; -#if !defined(__mips_n64) - int memory_larger_than_512meg = 0; -#endif + int need_local_mappings = 0; /* Sort. */ again: @@ -456,10 +519,13 @@ again: } } -#if !defined(__mips_n64) - if (phys_avail[i - 1] >= MIPS_KSEG0_LARGEST_PHYS) - memory_larger_than_512meg = 1; -#endif + /* + * In 32 bit, we may have memory which cannot be mapped directly + * this memory will need temporary mapping before it can be + * accessed. + */ + if (!MIPS_DIRECT_MAPPABLE(phys_avail[i - 1])) + need_local_mappings = 1; /* * Copy the phys_avail[] array before we start stealing memory from it. @@ -518,22 +584,8 @@ again: printf("pcpu is available at virtual address %p.\n", pcpup); #endif -#if !defined(__mips_n64) - /* - * Steal some virtual space that will not be in kernel_segmap. This - * va memory space will be used to map in kernel pages that are - * outside the 512Meg region. Note that we only do this steal when - * we do have memory in this region, that way for systems with - * smaller memory we don't "steal" any va ranges :-) - */ - if (memory_larger_than_512meg) { - for (i = 0; i < MAXCPU; i++) { - sysmap_lmem[i].base = virtual_avail; - virtual_avail += PAGE_SIZE * 2; - sysmap_lmem[i].valid1 = sysmap_lmem[i].valid2 = 0; - } - } -#endif + if (need_local_mappings) + pmap_alloc_lmem_map(); pmap_create_kernel_pagetable(); pmap_max_asid = VMNUM_PIDS; mips_wr_entryhi(0); @@ -579,22 +631,6 @@ pmap_init(void) * Low level helper routines..... ***************************************************/ -#if defined(PMAP_DIAGNOSTIC) - -/* - * This code checks for non-writeable/modified pages. - * This should be an invalid condition. - */ -static int -pmap_nw_modified(pt_entry_t pte) -{ - if ((pte & (PTE_D | PTE_RO)) == (PTE_D | PTE_RO)) - return (1); - else - return (0); -} -#endif - static __inline void pmap_invalidate_all_local(pmap_t pmap) { @@ -750,7 +786,7 @@ pmap_extract(pmap_t pmap, vm_offset_t va) retval = TLBLO_PTE_TO_PA(*pte) | (va & PAGE_MASK); } PMAP_UNLOCK(pmap); - return retval; + return (retval); } /* @@ -792,8 +828,8 @@ retry: /* * add a wired page to the kva */ - /* PMAP_INLINE */ void -pmap_kenter(vm_offset_t va, vm_paddr_t pa) +void +pmap_kenter_attr(vm_offset_t va, vm_paddr_t pa, int attr) { pt_entry_t *pte; pt_entry_t opte, npte; @@ -801,12 +837,7 @@ pmap_kenter(vm_offset_t va, vm_paddr_t pa) #ifdef PMAP_DEBUG printf("pmap_kenter: va: %p -> pa: %p\n", (void *)va, (void *)pa); #endif - npte = TLBLO_PA_TO_PFN(pa) | PTE_D | PTE_V | PTE_G | PTE_W; - - if (is_cacheable_mem(pa)) - npte |= PTE_C_CACHE; - else - npte |= PTE_C_UNCACHED; + npte = TLBLO_PA_TO_PFN(pa) | PTE_D | PTE_V | PTE_G | PTE_W | attr; pte = pmap_pte(kernel_pmap, va); opte = *pte; @@ -815,6 +846,16 @@ pmap_kenter(vm_offset_t va, vm_paddr_t pa) pmap_update_page(kernel_pmap, va, npte); } +void +pmap_kenter(vm_offset_t va, vm_paddr_t pa) +{ + + KASSERT(is_cacheable_mem(pa), + ("pmap_kenter: memory at 0x%lx is not cacheable", (u_long)pa)); + + pmap_kenter_attr(va, pa, PTE_C_CACHE); +} + /* * remove a page from the kernel pagetables */ @@ -847,20 +888,13 @@ pmap_kremove(vm_offset_t va) * * Use XKPHYS for 64 bit, and KSEG0 where possible for 32 bit. */ -#if defined(__mips_n64) -vm_offset_t -pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot) -{ - return (MIPS_PHYS_TO_XKPHYS_CACHED(start)); -} -#else vm_offset_t pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot) { vm_offset_t va, sva; - if (end <= MIPS_KSEG0_LARGEST_PHYS) - return (MIPS_PHYS_TO_KSEG0(start)); + if (MIPS_DIRECT_MAPPABLE(end)) + return (MIPS_PHYS_TO_DIRECT(start)); va = sva = *virt; while (start < end) { @@ -871,7 +905,6 @@ pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot) *virt = va; return (sva); } -#endif /* * Add a list of wired pages to the kva @@ -968,7 +1001,7 @@ _pmap_unwire_pte_hold(pmap_t pmap, vm_offset_t va, vm_page_t m) * Recursively decrement next level pagetable refcount */ pdp = (pd_entry_t *)*pmap_segmap(pmap, va); - pdpg = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(pdp)); + pdpg = PHYS_TO_VM_PAGE(MIPS_DIRECT_TO_PHYS(pdp)); pmap_unwire_pte_hold(pmap, va, pdpg); } #endif @@ -1003,11 +1036,11 @@ pmap_unuse_pt(pmap_t pmap, vm_offset_t va, vm_page_t mpte) mpte = pmap->pm_ptphint; } else { pteva = *pmap_pde(pmap, va); - mpte = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(pteva)); + mpte = PHYS_TO_VM_PAGE(MIPS_DIRECT_TO_PHYS(pteva)); pmap->pm_ptphint = mpte; } } - return pmap_unwire_pte_hold(pmap, va, mpte); + return (pmap_unwire_pte_hold(pmap, va, mpte)); } void @@ -1032,7 +1065,11 @@ static void pmap_grow_pte_page_cache() { +#ifdef __mips_n64 + vm_contig_grow_cache(3, 0, MIPS_XKPHYS_LARGEST_PHYS); +#else vm_contig_grow_cache(3, 0, MIPS_KSEG0_LARGEST_PHYS); +#endif } static vm_page_t @@ -1072,7 +1109,7 @@ pmap_pinit(pmap_t pmap) while ((ptdpg = pmap_alloc_pte_page(NUSERPGTBLS, VM_ALLOC_NORMAL)) == NULL) pmap_grow_pte_page_cache(); - ptdva = MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(ptdpg)); + ptdva = MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(ptdpg)); pmap->pm_segtab = (pd_entry_t *)ptdva; pmap->pm_active = 0; pmap->pm_ptphint = NULL; @@ -1123,7 +1160,7 @@ _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags) * Map the pagetable page into the process address space, if it * isn't already there. */ - pageva = MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(m)); + pageva = MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(m)); #ifdef __mips_n64 if (ptepindex >= NUPDE) { @@ -1146,7 +1183,7 @@ _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags) return (NULL); } } else { - pg = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(*pdep)); + pg = PHYS_TO_VM_PAGE(MIPS_DIRECT_TO_PHYS(*pdep)); pg->wire_count++; } /* Next level entry */ @@ -1199,7 +1236,7 @@ retry: (pmap->pm_ptphint->pindex == ptepindex)) { m = pmap->pm_ptphint; } else { - m = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(*pde)); + m = PHYS_TO_VM_PAGE(MIPS_DIRECT_TO_PHYS(*pde)); pmap->pm_ptphint = m; } m->wire_count++; @@ -1247,7 +1284,7 @@ pmap_release(pmap_t pmap) pmap->pm_stats.resident_count)); ptdva = (vm_offset_t)pmap->pm_segtab; - ptdpg = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(ptdva)); + ptdpg = PHYS_TO_VM_PAGE(MIPS_DIRECT_TO_PHYS(ptdva)); ptdpg->wire_count--; atomic_subtract_int(&cnt.v_wire_count, 1); @@ -1278,7 +1315,7 @@ pmap_growkernel(vm_offset_t addr) nkpg = pmap_alloc_pte_page(nkpt, VM_ALLOC_INTERRUPT); if (nkpg == NULL) panic("pmap_growkernel: no memory to grow kernel"); - *pdpe = (pd_entry_t)MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(nkpg)); + *pdpe = (pd_entry_t)MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(nkpg)); continue; /* try again */ } #endif @@ -1299,7 +1336,7 @@ pmap_growkernel(vm_offset_t addr) if (!nkpg) panic("pmap_growkernel: no memory to grow kernel"); nkpt++; - *pde = (pd_entry_t)MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(nkpg)); + *pde = (pd_entry_t)MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(nkpg)); /* * The R[4-7]?00 stores only one copy of the Global bit in @@ -1546,13 +1583,9 @@ pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va) if (page_is_managed(pa)) { m = PHYS_TO_VM_PAGE(pa); if (pte_test(&oldpte, PTE_D)) { -#if defined(PMAP_DIAGNOSTIC) - if (pmap_nw_modified(oldpte)) { - printf( - "pmap_remove: modified page not writable: va: 0x%x, pte: 0x%x\n", - va, oldpte); - } -#endif + KASSERT(!pte_test(&oldpte, PTE_RO), + ("%s: modified page not writable: va: %p, pte: 0x%x", + __func__, (void *)va, oldpte)); vm_page_dirty(m); } if (m->md.pv_flags & PV_TABLE_REF) @@ -1561,7 +1594,7 @@ pmap_remove_pte(struct pmap *pmap, pt_entry_t *ptq, vm_offset_t va) pmap_remove_entry(pmap, m, va); } - return pmap_unuse_pt(pmap, va, NULL); + return (pmap_unuse_pt(pmap, va, NULL)); } /* @@ -1709,13 +1742,9 @@ pmap_remove_all(vm_page_t m) * Update the vm_page_t clean and reference bits. */ if (pte_test(&tpte, PTE_D)) { -#if defined(PMAP_DIAGNOSTIC) - if (pmap_nw_modified(tpte)) { - printf( - "pmap_remove_all: modified page not writable: va: 0x%x, pte: 0x%x\n", - pv->pv_va, tpte); - } -#endif + KASSERT(!pte_test(&tpte, PTE_RO), + ("%s: modified page not writable: va: %p, pte: 0x%x", + __func__, (void *)pv->pv_va, tpte)); vm_page_dirty(m); } pmap_invalidate_page(pv->pv_pmap, pv->pv_va); @@ -1856,7 +1885,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, * Page Directory table entry not valid, we need a new PT page */ if (pte == NULL) { - panic("pmap_enter: invalid page directory, pdir=%p, va=%p\n", + panic("pmap_enter: invalid page directory, pdir=%p, va=%p", (void *)pmap->pm_segtab, (void *)va); } pa = VM_PAGE_TO_PHYS(m); @@ -1879,13 +1908,9 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m, else if (!wired && pte_test(&origpte, PTE_W)) pmap->pm_stats.wired_count--; -#if defined(PMAP_DIAGNOSTIC) - if (pmap_nw_modified(origpte)) { - printf( - "pmap_enter: modified page not writable: va: 0x%x, pte: 0x%x\n", - va, origpte); - } -#endif + KASSERT(!pte_test(&origpte, PTE_D | PTE_RO), + ("%s: modified page not writable: va: %p, pte: 0x%x", + __func__, (void *)va, origpte)); /* * Remove extra pte reference @@ -2077,7 +2102,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, mpte = pmap->pm_ptphint; } else { mpte = PHYS_TO_VM_PAGE( - MIPS_KSEG0_TO_PHYS(*pde)); + MIPS_DIRECT_TO_PHYS(*pde)); pmap->pm_ptphint = mpte; } mpte->wire_count++; @@ -2153,30 +2178,21 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, * * Use XKPHYS for 64 bit, and KSEG0 where possible for 32 bit. */ -#if defined(__mips_n64) -void * -pmap_kenter_temporary(vm_paddr_t pa, int i) -{ - return ((void *)MIPS_PHYS_TO_XKPHYS_CACHED(pa)); -} -void -pmap_kenter_temporary_free(vm_paddr_t pa) -{ -} -#else void * pmap_kenter_temporary(vm_paddr_t pa, int i) { vm_offset_t va; - register_t intr; + if (i != 0) printf("%s: ERROR!!! More than one page of virtual address mapping not supported\n", __func__); - if (pa < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_KSEG0(pa); + if (MIPS_DIRECT_MAPPABLE(pa)) { + va = MIPS_PHYS_TO_DIRECT(pa); } else { +#ifndef __mips_n64 /* XXX : to be converted to new style */ int cpu; + register_t intr; struct local_sysmaps *sysm; pt_entry_t *pte, npte; @@ -2196,6 +2212,7 @@ pmap_kenter_temporary(vm_paddr_t pa, int i) pmap_update_page(kernel_pmap, sysm->base, npte); va = sysm->base; intr_restore(intr); +#endif } return ((void *)va); } @@ -2203,14 +2220,17 @@ pmap_kenter_temporary(vm_paddr_t pa, int i) void pmap_kenter_temporary_free(vm_paddr_t pa) { +#ifndef __mips_n64 /* XXX : to be converted to new style */ int cpu; register_t intr; struct local_sysmaps *sysm; +#endif - if (pa < MIPS_KSEG0_LARGEST_PHYS) { + if (MIPS_DIRECT_MAPPABLE(pa)) { /* nothing to do for this case */ return; } +#ifndef __mips_n64 /* XXX : to be converted to new style */ cpu = PCPU_GET(cpuid); sysm = &sysmap_lmem[cpu]; if (sysm->valid1) { @@ -2223,8 +2243,8 @@ pmap_kenter_temporary_free(vm_paddr_t pa) intr_restore(intr); sysm->valid1 = 0; } -} #endif +} /* * Moved the code to Machine Independent @@ -2333,113 +2353,65 @@ pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, * * Use XKPHYS for 64 bit, and KSEG0 where possible for 32 bit. */ -#if defined (__mips_n64) void pmap_zero_page(vm_page_t m) { vm_offset_t va; vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - va = MIPS_PHYS_TO_XKPHYS_CACHED(phys); - bzero((caddr_t)va, PAGE_SIZE); - mips_dcache_wbinv_range(va, PAGE_SIZE); -} -#else -void -pmap_zero_page(vm_page_t m) -{ - vm_offset_t va; - vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - register_t intr; - - if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_KSEG0(phys); - + if (MIPS_DIRECT_MAPPABLE(phys)) { + va = MIPS_PHYS_TO_DIRECT(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); } else { - PMAP_LMEM_MAP1(va, phys); - + va = pmap_lmem_map1(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); - - PMAP_LMEM_UNMAP(); + pmap_lmem_unmap(); } } -#endif + /* * 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. */ -#if defined (__mips_n64) void pmap_zero_page_area(vm_page_t m, int off, int size) { vm_offset_t va; vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - va = MIPS_PHYS_TO_XKPHYS_CACHED(phys); - bzero((char *)(caddr_t)va + off, size); - mips_dcache_wbinv_range(va + off, size); -} -#else -void -pmap_zero_page_area(vm_page_t m, int off, int size) -{ - vm_offset_t va; - vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - register_t intr; - - if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_KSEG0(phys); + if (MIPS_DIRECT_MAPPABLE(phys)) { + va = MIPS_PHYS_TO_DIRECT(phys); bzero((char *)(caddr_t)va + off, size); mips_dcache_wbinv_range(va + off, size); } else { - PMAP_LMEM_MAP1(va, phys); - + va = pmap_lmem_map1(phys); bzero((char *)va + off, size); mips_dcache_wbinv_range(va + off, size); - - PMAP_LMEM_UNMAP(); + pmap_lmem_unmap(); } } -#endif -#if defined (__mips_n64) void pmap_zero_page_idle(vm_page_t m) { vm_offset_t va; vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - va = MIPS_PHYS_TO_XKPHYS_CACHED(phys); - bzero((caddr_t)va, PAGE_SIZE); - mips_dcache_wbinv_range(va, PAGE_SIZE); -} -#else -void -pmap_zero_page_idle(vm_page_t m) -{ - vm_offset_t va; - vm_paddr_t phys = VM_PAGE_TO_PHYS(m); - register_t intr; - - if (phys < MIPS_KSEG0_LARGEST_PHYS) { - va = MIPS_PHYS_TO_KSEG0(phys); + if (MIPS_DIRECT_MAPPABLE(phys)) { + va = MIPS_PHYS_TO_DIRECT(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); } else { - PMAP_LMEM_MAP1(va, phys); - + va = pmap_lmem_map1(phys); bzero((caddr_t)va, PAGE_SIZE); mips_dcache_wbinv_range(va, PAGE_SIZE); - - PMAP_LMEM_UNMAP(); + pmap_lmem_unmap(); } } -#endif /* * pmap_copy_page copies the specified (machine independent) @@ -2449,31 +2421,14 @@ pmap_zero_page_idle(vm_page_t m) * * Use XKPHYS for 64 bit, and KSEG0 where possible for 32 bit. */ -#if defined (__mips_n64) void pmap_copy_page(vm_page_t src, vm_page_t dst) { vm_offset_t va_src, va_dst; - vm_paddr_t phy_src = VM_PAGE_TO_PHYS(src); - vm_paddr_t phy_dst = VM_PAGE_TO_PHYS(dst); + vm_paddr_t phys_src = VM_PAGE_TO_PHYS(src); + vm_paddr_t phys_dst = VM_PAGE_TO_PHYS(dst); - pmap_flush_pvcache(src); - mips_dcache_wbinv_range_index(MIPS_PHYS_TO_XKPHYS_CACHED(phy_dst), PAGE_SIZE); - va_src = MIPS_PHYS_TO_XKPHYS_CACHED(phy_src); - va_dst = MIPS_PHYS_TO_XKPHYS_CACHED(phy_dst); - bcopy((caddr_t)va_src, (caddr_t)va_dst, PAGE_SIZE); - mips_dcache_wbinv_range(va_dst, PAGE_SIZE); -} -#else -void -pmap_copy_page(vm_page_t src, vm_page_t dst) -{ - vm_offset_t va_src, va_dst; - vm_paddr_t phy_src = VM_PAGE_TO_PHYS(src); - vm_paddr_t phy_dst = VM_PAGE_TO_PHYS(dst); - register_t intr; - - if ((phy_src < MIPS_KSEG0_LARGEST_PHYS) && (phy_dst < MIPS_KSEG0_LARGEST_PHYS)) { + if (MIPS_DIRECT_MAPPABLE(phys_src) && MIPS_DIRECT_MAPPABLE(phys_dst)) { /* easy case, all can be accessed via KSEG0 */ /* * Flush all caches for VA that are mapped to this page @@ -2481,21 +2436,19 @@ pmap_copy_page(vm_page_t src, vm_page_t dst) */ pmap_flush_pvcache(src); mips_dcache_wbinv_range_index( - MIPS_PHYS_TO_KSEG0(phy_dst), PAGE_SIZE); - va_src = MIPS_PHYS_TO_KSEG0(phy_src); - va_dst = MIPS_PHYS_TO_KSEG0(phy_dst); + MIPS_PHYS_TO_DIRECT(phys_dst), PAGE_SIZE); + va_src = MIPS_PHYS_TO_DIRECT(phys_src); + va_dst = MIPS_PHYS_TO_DIRECT(phys_dst); bcopy((caddr_t)va_src, (caddr_t)va_dst, PAGE_SIZE); mips_dcache_wbinv_range(va_dst, PAGE_SIZE); } else { - PMAP_LMEM_MAP2(va_src, phy_src, va_dst, phy_dst); - + va_src = pmap_lmem_map2(phys_src, phys_dst); + va_dst = va_src + PAGE_SIZE; bcopy((void *)va_src, (void *)va_dst, PAGE_SIZE); mips_dcache_wbinv_range(va_dst, PAGE_SIZE); - - PMAP_LMEM_UNMAP(); + pmap_lmem_unmap(); } } -#endif /* * Returns true if the pmap's pv is one of the first @@ -2549,13 +2502,11 @@ pmap_remove_pages(pmap_t pmap) } vm_page_lock_queues(); PMAP_LOCK(pmap); - sched_pin(); - //XXX need to be TAILQ_FOREACH_SAFE ? - for (pv = TAILQ_FIRST(&pmap->pm_pvlist); pv; pv = npv) { + for (pv = TAILQ_FIRST(&pmap->pm_pvlist); pv != NULL; pv = npv) { pte = pmap_pte(pv->pv_pmap, pv->pv_va); if (!pte_test(pte, PTE_V)) - panic("pmap_remove_pages: page on pm_pvlist has no pte\n"); + panic("pmap_remove_pages: page on pm_pvlist has no pte"); tpte = *pte; /* @@ -2590,7 +2541,6 @@ pmap_remove_pages(pmap_t pmap) pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem); free_pv_entry(pv); } - sched_unpin(); pmap_invalidate_all(pmap); PMAP_UNLOCK(pmap); vm_page_unlock_queues(); @@ -2609,19 +2559,13 @@ pmap_testbit(vm_page_t m, int bit) boolean_t rv = FALSE; if (m->flags & PG_FICTITIOUS) - return rv; + return (rv); if (TAILQ_FIRST(&m->md.pv_list) == NULL) - return rv; + return (rv); mtx_assert(&vm_page_queue_mtx, MA_OWNED); TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { -#if defined(PMAP_DIAGNOSTIC) - if (!pv->pv_pmap) { - printf("Null pmap (tb) at va: 0x%x\n", pv->pv_va); - continue; - } -#endif PMAP_LOCK(pv->pv_pmap); pte = pmap_pte(pv->pv_pmap, pv->pv_va); rv = pte_test(pte, bit); @@ -2650,13 +2594,6 @@ pmap_changebit(vm_page_t m, int bit, boolean_t setem) * setting RO do we need to clear the VAC? */ TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) { -#if defined(PMAP_DIAGNOSTIC) - if (!pv->pv_pmap) { - printf("Null pmap (cb) at va: 0x%x\n", pv->pv_va); - continue; - } -#endif - PMAP_LOCK(pv->pv_pmap); pte = pmap_pte(pv->pv_pmap, pv->pv_va); if (setem) { @@ -2743,7 +2680,7 @@ pmap_remove_write(vm_page_t m) npv = TAILQ_NEXT(pv, pv_plist); pte = pmap_pte(pv->pv_pmap, pv->pv_va); if (pte == NULL || !pte_test(pte, PTE_V)) - panic("page on pm_pvlist has no pte\n"); + panic("page on pm_pvlist has no pte"); va = pv->pv_va; pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE, @@ -2911,18 +2848,6 @@ pmap_clear_reference(vm_page_t m) * * Use XKPHYS uncached for 64 bit, and KSEG1 where possible for 32 bit. */ -#if defined(__mips_n64) -void * -pmap_mapdev(vm_offset_t pa, vm_size_t size) -{ - return ((void *)MIPS_PHYS_TO_XKPHYS_UNCACHED(pa)); -} - -void -pmap_unmapdev(vm_offset_t va, vm_size_t size) -{ -} -#else void * pmap_mapdev(vm_offset_t pa, vm_size_t size) { @@ -2932,8 +2857,8 @@ pmap_mapdev(vm_offset_t pa, vm_size_t size) * KSEG1 maps only first 512M of phys address space. For * pa > 0x20000000 we should make proper mapping * using pmap_kenter. */ - if ((pa + size - 1) < MIPS_KSEG0_LARGEST_PHYS) - return (void *)MIPS_PHYS_TO_KSEG1(pa); + if (MIPS_DIRECT_MAPPABLE(pa + size - 1)) + return ((void *)MIPS_PHYS_TO_DIRECT_UNCACHED(pa)); else { offset = pa & PAGE_MASK; size = roundup(size + offset, PAGE_SIZE); @@ -2943,7 +2868,7 @@ pmap_mapdev(vm_offset_t pa, vm_size_t size) panic("pmap_mapdev: Couldn't alloc kernel virtual memory"); pa = trunc_page(pa); for (tmpva = va; size > 0;) { - pmap_kenter(tmpva, pa); + pmap_kenter_attr(tmpva, pa, PTE_C_UNCACHED); size -= PAGE_SIZE; tmpva += PAGE_SIZE; pa += PAGE_SIZE; @@ -2956,6 +2881,7 @@ pmap_mapdev(vm_offset_t pa, vm_size_t size) void pmap_unmapdev(vm_offset_t va, vm_size_t size) { +#ifndef __mips_n64 vm_offset_t base, offset, tmpva; /* If the address is within KSEG1 then there is nothing to do */ @@ -2968,8 +2894,8 @@ pmap_unmapdev(vm_offset_t va, vm_size_t size) for (tmpva = base; tmpva < base + size; tmpva += PAGE_SIZE) pmap_kremove(tmpva); kmem_free(kernel_map, base, size); -} #endif +} /* * perform the pmap work for mincore @@ -3239,11 +3165,11 @@ page_is_managed(vm_offset_t pa) m = PHYS_TO_VM_PAGE(pa); if (m == NULL) - return 0; + return (0); if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0) - return 1; + return (1); } - return 0; + return (0); } static int diff --git a/sys/mips/mips/psraccess.S b/sys/mips/mips/psraccess.S deleted file mode 100644 index 02be3368e3e..00000000000 --- a/sys/mips/mips/psraccess.S +++ /dev/null @@ -1,81 +0,0 @@ -/* $OpenBSD$ */ -/* - * Copyright (c) 2001 Opsycon AB (www.opsycon.se / www.opsycon.com) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Opsycon AB, Sweden. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * JNPR: psraccess.S,v 1.4.2.1 2007/09/10 10:36:50 girish - * $FreeBSD$ - * - */ - -/* - * Low level code to manage processor specific registers. - */ - -#include -#include -#include - -#include "opt_cputype.h" - -#include "assym.s" - -/* - * FREEBSD_DEVELOPERS_FIXME - * Some MIPS CPU may need delays using nops between executing CP0 Instructions - */ -#define MIPS_CPU_NOP_DELAY nop;nop;nop;nop;nop;nop;nop;nop;nop;nop; - - .set noreorder # Noreorder is default style! - -LEAF(set_intr_mask) - li t0, MIPS_SR_INT_MASK # 1 means masked so invert. - not a0, a0 # 1 means masked so invert. - and a0, t0 # 1 means masked so invert. - mfc0 v0, MIPS_COP_0_STATUS - li v1, ~MIPS_SR_INT_MASK - and v1, v0 - or v1, a0 - mtc0 v1, MIPS_COP_0_STATUS - MIPS_CPU_NOP_DELAY - move v0, v1 - jr ra - nop - -END(set_intr_mask) - -LEAF(get_intr_mask) - li a0, 0 - mfc0 v0, MIPS_COP_0_STATUS - li v1, MIPS_SR_INT_MASK - and v0, v1 - or v0, a0 - jr ra - nop - -END(get_intr_mask) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 2323c668882..009db7caed6 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -304,7 +304,7 @@ trap(struct trapframe *trapframe) * return to userland. */ if (trapframe->sr & MIPS_SR_INT_IE) { - set_intr_mask(~(trapframe->sr & MIPS_SR_INT_MASK)); + set_intr_mask(trapframe->sr & MIPS_SR_INT_MASK); intr_enable(); } else { intr_disable(); diff --git a/sys/mips/rmi/board.c b/sys/mips/rmi/board.c index d346a9c274d..4c49dacc5ce 100644 --- a/sys/mips/rmi/board.c +++ b/sys/mips/rmi/board.c @@ -38,56 +38,318 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include -#include -static int xlr_rxstn_to_txstn_map[128] = { - [0 ... 7] = TX_STN_CPU_0, - [8 ... 15] = TX_STN_CPU_1, - [16 ... 23] = TX_STN_CPU_2, - [24 ... 31] = TX_STN_CPU_3, - [32 ... 39] = TX_STN_CPU_4, - [40 ... 47] = TX_STN_CPU_5, - [48 ... 55] = TX_STN_CPU_6, - [56 ... 63] = TX_STN_CPU_7, - [64 ... 95] = TX_STN_INVALID, - [96 ... 103] = TX_STN_GMAC, - [104 ... 107] = TX_STN_DMA, - [108 ... 111] = TX_STN_INVALID, - [112 ... 113] = TX_STN_XGS_0, - [114 ... 115] = TX_STN_XGS_1, - [116 ... 119] = TX_STN_INVALID, - [120 ... 127] = TX_STN_SAE -}; +struct stn_cc *xlr_core_cc_configs[] = { &cc_table_cpu_0, &cc_table_cpu_1, + &cc_table_cpu_2, &cc_table_cpu_3, &cc_table_cpu_4, &cc_table_cpu_5, + &cc_table_cpu_6, &cc_table_cpu_7}; -static int xls_rxstn_to_txstn_map[128] = { - [0 ... 7] = TX_STN_CPU_0, - [8 ... 15] = TX_STN_CPU_1, - [16 ... 23] = TX_STN_CPU_2, - [24 ... 31] = TX_STN_CPU_3, - [32 ... 63] = TX_STN_INVALID, - [64 ... 71] = TX_STN_PCIE, - [72 ... 79] = TX_STN_INVALID, - [80 ... 87] = TX_STN_GMAC1, - [88 ... 95] = TX_STN_INVALID, - [96 ... 103] = TX_STN_GMAC0, - [104 ... 107] = TX_STN_DMA, - [108 ... 111] = TX_STN_CDE, - [112 ... 119] = TX_STN_INVALID, - [120 ... 127] = TX_STN_SAE -}; - -struct stn_cc *xlr_core_cc_configs[] = {&cc_table_cpu_0, &cc_table_cpu_1, - &cc_table_cpu_2, &cc_table_cpu_3, - &cc_table_cpu_4, &cc_table_cpu_5, -&cc_table_cpu_6, &cc_table_cpu_7}; - -struct stn_cc *xls_core_cc_configs[] = {&xls_cc_table_cpu_0, &xls_cc_table_cpu_1, -&xls_cc_table_cpu_2, &xls_cc_table_cpu_3}; +struct stn_cc *xls_core_cc_configs[] = { &xls_cc_table_cpu_0, &xls_cc_table_cpu_1, + &xls_cc_table_cpu_2, &xls_cc_table_cpu_3 }; struct xlr_board_info xlr_board_info; +static int +xlr_pcmcia_present(void) +{ + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); + uint32_t resetconf; + + resetconf = xlr_read_reg(mmio, 21); + return ((resetconf & 0x4000) != 0); +} + +static void +xlr_chip_specific_overrides(struct xlr_board_info* board) +{ + struct xlr_gmac_block_t *blk0, *blk1, *blk2; + uint32_t chipid; + uint32_t revision; + + blk0 = &board->gmac_block[0]; + blk1 = &board->gmac_block[1]; + blk2 = &board->gmac_block[2]; + + chipid = xlr_processor_id(); + revision = xlr_revision(); + + if (revision == 0x04) { /* B2 */ + switch (chipid) { + case 0x07: /* XLR 508 */ + case 0x08: /* XLR 516 */ + case 0x09: /* XLR 532 */ + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + case 0x06: /* XLR 308 */ + /* NA0 has 3 ports */ + blk0->gmac_port[3].valid = 0; + blk0->num_ports--; + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + default: + break; + } + } else if (revision == 0x91) { /* C4 */ + switch (chipid) { + case 0x0B: /* XLR 508 */ + case 0x0A: /* XLR 516 */ + case 0x08: /* XLR 532 */ + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + case 0x0F: /* XLR 308 */ + /* NA0 has 3 ports */ + blk0->gmac_port[3].valid = 0; + blk0->num_ports--; + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + default: + break; + } + } else { /* other pre-production silicon */ + switch (chipid) { + /* XLR 5xx */ + case 0x0B: + case 0x0A: + case 0x07: + case 0x08: + case 0x09: + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + /* XLR 3xx */ + case 0x0F: + case 0x06: + /* NA0 has 3 ports */ + blk0->gmac_port[3].valid = 0; + blk0->num_ports--; + /* NA[12] not available */ + memset(blk1, 0, sizeof(*blk1)); + memset(blk2, 0, sizeof(*blk2)); + break; + default: + break; + } + } +} + +static void +xlr_board_specific_overrides(struct xlr_board_info* board) +{ + struct xlr_gmac_block_t *blk1, *blk2; + + blk1 = &board->gmac_block[1]; + blk2 = &board->gmac_block[2]; + + switch (xlr_boot1_info.board_major_version) { + case RMI_XLR_BOARD_ARIZONA_I: + /* ATX-I has SPI-4, not XGMAC */ + blk1->type = XLR_SPI4; + blk1->enabled = 0; /* nlge does not + support SPI-4 */ + blk2->type = XLR_SPI4; + blk2->enabled = 0; + break; + + case RMI_XLR_BOARD_ARIZONA_II: + /* XGMII_A --> VSC7281, XGMII_B --> VSC7281 */ + blk1->enabled = 1; + blk1->num_ports = 1; + blk1->gmac_port[0].valid = 1; + + blk2->enabled = 1; + blk2->num_ports = 1; + blk2->gmac_port[0].valid = 1; + default: + break; + } +} + +static int +quad0_xaui(void) +{ + xlr_reg_t *gpio_mmio = + (unsigned int *)(DEFAULT_XLR_IO_BASE + XLR_IO_GPIO_OFFSET); + uint32_t bit24; + + bit24 = (xlr_read_reg(gpio_mmio, 0x15) >> 24) & 0x1; + return (bit24); +} + +static int +quad1_xaui(void) +{ + xlr_reg_t *gpio_mmio = + (unsigned int *)(DEFAULT_XLR_IO_BASE + XLR_IO_GPIO_OFFSET); + uint32_t bit25; + + bit25 = (xlr_read_reg(gpio_mmio, 0x15) >> 25) & 0x1; + return (bit25); +} + +static void +xls_chip_specific_overrides(struct xlr_board_info* board) +{ + struct xlr_gmac_block_t *blk0, *blk1; + uint32_t chipid; + + blk0 = &board->gmac_block[0]; + blk1 = &board->gmac_block[1]; + chipid = xlr_processor_id(); + + switch (chipid) { + case 0x8E: /* XLS208 */ + case 0x8F: /* XLS204 */ + /* NA1 is not available */ + memset(blk1, 0, sizeof(*blk1)); + break; + case 0xCE: /* XLS108 */ + case 0xCF: /* XLS104 */ + /* NA0 has 3 ports */ + blk0->gmac_port[3].valid = 0; + blk0->num_ports--; + /* NA1 is not available */ + memset(blk1, 0, sizeof(*blk1)); + break; + default: + break; + } +} + +static void +xls_board_specific_overrides(struct xlr_board_info* board) +{ + struct xlr_gmac_block_t *blk0, *blk1; + int i; + + blk0 = &board->gmac_block[0]; + blk1 = &board->gmac_block[1]; + + switch (xlr_boot1_info.board_major_version) { + case RMI_XLR_BOARD_ARIZONA_VI: + blk0->mode = XLR_PORT0_RGMII; + blk0->gmac_port[0].type = XLR_RGMII; + blk0->gmac_port[0].phy_addr = 0; + blk0->gmac_port[0].mii_addr = XLR_IO_GMAC_4_OFFSET; + /* Because of the Octal PHY, SGMII Quad1 is MII is also bound + * to the PHY attached to SGMII0_MDC/MDIO/MDINT. */ + for (i = 0; i < 4; i++) { + blk1->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; + } + blk1->gmac_port[1].mii_addr = XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[2].mii_addr = XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[3].mii_addr = XLR_IO_GMAC_0_OFFSET; + + blk1->gmac_port[1].serdes_addr = XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[2].serdes_addr = XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[3].serdes_addr = XLR_IO_GMAC_0_OFFSET; + + /* RGMII MDIO interrupt is thru NA1 and SGMII MDIO + * interrupts for ports in blk1 are from NA0 */ + blk0->gmac_port[0].mdint_id = 1; + + blk1->gmac_port[0].mdint_id = 0; + blk1->gmac_port[1].mdint_id = 0; + blk1->gmac_port[2].mdint_id = 0; + blk1->gmac_port[3].mdint_id = 0; + + /* If we have a 4xx lite chip, don't enable the + * GMACs which are disabled in hardware */ + if (xlr_is_xls4xx_lite()) { + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); + uint32_t tmp; + + /* Port 6 & 7 are not enabled on the condor 4xx, figure + * this out from the GPIO fuse bank */ + tmp = xlr_read_reg(mmio, 35); + if ((tmp & (3 << 28)) != 0) { + blk1->enabled = 0x3; + blk1->gmac_port[2].valid = 0; + blk1->gmac_port[3].valid = 0; + blk1->num_ports = 2; + } + } + break; + + case RMI_XLR_BOARD_ARIZONA_VIII: + if (blk1->enabled) { + /* There is just one Octal PHY on the board and it is + * connected to the MII interface for NA Quad 0. */ + for (i = 0; i < 4; i++) { + blk1->gmac_port[i].mii_addr = + XLR_IO_GMAC_0_OFFSET; + blk1->gmac_port[i].mdint_id = 0; + } + } + break; + + case RMI_XLR_BOARD_ARIZONA_XI: + case RMI_XLR_BOARD_ARIZONA_XII: + if (quad0_xaui()) { /* GMAC ports 0-3 are set to XAUI */ + /* only GMAC0 is active i.e, the 0-th port on this quad. + * Disable all the other 7 possible ports. */ + for (i = 1; i < MAX_NA_PORTS; i++) { + memset(&blk0->gmac_port[i], 0, + sizeof(blk0->gmac_port[i])); + } + /* Setup for XAUI on N/w Acc0: gmac0 */ + blk0->type = XLR_XGMAC; + blk0->mode = XLR_XAUI; + blk0->num_ports = 1; + blk0->gmac_port[0].type = XLR_XAUI; + blk1->gmac_port[0].phy_addr = 16; + blk0->gmac_port[0].tx_bucket_id = blk0->station_txbase; + /* Other addresses etc need not be modified as XAUI_0 + * shares its addresses with SGMII GMAC_0, which was + * set in the caller. */ + } + else { + blk0->num_ports = 1; /* only 1 RGMII port */ + blk0->mode = XLR_PORT0_RGMII; + blk0->gmac_port[0].type = XLR_RGMII; + blk0->gmac_port[0].phy_addr = 0; + blk0->gmac_port[0].mii_addr = XLR_IO_GMAC_0_OFFSET; + } + + if (quad1_xaui()) { /* GMAC ports 4-7 are used for XAUI */ + /* only GMAC4 is active i.e, the 0-th port on this quad. + * Disable all the other 7 possible ports. */ + for (i = 1; i < MAX_NA_PORTS; i++) { + memset(&blk1->gmac_port[i], 0, + sizeof(blk1->gmac_port[i])); + } + /* Setup for XAUI on N/w Acc1: gmac4 */ + blk1->type = XLR_XGMAC; + blk1->mode = XLR_XAUI; + blk1->num_ports = 1; + /* XAUI and SGMII ports share FMN buckets on N/w Acc 1; + so, station_txbase, station_rfr need not be + patched up. */ + blk1->gmac_port[0].type = XLR_XAUI; + blk1->gmac_port[0].phy_addr = 16; + blk1->gmac_port[0].tx_bucket_id = blk1->station_txbase; + /* Other addresses etc need not be modified as XAUI_1 + * shares its addresses with SGMII GMAC_4, which was + * set in the caller. */ + } + break; + + default: + break; + } +} + /* * All our knowledge of chip and board that cannot be detected by probing * at run-time goes here @@ -95,6 +357,61 @@ struct xlr_board_info xlr_board_info; int xlr_board_info_setup() { + struct xlr_gmac_block_t *blk0, *blk1, *blk2; + int i; + + /* This setup code is long'ish because the same base driver + * (if_nlge.c) is used for different: + * - CPUs (XLR/XLS) + * - boards (for each CPU, multiple board configs are possible + * and available). + * + * At the time of writing, there are atleast 12 boards, 4 with XLR + * and 8 with XLS. This means that the base driver needs to work with + * 12 different configurations, with varying levels of differences. + * To accomodate the different configs, the xlr_board_info struct + * has various attributes for paramters that could be different. + * These attributes are setup here and can be used directly in the + * base driver. + * It was seen that the setup code is not entirely trivial and + * it is possible to organize it in different ways. In the following, + * we choose an approach that sacrifices code-compactness/speed for + * readability. This is because configuration code executes once + * per reboot and hence has a minimal performance impact. + * On the other hand, driver debugging/enhancements require + * that different engineers can quickly comprehend the setup + * sequence. Hence, readability is seen as the key requirement for + * this code. It is for the reader to decide how much of this + * requirement is met with the current code organization !! + * + * The initialization is organized thus: + * + * if (CPU is XLS) { + * // initialize per XLS architecture + * // default inits (per chip spec) + * // chip-specific overrides + * // board-specific overrides + * } else if (CPU is XLR) { + * // initialize per XLR architecture + * // default inits (per chip spec) + * // chip-specific overrides + * // board-specific overrides + * } + * + * For each CPU family, all the default initializations + * are done for a fully-loaded device of that family. + * This configuration is then adjusted for the actual + * chip id. This is followed up with board specific + * overrides. + */ + + /* start with a clean slate */ + memset(&xlr_board_info, 0, sizeof(xlr_board_info)); + xlr_board_info.ata = xlr_pcmcia_present(); + + blk0 = &xlr_board_info.gmac_block[0]; + blk1 = &xlr_board_info.gmac_block[1]; + blk2 = &xlr_board_info.gmac_block[2]; if (xlr_is_xls()) { xlr_board_info.is_xls = 1; @@ -105,94 +422,153 @@ xlr_board_info_setup() (xlr_boot1_info.board_major_version != RMI_XLR_BOARD_ARIZONA_VIII); xlr_board_info.pci_irq = 0; xlr_board_info.credit_configs = xls_core_cc_configs; - xlr_board_info.bucket_sizes = &xls_bucket_sizes; - xlr_board_info.msgmap = xls_rxstn_to_txstn_map; - xlr_board_info.gmacports = 8; + xlr_board_info.bucket_sizes = &xls_bucket_sizes; + xlr_board_info.gmacports = MAX_NA_PORTS; - /* network block 0 */ - xlr_board_info.gmac_block[0].type = XLR_GMAC; - xlr_board_info.gmac_block[0].enabled = 0xf; - xlr_board_info.gmac_block[0].credit_config = &xls_cc_table_gmac0; - xlr_board_info.gmac_block[0].station_txbase = MSGRNG_STNID_GMACTX0; - xlr_board_info.gmac_block[0].station_rfr = MSGRNG_STNID_GMACRFR_0; - if (xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_VI || - xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_XI || - xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_XII) - xlr_board_info.gmac_block[0].mode = XLR_PORT0_RGMII; - else - xlr_board_info.gmac_block[0].mode = XLR_SGMII; - xlr_board_info.gmac_block[0].baseaddr = XLR_IO_GMAC_0_OFFSET; - xlr_board_info.gmac_block[0].baseirq = PIC_GMAC_0_IRQ; - xlr_board_info.gmac_block[0].baseinst = 0; + /* ---------------- Network Acc 0 ---------------- */ - /* network block 1 */ - xlr_board_info.gmac_block[1].type = XLR_GMAC; - xlr_board_info.gmac_block[1].enabled = xlr_is_xls1xx() ? 0 : 0xf; - if (xlr_is_xls4xx_lite()) { - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); - uint32_t tmp; + blk0->type = XLR_GMAC; + blk0->enabled = 0xf; + blk0->credit_config = &xls_cc_table_gmac0; + blk0->station_id = MSGRNG_STNID_GMAC; + blk0->station_txbase = MSGRNG_STNID_GMACTX0; + blk0->station_rfr = MSGRNG_STNID_GMACRFR_0; + blk0->mode = XLR_SGMII; + blk0->baseaddr = XLR_IO_GMAC_0_OFFSET; + blk0->baseirq = PIC_GMAC_0_IRQ; + blk0->baseinst = 0; - /* some ports are not enabled on the condor 4xx, figure this - out from the GPIO fuse bank */ - tmp = xlr_read_reg(mmio, 35); - if (tmp & (1<<28)) - xlr_board_info.gmac_block[1].enabled &= ~0x8; - if (tmp & (1<<29)) - xlr_board_info.gmac_block[1].enabled &= ~0x4; + /* By default, assume SGMII is setup. But this can change based + on board-specific or setting-specific info. */ + for (i = 0; i < 4; i++) { + blk0->gmac_port[i].valid = 1; + blk0->gmac_port[i].instance = i + blk0->baseinst; + blk0->gmac_port[i].type = XLR_SGMII; + blk0->gmac_port[i].phy_addr = i + 16; + blk0->gmac_port[i].tx_bucket_id = + blk0->station_txbase + i; + blk0->gmac_port[i].mdint_id = 0; + blk0->num_ports++; + blk0->gmac_port[i].base_addr = XLR_IO_GMAC_0_OFFSET + i * 0x1000; + blk0->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; + blk0->gmac_port[i].pcs_addr = XLR_IO_GMAC_0_OFFSET; + blk0->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; } - xlr_board_info.gmac_block[1].credit_config = &xls_cc_table_gmac1; - xlr_board_info.gmac_block[1].station_txbase = MSGRNG_STNID_GMAC1_TX0; - xlr_board_info.gmac_block[1].station_rfr = MSGRNG_STNID_GMAC1_FR_0; - xlr_board_info.gmac_block[1].mode = XLR_SGMII; - xlr_board_info.gmac_block[1].baseaddr = XLR_IO_GMAC_4_OFFSET; - xlr_board_info.gmac_block[1].baseirq = PIC_XGS_0_IRQ; - xlr_board_info.gmac_block[1].baseinst = 4; - /* network block 2 */ - xlr_board_info.gmac_block[2].enabled = 0; /* disabled on XLS */ - } else { + /* ---------------- Network Acc 1 ---------------- */ + blk1->type = XLR_GMAC; + blk1->enabled = 0xf; + blk1->credit_config = &xls_cc_table_gmac1; + blk1->station_id = MSGRNG_STNID_GMAC1; + blk1->station_txbase = MSGRNG_STNID_GMAC1_TX0; + blk1->station_rfr = MSGRNG_STNID_GMAC1_FR_0; + blk1->mode = XLR_SGMII; + blk1->baseaddr = XLR_IO_GMAC_4_OFFSET; + blk1->baseirq = PIC_XGS_0_IRQ; + blk1->baseinst = 4; + + for (i = 0; i < 4; i++) { + blk1->gmac_port[i].valid = 1; + blk1->gmac_port[i].instance = i + blk1->baseinst; + blk1->gmac_port[i].type = XLR_SGMII; + blk1->gmac_port[i].phy_addr = i + 20; + blk1->gmac_port[i].tx_bucket_id = + blk1->station_txbase + i; + blk1->gmac_port[i].mdint_id = 1; + blk1->num_ports++; + blk1->gmac_port[i].base_addr = XLR_IO_GMAC_4_OFFSET + i * 0x1000; + blk1->gmac_port[i].mii_addr = XLR_IO_GMAC_4_OFFSET; + blk1->gmac_port[i].pcs_addr = XLR_IO_GMAC_4_OFFSET; + blk1->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; + } + + /* ---------------- Network Acc 2 ---------------- */ + xlr_board_info.gmac_block[2].enabled = 0; /* disabled on XLS */ + + xls_chip_specific_overrides(&xlr_board_info); + xls_board_specific_overrides(&xlr_board_info); + + } else { /* XLR */ xlr_board_info.is_xls = 0; xlr_board_info.nr_cpus = 32; xlr_board_info.usb = 0; xlr_board_info.cfi = 1; xlr_board_info.pci_irq = 0; xlr_board_info.credit_configs = xlr_core_cc_configs; - xlr_board_info.bucket_sizes = &bucket_sizes; - xlr_board_info.msgmap = xlr_rxstn_to_txstn_map; - xlr_board_info.gmacports = 4; + xlr_board_info.bucket_sizes = &bucket_sizes; + xlr_board_info.gmacports = 4; - /* GMAC0 */ - xlr_board_info.gmac_block[0].type = XLR_GMAC; - xlr_board_info.gmac_block[0].enabled = 0xf; - xlr_board_info.gmac_block[0].credit_config = &cc_table_gmac; - xlr_board_info.gmac_block[0].station_txbase = MSGRNG_STNID_GMACTX0; - xlr_board_info.gmac_block[0].station_rfr = MSGRNG_STNID_GMACRFR_0; - xlr_board_info.gmac_block[0].mode = XLR_RGMII; - xlr_board_info.gmac_block[0].baseaddr = XLR_IO_GMAC_0_OFFSET; - xlr_board_info.gmac_block[0].baseirq = PIC_GMAC_0_IRQ; - xlr_board_info.gmac_block[0].baseinst = 0; + /* ---------------- GMAC0 ---------------- */ + blk0->type = XLR_GMAC; + blk0->enabled = 0xf; + blk0->credit_config = &cc_table_gmac; + blk0->station_id = MSGRNG_STNID_GMAC; + blk0->station_txbase = MSGRNG_STNID_GMACTX0; + blk0->station_rfr = MSGRNG_STNID_GMACRFR_0; + blk0->mode = XLR_RGMII; + blk0->baseaddr = XLR_IO_GMAC_0_OFFSET; + blk0->baseirq = PIC_GMAC_0_IRQ; + blk0->baseinst = 0; - /* XGMAC0 */ - xlr_board_info.gmac_block[1].type = XLR_XGMAC; - xlr_board_info.gmac_block[1].enabled = 1; - xlr_board_info.gmac_block[1].credit_config = &cc_table_xgs_0; - xlr_board_info.gmac_block[1].station_txbase = MSGRNG_STNID_XGS0_TX; - xlr_board_info.gmac_block[1].station_rfr = MSGRNG_STNID_XGS0FR; - xlr_board_info.gmac_block[1].mode = -1; - xlr_board_info.gmac_block[1].baseaddr = XLR_IO_XGMAC_0_OFFSET; - xlr_board_info.gmac_block[1].baseirq = PIC_XGS_0_IRQ; - xlr_board_info.gmac_block[1].baseinst = 4; + /* first, do the common/easy stuff for all the ports */ + for (i = 0; i < 4; i++) { + blk0->gmac_port[i].valid = 1; + blk0->gmac_port[i].instance = i + blk0->baseinst; + blk0->gmac_port[i].type = XLR_RGMII; + blk0->gmac_port[i].phy_addr = i; + blk0->gmac_port[i].tx_bucket_id = + blk0->station_txbase + i; + blk0->gmac_port[i].mdint_id = 0; + blk0->gmac_port[i].base_addr = XLR_IO_GMAC_0_OFFSET + i * 0x1000; + blk0->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; + /* RGMII ports, no PCS/SERDES */ + blk0->num_ports++; + } - /* XGMAC1 */ - xlr_board_info.gmac_block[2].type = XLR_XGMAC; - xlr_board_info.gmac_block[2].enabled = 1; - xlr_board_info.gmac_block[2].credit_config = &cc_table_xgs_1; - xlr_board_info.gmac_block[2].station_txbase = MSGRNG_STNID_XGS1_TX; - xlr_board_info.gmac_block[2].station_rfr = MSGRNG_STNID_XGS1FR; - xlr_board_info.gmac_block[2].mode = -1; - xlr_board_info.gmac_block[2].baseaddr = XLR_IO_XGMAC_1_OFFSET; - xlr_board_info.gmac_block[2].baseirq = PIC_XGS_1_IRQ; - xlr_board_info.gmac_block[2].baseinst = 5; - } - return 0; + /* ---------------- XGMAC0 ---------------- */ + blk1->type = XLR_XGMAC; + blk1->mode = XLR_XGMII; + blk1->enabled = 0; + blk1->credit_config = &cc_table_xgs_0; + blk1->station_txbase = MSGRNG_STNID_XGS0_TX; + blk1->station_rfr = MSGRNG_STNID_XMAC0RFR; + blk1->station_id = MSGRNG_STNID_XGS0FR; + blk1->baseaddr = XLR_IO_XGMAC_0_OFFSET; + blk1->baseirq = PIC_XGS_0_IRQ; + blk1->baseinst = 4; + + blk1->gmac_port[0].type = XLR_XGMII; + blk1->gmac_port[0].instance = 0; + blk1->gmac_port[0].phy_addr = 0; + blk1->gmac_port[0].base_addr = XLR_IO_XGMAC_0_OFFSET; + blk1->gmac_port[0].mii_addr = XLR_IO_XGMAC_0_OFFSET; + blk1->gmac_port[0].tx_bucket_id = blk1->station_txbase; + blk1->gmac_port[0].mdint_id = 1; + + /* ---------------- XGMAC1 ---------------- */ + blk2->type = XLR_XGMAC; + blk2->mode = XLR_XGMII; + blk2->enabled = 0; + blk2->credit_config = &cc_table_xgs_1; + blk2->station_txbase = MSGRNG_STNID_XGS1_TX; + blk2->station_rfr = MSGRNG_STNID_XMAC1RFR; + blk2->station_id = MSGRNG_STNID_XGS1FR; + blk2->baseaddr = XLR_IO_XGMAC_1_OFFSET; + blk2->baseirq = PIC_XGS_1_IRQ; + blk2->baseinst = 5; + + blk2->gmac_port[0].type = XLR_XGMII; + blk2->gmac_port[0].instance = 0; + blk2->gmac_port[0].phy_addr = 0; + blk2->gmac_port[0].base_addr = XLR_IO_XGMAC_1_OFFSET; + blk2->gmac_port[0].mii_addr = XLR_IO_XGMAC_1_OFFSET; + blk2->gmac_port[0].tx_bucket_id = blk2->station_txbase; + blk2->gmac_port[0].mdint_id = 2; + + /* Done with default setup. Now handle chip and board-specific + variations. */ + xlr_chip_specific_overrides(&xlr_board_info); + xlr_board_specific_overrides(&xlr_board_info); + } + return 0; } diff --git a/sys/mips/rmi/board.h b/sys/mips/rmi/board.h index 0092fea25d3..35ce7e17492 100644 --- a/sys/mips/rmi/board.h +++ b/sys/mips/rmi/board.h @@ -30,22 +30,22 @@ * $FreeBSD$ */ #ifndef _RMI_BOARD_H_ -#define _RMI_BOARD_H_ +#define _RMI_BOARD_H_ /* * Engineering boards have a major/minor number in their EEPROM to * identify their configuration */ -#define RMI_XLR_BOARD_ARIZONA_I 1 -#define RMI_XLR_BOARD_ARIZONA_II 2 -#define RMI_XLR_BOARD_ARIZONA_III 3 -#define RMI_XLR_BOARD_ARIZONA_IV 4 -#define RMI_XLR_BOARD_ARIZONA_V 5 -#define RMI_XLR_BOARD_ARIZONA_VI 6 -#define RMI_XLR_BOARD_ARIZONA_VII 7 -#define RMI_XLR_BOARD_ARIZONA_VIII 8 -#define RMI_XLR_BOARD_ARIZONA_XI 11 -#define RMI_XLR_BOARD_ARIZONA_XII 12 +#define RMI_XLR_BOARD_ARIZONA_I 1 +#define RMI_XLR_BOARD_ARIZONA_II 2 +#define RMI_XLR_BOARD_ARIZONA_III 3 +#define RMI_XLR_BOARD_ARIZONA_IV 4 +#define RMI_XLR_BOARD_ARIZONA_V 5 +#define RMI_XLR_BOARD_ARIZONA_VI 6 +#define RMI_XLR_BOARD_ARIZONA_VII 7 +#define RMI_XLR_BOARD_ARIZONA_VIII 8 +#define RMI_XLR_BOARD_ARIZONA_XI 11 +#define RMI_XLR_BOARD_ARIZONA_XII 12 /* * RMI Chips - Values in Processor ID field @@ -55,24 +55,39 @@ #define RMI_CHIP_XLR308 0x06 #define RMI_CHIP_XLR532 0x09 -#define RMI_CHIP_XLS616_B0 0x40 -#define RMI_CHIP_XLS608_B0 0x4a -#define RMI_CHIP_XLS608 0x80 /* Internal */ -#define RMI_CHIP_XLS416_B0 0x44 -#define RMI_CHIP_XLS412_B0 0x4c -#define RMI_CHIP_XLS408_B0 0x4e -#define RMI_CHIP_XLS408 0x88 /* Lite "Condor" */ -#define RMI_CHIP_XLS404_B0 0x4f -#define RMI_CHIP_XLS404 0x8c /* Lite "Condor" */ -#define RMI_CHIP_XLS208 0x8e -#define RMI_CHIP_XLS204 0x8f -#define RMI_CHIP_XLS108 0xce -#define RMI_CHIP_XLS104 0xcf +/* + * XLR C revisions + */ +#define RMI_CHIP_XLR308_C 0x0F +#define RMI_CHIP_XLR508_C 0x0b +#define RMI_CHIP_XLR516_C 0x0a +#define RMI_CHIP_XLR532_C 0x08 + +/* + * XLS processors + */ +#define RMI_CHIP_XLS408 0x88 /* Lite "Condor" */ +#define RMI_CHIP_XLS608 0x80 /* Internal */ +#define RMI_CHIP_XLS404 0x8c /* Lite "Condor" */ +#define RMI_CHIP_XLS208 0x8e +#define RMI_CHIP_XLS204 0x8f +#define RMI_CHIP_XLS108 0xce +#define RMI_CHIP_XLS104 0xcf + +/* + * XLS B revision chips + */ +#define RMI_CHIP_XLS616_B0 0x40 +#define RMI_CHIP_XLS608_B0 0x4a +#define RMI_CHIP_XLS416_B0 0x44 +#define RMI_CHIP_XLS412_B0 0x4c +#define RMI_CHIP_XLS408_B0 0x4e +#define RMI_CHIP_XLS404_B0 0x4f /* * The XLS product line has chip versions 0x4x and 0x8x */ -static __inline__ unsigned int +static __inline unsigned int xlr_is_xls(void) { uint32_t prid = mips_rd_prid(); @@ -84,33 +99,65 @@ xlr_is_xls(void) /* * The last byte of the processor id field is revision */ -static __inline__ unsigned int +static __inline unsigned int xlr_revision(void) { - return mips_rd_prid() & 0xff; + + return (mips_rd_prid() & 0xff); } /* * The 15:8 byte of the PR Id register is the Processor ID */ -static __inline__ unsigned int +static __inline unsigned int xlr_processor_id(void) { + return ((mips_rd_prid() & 0xff00) >> 8); } +/* + * The processor is XLR and C-Series + */ +static __inline unsigned int +xlr_is_c_revision(void) +{ + int processor_id = xlr_processor_id(); + int revision_id = xlr_revision(); + + switch (processor_id) { + /* + * These are the relevant PIDs for XLR + * steppings (hawk and above). For these, + * PIDs, Rev-Ids of [5-9] indicate 'C'. + */ + case RMI_CHIP_XLR308_C: + case RMI_CHIP_XLR508_C: + case RMI_CHIP_XLR516_C: + case RMI_CHIP_XLR532_C: + case RMI_CHIP_XLR716: + case RMI_CHIP_XLR732: + if (revision_id >= 5 && revision_id <= 9) + return (1); + default: + return (0); + } + return (0); +} + /* * RMI Engineering boards which are PCI cards * These should come up in PCI device mode (not yet) */ -static __inline__ int -xlr_board_pci(void) +static __inline int +xlr_board_pci(int board_major) { - return ((xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_III) || - (xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_V)); + + return ((board_major == RMI_XLR_BOARD_ARIZONA_III) || + (board_major == RMI_XLR_BOARD_ARIZONA_V)); } -static __inline__ int +static __inline int xlr_is_xls1xx(void) { uint32_t chipid = xlr_processor_id(); @@ -118,7 +165,7 @@ xlr_is_xls1xx(void) return (chipid == 0xce || chipid == 0xcf); } -static __inline__ int +static __inline int xlr_is_xls2xx(void) { uint32_t chipid = xlr_processor_id(); @@ -126,7 +173,7 @@ xlr_is_xls2xx(void) return (chipid == 0x8e || chipid == 0x8f); } -static __inline__ int +static __inline int xlr_is_xls4xx_lite(void) { uint32_t chipid = xlr_processor_id(); @@ -134,38 +181,59 @@ xlr_is_xls4xx_lite(void) return (chipid == 0x88 || chipid == 0x8c); } -/* all our knowledge of chip and board that cannot be detected run-time goes here */ -enum gmac_block_types { - XLR_GMAC, XLR_XGMAC, XLR_SPI4 -}; +static __inline unsigned int +xlr_is_xls_b0(void) +{ + uint32_t chipid = xlr_processor_id(); -enum gmac_block_modes { - XLR_RGMII, XLR_SGMII, XLR_PORT0_RGMII -}; + return (chipid >= 0x40 && chipid <= 0x4f); +} + +/* SPI-4 --> 8 ports, 1G MAC --> 4 ports and 10G MAC --> 1 port */ +#define MAX_NA_PORTS 8 + +/* all our knowledge of chip and board that cannot be detected run-time goes here */ +enum gmac_block_types { XLR_GMAC, XLR_XGMAC, XLR_SPI4}; +enum gmac_port_types { XLR_RGMII, XLR_SGMII, XLR_PORT0_RGMII, XLR_XGMII, XLR_XAUI }; struct xlr_board_info { int is_xls; int nr_cpus; - int usb; /* usb enabled ? */ - int cfi; /* compact flash driver for NOR? */ + int usb; /* usb enabled ? */ + int cfi; /* compact flash driver for NOR? */ + int ata; /* ata driver */ int pci_irq; - struct stn_cc **credit_configs; /* pointer to Core station credits */ - struct bucket_size *bucket_sizes; /* pointer to Core station - * bucket */ - int *msgmap; /* mapping of message station to devices */ - int gmacports; /* number of gmac ports on the board */ - struct xlr_gmac_block_t { - int type; /* see enum gmac_block_types */ - unsigned int enabled; /* mask of ports enabled */ - struct stn_cc *credit_config; /* credit configuration */ - int station_txbase; /* station id for tx */ - int station_rfr;/* free desc bucket */ - int mode; /* see gmac_block_modes */ - uint32_t baseaddr; /* IO base */ - int baseirq; /* first irq for this block, the rest are in - * sequence */ - int baseinst; /* the first rge unit for this block */ - } gmac_block[3]; + struct stn_cc **credit_configs; /* pointer to Core station credits */ + struct bucket_size *bucket_sizes; /* pointer to Core station bucket */ + int *msgmap; /* mapping of message station to devices */ + int gmacports; /* number of gmac ports on the board */ + struct xlr_gmac_block_t { /* refers to the set of GMACs controlled by a + network accelarator */ + int type; /* see enum gmac_block_types */ + unsigned int enabled; /* mask of ports enabled */ + struct stn_cc *credit_config; /* credit configuration */ + int station_id; /* station id for sending msgs */ + int station_txbase; /* station id for tx */ + int station_rfr; /* free desc bucket */ + int mode; /* see gmac_block_modes */ + uint32_t baseaddr; /* IO base */ + int baseirq; /* first irq for this block, the rest are in sequence */ + int baseinst; /* the first rge unit for this block */ + int num_ports; + struct xlr_gmac_port { + int valid; + int type; /* see enum gmac_port_types */ + uint32_t instance; /* identifies the GMAC to which + this port is bound to. */ + uint32_t phy_addr; + uint32_t base_addr; + uint32_t mii_addr; + uint32_t pcs_addr; + uint32_t serdes_addr; + uint32_t tx_bucket_id; + uint32_t mdint_id; + } gmac_port[MAX_NA_PORTS]; + } gmac_block [3]; }; extern struct xlr_board_info xlr_board_info; diff --git a/sys/mips/rmi/clock.c b/sys/mips/rmi/clock.c deleted file mode 100644 index c123edf589e..00000000000 --- a/sys/mips/rmi/clock.c +++ /dev/null @@ -1,356 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - * - * RMI_BSD - */ - -#include /* RCS ID & Copyright macro defns */ -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef XLR_PERFMON -#include -#endif - -uint64_t counter_freq; -uint64_t cycles_per_tick; -uint64_t cycles_per_usec; -uint64_t cycles_per_sec; -uint64_t cycles_per_hz; - -u_int32_t counter_upper = 0; -u_int32_t counter_lower_last = 0; - -#define STAT_PROF_CLOCK_SCALE_FACTOR 8 - -static int scale_factor; -static int count_scale_factor[32]; - -uint64_t -platform_get_frequency() -{ - return XLR_PIC_HZ; -} - -void -mips_timer_early_init(uint64_t clock_hz) -{ - /* Initialize clock early so that we can use DELAY sooner */ - counter_freq = clock_hz; - cycles_per_usec = (clock_hz / (1000 * 1000)); - -} - -/* -* count_compare_clockhandler: -* -* Handle the clock interrupt when count becomes equal to -* compare. -*/ -int -count_compare_clockhandler(struct trapframe *tf) -{ - int cpu = PCPU_GET(cpuid); - uint32_t cycles; - - critical_enter(); - - if (cpu == 0) { - mips_wr_compare(0); - } else { - count_scale_factor[cpu]++; - cycles = mips_rd_count(); - cycles += XLR_CPU_HZ / hz; - mips_wr_compare(cycles); - - hardclock_cpu(TRAPF_USERMODE(tf)); - if (count_scale_factor[cpu] == STAT_PROF_CLOCK_SCALE_FACTOR) { - statclock(TRAPF_USERMODE(tf)); - if (profprocs != 0) { - profclock(TRAPF_USERMODE(tf), tf->pc); - } - count_scale_factor[cpu] = 0; - } - /* If needed , handle count compare tick skew here */ - } - - critical_exit(); - return (FILTER_HANDLED); -} - -unsigned long clock_tick_foo=0; - -int -pic_hardclockhandler(struct trapframe *tf) -{ - int cpu = PCPU_GET(cpuid); - - critical_enter(); - - if (cpu == 0) { - scale_factor++; - clock_tick_foo++; -/* - if ((clock_tick_foo % 10000) == 0) { - printf("Clock tick foo at %ld\n", clock_tick_foo); - } -*/ - hardclock(TRAPF_USERMODE(tf), tf->pc); - if (scale_factor == STAT_PROF_CLOCK_SCALE_FACTOR) { - statclock(TRAPF_USERMODE(tf)); - if (profprocs != 0) { - profclock(TRAPF_USERMODE(tf), tf->pc); - } - scale_factor = 0; - } -#ifdef XLR_PERFMON - if (xlr_perfmon_started) - xlr_perfmon_clockhandler(); -#endif - - } else { - /* If needed , handle count compare tick skew here */ - } - critical_exit(); - return (FILTER_HANDLED); -} - -int -pic_timecounthandler(struct trapframe *tf) -{ - return (FILTER_HANDLED); -} - -void -rmi_early_counter_init() -{ - int cpu = PCPU_GET(cpuid); - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - - /* - * We do this to get the PIC time counter running right after system - * start. Otherwise the DELAY() function will not be able to work - * since it won't have a TC to read. - */ - xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_0, (0xffffffff & 0xffffffff)); - xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_1, (0xffffffff & 0xffffffff)); - xlr_write_reg(mmio, PIC_IRT_0_TIMER_6, (1 << cpu)); - xlr_write_reg(mmio, PIC_IRT_1_TIMER_6, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_6_IRQ)); - pic_update_control(1 << (8 + 6), 0); -} - -void tick_init(void); - -void -platform_initclocks(void) -{ - int cpu = PCPU_GET(cpuid); - void *cookie; - - /* - * Note: Passing #3 as NULL ensures that clockhandler gets called - * with trapframe - */ - /* profiling/process accounting timer interrupt for non-zero cpus */ - cpu_establish_hardintr("compare", - (driver_filter_t *) count_compare_clockhandler, - NULL, - NULL, - IRQ_TIMER, - INTR_TYPE_CLK | INTR_FAST, &cookie); - - /* timekeeping timer interrupt for cpu 0 */ - cpu_establish_hardintr("hardclk", - (driver_filter_t *) pic_hardclockhandler, - NULL, - NULL, - PIC_TIMER_7_IRQ, - INTR_TYPE_CLK | INTR_FAST, - &cookie); - - /* this is used by timecounter */ - cpu_establish_hardintr("timecount", - (driver_filter_t *) pic_timecounthandler, NULL, - NULL, PIC_TIMER_6_IRQ, INTR_TYPE_CLK | INTR_FAST, - &cookie); - - if (cpu == 0) { - __uint64_t maxval = XLR_PIC_HZ / hz; - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - - stathz = hz / STAT_PROF_CLOCK_SCALE_FACTOR; - profhz = stathz; - - /* Setup PIC Interrupt */ - - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - xlr_write_reg(mmio, PIC_TIMER_7_MAXVAL_0, (maxval & 0xffffffff)); /* 0x100 + 7 */ - xlr_write_reg(mmio, PIC_TIMER_7_MAXVAL_1, (maxval >> 32) & 0xffffffff); /* 0x110 + 7 */ - /* 0x40 + 8 */ - /* reg 40 is lower bits 31-0 and holds CPU mask */ - xlr_write_reg(mmio, PIC_IRT_0_TIMER_7, (1 << cpu)); - /* 0x80 + 8 */ - /* Reg 80 is upper bits 63-32 and holds */ - /* Valid Edge Local IRQ */ - xlr_write_reg(mmio, PIC_IRT_1_TIMER_7, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_7_IRQ)); - - pic_update_control(1 << (8 + 7), 1); - xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_0, (0xffffffff & 0xffffffff)); - xlr_write_reg(mmio, PIC_TIMER_6_MAXVAL_1, (0xffffffff & 0xffffffff)); - xlr_write_reg(mmio, PIC_IRT_0_TIMER_6, (1 << cpu)); - xlr_write_reg(mmio, PIC_IRT_1_TIMER_6, (1 << 31) | (0 << 30) | (1 << 6) | (PIC_TIMER_6_IRQ)); - pic_update_control(1 << (8 + 6), 1); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - } else { - /* Setup count-compare interrupt for vcpu[1-31] */ - mips_wr_compare((xlr_boot1_info.cpu_frequency) / hz); - } - tick_init(); -} - -unsigned -__attribute__((no_instrument_function)) -platform_get_timecount(struct timecounter *tc __unused) -{ - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - - return 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_0); -} - -void -DELAY(int n) -{ - uint32_t cur, last, delta, usecs; - - /* - * This works by polling the timer and counting the number of - * microseconds that go by. - */ - last = platform_get_timecount(NULL); - delta = usecs = 0; - - while (n > usecs) { - cur = platform_get_timecount(NULL); - - /* Check to see if the timer has wrapped around. */ - if (cur < last) - delta += (cur + (cycles_per_hz - last)); - else - delta += (cur - last); - - last = cur; - - if (delta >= cycles_per_usec) { - usecs += delta / cycles_per_usec; - delta %= cycles_per_usec; - } - } -} - -static -uint64_t -read_pic_counter(void) -{ - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - uint32_t lower, upper; - uint64_t tc; - - /* - * Pull the value of the 64 bit counter which is stored in PIC - * register 120+N and 130+N - */ - upper = 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_1); - lower = 0xffffffffU - xlr_read_reg(mmio, PIC_TIMER_6_COUNTER_0); - tc = (((uint64_t) upper << 32) | (uint64_t) lower); - return (tc); -} - -extern struct timecounter counter_timecounter; - -void -mips_timer_init_params(uint64_t platform_counter_freq, int double_count) -{ - - /* - * XXX: Do not use printf here: uart code 8250 may use DELAY so this - * function should be called before cninit. - */ - counter_freq = platform_counter_freq; - /* - * XXX: Some MIPS32 cores update the Count register only every two - * pipeline cycles. - */ - if (double_count != 0) - counter_freq /= 2; - - cycles_per_tick = counter_freq / 1000; - cycles_per_hz = counter_freq / hz; - cycles_per_usec = counter_freq / (1 * 1000 * 1000); - cycles_per_sec = counter_freq; - - counter_timecounter.tc_frequency = counter_freq; - printf("hz=%d cyl_per_hz:%jd cyl_per_usec:%jd freq:%jd cyl_per_hz:%jd cyl_per_sec:%jd\n", - hz, - cycles_per_tick, - cycles_per_usec, - counter_freq, - cycles_per_hz, - cycles_per_sec - ); - set_cputicker(read_pic_counter, counter_freq, 1); -} diff --git a/sys/mips/rmi/dev/nlge/if_nlge.c b/sys/mips/rmi/dev/nlge/if_nlge.c new file mode 100644 index 00000000000..37e1c54c3c1 --- /dev/null +++ b/sys/mips/rmi/dev/nlge/if_nlge.c @@ -0,0 +1,2564 @@ +/*- + * Copyright (c) 2003-2009 RMI Corporation + * 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 RMI Corporation, 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 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. + * + * RMI_BSD */ + +/* + * The XLR device supports upto four 10/100/1000 Ethernet MACs and upto + * two 10G Ethernet MACs (of XGMII). Alternatively, each 10G port can used + * as a SPI-4 interface, with 8 ports per such interface. The MACs are + * encapsulated in another hardware block referred to as network accelerator, + * such that there are three instances of these in a XLR. One of them controls + * the four 1G RGMII ports while one each of the others controls an XGMII port. + * Enabling MACs requires configuring the corresponding network accelerator + * and the individual port. + * The XLS device supports upto 8 10/100/1000 Ethernet MACs or max 2 10G + * Ethernet MACs. The 1G MACs are of SGMII and 10G MACs are of XAUI + * interface. These ports are part of two network accelerators. + * The nlge driver configures and initializes non-SPI4 Ethernet ports in the + * XLR/XLS devices and enables data transfer on them. + */ + +#include +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_device_polling.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __RMAN_RESOURCE_VISIBLE +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* for DELAY */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "miidevs.h" +#include +#include "miibus_if.h" + +#include + +MODULE_DEPEND(nlna, nlge, 1, 1, 1); +MODULE_DEPEND(nlge, ether, 1, 1, 1); +MODULE_DEPEND(nlge, miibus, 1, 1, 1); + +/* Network accelarator entry points */ +static int nlna_probe(device_t); +static int nlna_attach(device_t); +static int nlna_detach(device_t); +static int nlna_suspend(device_t); +static int nlna_resume(device_t); +static int nlna_shutdown(device_t); + +/* GMAC port entry points */ +static int nlge_probe(device_t); +static int nlge_attach(device_t); +static int nlge_detach(device_t); +static int nlge_suspend(device_t); +static int nlge_resume(device_t); +static void nlge_init(void *); +static int nlge_ioctl(struct ifnet *, u_long, caddr_t); +static void nlge_start(struct ifnet *); +static void nlge_rx(struct nlge_softc *sc, vm_paddr_t paddr, int len); + +static int nlge_mii_write(struct device *, int, int, int); +static int nlge_mii_read(struct device *, int, int); +static void nlge_mac_mii_statchg(device_t); +static int nlge_mediachange(struct ifnet *ifp); +static void nlge_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr); + +/* Other internal/helper functions */ +static void *get_buf(void); + +static void nlna_add_to_port_set(struct nlge_port_set *pset, + struct nlge_softc *sc); +static void nlna_config_pde(struct nlna_softc *); +static void nlna_config_parser(struct nlna_softc *); +static void nlna_config_classifier(struct nlna_softc *); +static void nlna_config_fifo_spill_area(struct nlna_softc *sc); +static void nlna_config_translate_table(struct nlna_softc *sc); +static void nlna_config_common(struct nlna_softc *); +static void nlna_disable_ports(struct nlna_softc *sc); +static void nlna_enable_intr(struct nlna_softc *sc); +static void nlna_disable_intr(struct nlna_softc *sc); +static void nlna_enable_ports(struct nlna_softc *sc); +static void nlna_get_all_softc(device_t iodi_dev, + struct nlna_softc **sc_vec, uint32_t vec_sz); +static void nlna_hw_init(struct nlna_softc *sc); +static int nlna_is_last_active_na(struct nlna_softc *sc); +static void nlna_media_specific_config(struct nlna_softc *sc); +static void nlna_reset_ports(struct nlna_softc *sc, + struct xlr_gmac_block_t *blk); +static struct nlna_softc *nlna_sc_init(device_t dev, + struct xlr_gmac_block_t *blk); +static void nlna_setup_intr(struct nlna_softc *sc); +static void nlna_smp_update_pde(void *dummy __unused); +static void nlna_submit_rx_free_desc(struct nlna_softc *sc, + uint32_t n_desc); + +static int nlge_gmac_config_speed(struct nlge_softc *, int quick); +static void nlge_hw_init(struct nlge_softc *sc); +static int nlge_if_init(struct nlge_softc *sc); +static void nlge_intr(void *arg); +static int nlge_irq_init(struct nlge_softc *sc); +static void nlge_irq_fini(struct nlge_softc *sc); +static void nlge_media_specific_init(struct nlge_softc *sc); +static void nlge_mii_init(device_t dev, struct nlge_softc *sc); +static int nlge_mii_read_internal(xlr_reg_t *mii_base, int phyaddr, + int regidx); +static void nlge_mii_write_internal(xlr_reg_t *mii_base, int phyaddr, + int regidx, int regval); +void nlge_msgring_handler(int bucket, int size, int code, + int stid, struct msgrng_msg *msg, void *data); +static void nlge_port_disable(struct nlge_softc *sc); +static void nlge_port_enable(struct nlge_softc *sc); +static void nlge_read_mac_addr(struct nlge_softc *sc); +static void nlge_sc_init(struct nlge_softc *sc, device_t dev, + struct xlr_gmac_port *port_info); +static void nlge_set_mac_addr(struct nlge_softc *sc); +static void nlge_set_port_attribs(struct nlge_softc *, + struct xlr_gmac_port *); +static void nlge_mac_set_rx_mode(struct nlge_softc *sc); +static void nlge_sgmii_init(struct nlge_softc *sc); +static void nlge_start_locked(struct ifnet *ifp, struct nlge_softc *sc); + +static int prepare_fmn_message(struct nlge_softc *sc, + struct msgrng_msg *msg, uint32_t *n_entries, struct mbuf *m_head, + uint64_t fr_stid, struct nlge_tx_desc **tx_desc); + +static void release_tx_desc(vm_paddr_t phy_addr); +static int send_fmn_msg_tx(struct nlge_softc *, struct msgrng_msg *, + uint32_t n_entries); + +static void +nl_tx_q_wakeup(void *addr); + +//#define DEBUG +#ifdef DEBUG +static int mac_debug = 1; +static int reg_dump = 0; +#undef PDEBUG +#define PDEBUG(fmt, args...) \ + do {\ + if (mac_debug) {\ + printf("[%s@%d|%s]: cpu_%d: " fmt, \ + __FILE__, __LINE__, __FUNCTION__, PCPU_GET(cpuid), ##args);\ + }\ + } while(0); + +/* Debug/dump functions */ +static void dump_reg(xlr_reg_t *addr, uint32_t offset, char *name); +static void dump_gmac_registers(struct nlge_softc *); +static void dump_na_registers(xlr_reg_t *base, int port_id); +static void dump_mac_stats(struct nlge_softc *sc); +static void dump_mii_regs(struct nlge_softc *sc) __attribute__((used)); +static void dump_mii_data(struct mii_data *mii) __attribute__((used)); +static void dump_board_info(struct xlr_board_info *); +static void dump_pcs_regs(struct nlge_softc *sc, int phy); + +#else +#undef PDEBUG +#define PDEBUG(fmt, args...) +#define dump_reg(a, o, n) /* nop */ +#define dump_gmac_registers(a) /* nop */ +#define dump_na_registers(a, p) /* nop */ +#define dump_board_info(b) /* nop */ +#define dump_mac_stats(sc) /* nop */ +#define dump_mii_regs(sc) /* nop */ +#define dump_mii_data(mii) /* nop */ +#define dump_pcs_regs(sc, phy) /* nop */ +#endif + +/* Wrappers etc. to export the driver entry points. */ +static device_method_t nlna_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, nlna_probe), + DEVMETHOD(device_attach, nlna_attach), + DEVMETHOD(device_detach, nlna_detach), + DEVMETHOD(device_shutdown, nlna_shutdown), + DEVMETHOD(device_suspend, nlna_suspend), + DEVMETHOD(device_resume, nlna_resume), + + /* bus interface : TBD : what are these for ? */ + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + { 0, 0 } +}; + +static driver_t nlna_driver = { + "nlna", + nlna_methods, + sizeof(struct nlna_softc) +}; + +static devclass_t nlna_devclass; + +static device_method_t nlge_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, nlge_probe), + DEVMETHOD(device_attach, nlge_attach), + DEVMETHOD(device_detach, nlge_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, nlge_suspend), + DEVMETHOD(device_resume, nlge_resume), + + /* MII interface */ + DEVMETHOD(miibus_readreg, nlge_mii_read), + DEVMETHOD(miibus_writereg, nlge_mii_write), + DEVMETHOD(miibus_statchg, nlge_mac_mii_statchg), + + {0, 0} +}; + +static driver_t nlge_driver = { + "nlge", + nlge_methods, + sizeof(struct nlge_softc) +}; + +static devclass_t nlge_devclass; + +DRIVER_MODULE(nlna, iodi, nlna_driver, nlna_devclass, 0, 0); +DRIVER_MODULE(nlge, nlna, nlge_driver, nlge_devclass, 0, 0); +DRIVER_MODULE(miibus, nlge, miibus_driver, miibus_devclass, 0, 0); + +static uma_zone_t nl_tx_desc_zone; + +/* Tunables. */ +static int flow_classification = 0; +TUNABLE_INT("hw.nlge.flow_classification", &flow_classification); + +static __inline void +atomic_incr_long(unsigned long *addr) +{ + /* XXX: fix for 64 bit */ + unsigned int *iaddr = (unsigned int *)addr; + + xlr_ldaddwu(1, iaddr); +} + +static int +nlna_probe(device_t dev) +{ + return (BUS_PROBE_DEFAULT); +} + +/* + * Add all attached GMAC/XGMAC ports to the device tree. Port + * configuration is spread in two regions - common configuration + * for all ports in the NA and per-port configuration in MAC-specific + * region. This function does the following: + * - adds the ports to the device tree + * - reset the ports + * - do all the common initialization + * - invoke bus_generic_attach for per-port configuration + * - supply initial free rx descriptors to ports + * - initialize s/w data structures + * - finally, enable interrupts (only in the last NA). + * + * For reference, sample address space for common and per-port + * registers is given below. + * + * The address map for RNA0 is: (typical value) + * + * XLR_IO_BASE +--------------------------------------+ 0xbef0_0000 + * | | + * | | + * | | + * | | + * | | + * | | + * GMAC0 ---> +--------------------------------------+ 0xbef0_c000 + * | | + * | | + * (common) -> |......................................| 0xbef0_c400 + * | | + * | (RGMII/SGMII: common registers) | + * | | + * GMAC1 ---> |--------------------------------------| 0xbef0_d000 + * | | + * | | + * (common) -> |......................................| 0xbef0_d400 + * | | + * | (RGMII/SGMII: common registers) | + * | | + * |......................................| + * and so on .... + * + * Ref: Figure 14-3 and Table 14-1 of XLR PRM + */ +static int +nlna_attach(device_t dev) +{ + struct xlr_gmac_block_t *block_info; + device_t gmac_dev; + struct nlna_softc *sc; + int error; + int i; + int id; + + id = device_get_unit(dev); + block_info = device_get_ivars(dev); + if (!block_info->enabled) { + return 0; + } + +#ifdef DEBUG + dump_board_info(&xlr_board_info); +#endif + /* Initialize nlna state in softc structure */ + sc = nlna_sc_init(dev, block_info); + + /* Add device's for the ports controlled by this NA. */ + if (block_info->type == XLR_GMAC) { + KASSERT(id < 2, ("No GMACs supported with this network" + "accelerator: %d", id)); + for (i = 0; i < sc->num_ports; i++) { + gmac_dev = device_add_child(dev, "nlge", -1); + device_set_ivars(gmac_dev, &block_info->gmac_port[i]); + } + } else if (block_info->type == XLR_XGMAC) { + KASSERT(id > 0 && id <= 2, ("No XGMACs supported with this" + "network accelerator: %d", id)); + gmac_dev = device_add_child(dev, "nlge", -1); + device_set_ivars(gmac_dev, &block_info->gmac_port[0]); + } else if (block_info->type == XLR_SPI4) { + /* SPI4 is not supported here */ + device_printf(dev, "Unsupported: NA with SPI4 type"); + return (ENOTSUP); + } + + nlna_reset_ports(sc, block_info); + + /* Initialize Network Accelarator registers. */ + nlna_hw_init(sc); + + error = bus_generic_attach(dev); + if (error) { + device_printf(dev, "failed to attach port(s)\n"); + goto fail; + } + + /* Send out the initial pool of free-descriptors for the rx path */ + nlna_submit_rx_free_desc(sc, MAX_FRIN_SPILL); + + /* S/w data structure initializations shared by all NA's. */ + if (nl_tx_desc_zone == NULL) { + /* Create a zone for allocating tx descriptors */ + nl_tx_desc_zone = uma_zcreate("NL Tx Desc", + sizeof(struct nlge_tx_desc), NULL, NULL, NULL, NULL, + XLR_CACHELINE_SIZE, 0); + } + + /* Other per NA s/w initialization */ + callout_init(&sc->tx_thr, CALLOUT_MPSAFE); + callout_reset(&sc->tx_thr, hz, nl_tx_q_wakeup, sc); + + /* Enable NA interrupts */ + nlna_setup_intr(sc); + + return (0); + +fail: + return (error); +} + +static int +nlna_detach(device_t dev) +{ + struct nlna_softc *sc; + + sc = device_get_softc(dev); + if (device_is_alive(dev)) { + nlna_disable_intr(sc); + /* This will make sure that per-port detach is complete + * and all traffic on the ports has been stopped. */ + bus_generic_detach(dev); + uma_zdestroy(nl_tx_desc_zone); + } + + return (0); +} + +static int +nlna_suspend(device_t dev) +{ + + return (0); +} + +static int +nlna_resume(device_t dev) +{ + + return (0); +} + +static int +nlna_shutdown(device_t dev) +{ + return (0); +} + + +/* GMAC port entry points */ +static int +nlge_probe(device_t dev) +{ + struct nlge_softc *sc; + struct xlr_gmac_port *port_info; + int index; + char *desc[] = { "RGMII", "SGMII", "RGMII/SGMII", "XGMAC", "XAUI", + "Unknown"}; + + port_info = device_get_ivars(dev); + index = (port_info->type < XLR_RGMII || port_info->type > XLR_XAUI) ? + 5 : port_info->type; + device_set_desc_copy(dev, desc[index]); + + sc = device_get_softc(dev); + nlge_sc_init(sc, dev, port_info); + + nlge_port_disable(sc); + + return (0); +} + +static int +nlge_attach(device_t dev) +{ + struct nlge_softc *sc; + struct nlna_softc *nsc; + int error; + + sc = device_get_softc(dev); + + nlge_if_init(sc); + nlge_mii_init(dev, sc); + error = nlge_irq_init(sc); + if (error) + return error; + nlge_hw_init(sc); + + nsc = (struct nlna_softc *)device_get_softc(device_get_parent(dev)); + nsc->child_sc[sc->instance] = sc; + + return (0); +} + +static int +nlge_detach(device_t dev) +{ + struct nlge_softc *sc; + struct ifnet *ifp; + + sc = device_get_softc(dev); + ifp = sc->nlge_if; + + if (device_is_attached(dev)) { + nlge_port_disable(sc); + nlge_irq_fini(sc); + ether_ifdetach(ifp); + bus_generic_detach(dev); + } + if (ifp) + if_free(ifp); + + return (0); +} + +static int +nlge_suspend(device_t dev) +{ + return (0); +} + +static int +nlge_resume(device_t dev) +{ + return (0); +} + +static void +nlge_init(void *addr) +{ + struct nlge_softc *sc; + struct ifnet *ifp; + + sc = (struct nlge_softc *)addr; + ifp = sc->nlge_if; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + return; + + nlge_gmac_config_speed(sc, 1); + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + nlge_port_enable(sc); + + if (sc->port_type == XLR_SGMII) { + dump_pcs_regs(sc, 27); + } + dump_gmac_registers(sc); + dump_mac_stats(sc); +} + +static int +nlge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct mii_data *mii; + struct nlge_softc *sc; + struct ifreq *ifr; + int error; + + sc = ifp->if_softc; + error = 0; + ifr = (struct ifreq *)data; + + switch(command) { + case SIOCSIFFLAGS: + NLGE_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + nlge_init(sc); + } + if (ifp->if_flags & IFF_PROMISC && + !(sc->if_flags & IFF_PROMISC)) { + sc->if_flags |= IFF_PROMISC; + nlge_mac_set_rx_mode(sc); + } else if (!(ifp->if_flags & IFF_PROMISC) && + sc->if_flags & IFF_PROMISC) { + sc->if_flags &= IFF_PROMISC; + nlge_mac_set_rx_mode(sc); + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + nlge_port_disable(sc); + } + } + sc->if_flags = ifp->if_flags; + NLGE_UNLOCK(sc); + error = 0; + break; + + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + if (sc->mii_bus != NULL) { + mii = (struct mii_data *)device_get_softc(sc->mii_bus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, + command); + } + break; + + default: + error = ether_ioctl(ifp, command, data); + break; + } + + return (error); +} + +/* This function is called from an interrupt handler */ +void +nlge_msgring_handler(int bucket, int size, int code, int stid, + struct msgrng_msg *msg, void *data) +{ + struct nlna_softc *na_sc; + struct nlge_softc *sc; + struct ifnet *ifp; + struct mbuf *m; + vm_paddr_t phys_addr; + uint32_t length; + int ctrl; + int tx_error; + int port; + int is_p2p; + + is_p2p = 0; + tx_error = 0; + length = (msg->msg0 >> 40) & 0x3fff; + na_sc = (struct nlna_softc *)data; + if (length == 0) { + ctrl = CTRL_REG_FREE; + phys_addr = msg->msg0 & 0xffffffffffULL; + port = (msg->msg0 >> 54) & 0x0f; + is_p2p = (msg->msg0 >> 62) & 0x1; + tx_error = (msg->msg0 >> 58) & 0xf; + } else { + ctrl = CTRL_SNGL; + phys_addr = msg->msg0 & 0xffffffffe0ULL; + length = length - BYTE_OFFSET - MAC_CRC_LEN; + port = msg->msg0 & 0x0f; + } + + sc = na_sc->child_sc[port]; + if (sc == NULL) { + printf("Message (of %d len) with softc=NULL on %d port (type=%s)\n", + length, port, (ctrl == CTRL_SNGL ? "Pkt rx" : + "Freeback for tx packet")); + return; + } + + if (ctrl == CTRL_REG_FREE || ctrl == CTRL_JUMBO_FREE) { + ifp = sc->nlge_if; + if (!tx_error) { + if (is_p2p) { + release_tx_desc(phys_addr); + } else { +#ifdef __mips_n64 + m = (struct mbuf *)(uintptr_t)xlr_paddr_ld(phys_addr); + m->m_nextpkt = NULL; +#else + m = (struct mbuf *)(uintptr_t)phys_addr; +#endif + m_freem(m); + } + NLGE_LOCK(sc); + if (ifp->if_drv_flags & IFF_DRV_OACTIVE){ + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + callout_reset(&na_sc->tx_thr, hz, + nl_tx_q_wakeup, na_sc); + } + NLGE_UNLOCK(sc); + } else { + printf("ERROR: Tx fb error (%d) on port %d\n", tx_error, + port); + } + atomic_incr_long((tx_error) ? &ifp->if_oerrors: &ifp->if_opackets); + } else if (ctrl == CTRL_SNGL || ctrl == CTRL_START) { + /* Rx Packet */ + + nlge_rx(sc, phys_addr, length); + nlna_submit_rx_free_desc(na_sc, 1); /* return free descr to NA */ + } else { + printf("[%s]: unrecognized ctrl=%d!\n", __func__, ctrl); + } + +} + +static void +nlge_start(struct ifnet *ifp) +{ + struct nlge_softc *sc; + + sc = ifp->if_softc; + //NLGE_LOCK(sc); + nlge_start_locked(ifp, sc); + //NLGE_UNLOCK(sc); +} + +static void +nl_tx_q_wakeup(void *addr) +{ + struct nlna_softc *na_sc; + struct nlge_softc *sc; + int i; + + na_sc = (struct nlna_softc *) addr; + for (i = 0; i < XLR_MAX_MACS; i++) { + sc = na_sc->child_sc[i]; + if (sc == NULL) + continue; + nlge_start_locked(sc->nlge_if, sc); + } + callout_reset(&na_sc->tx_thr, 5 * hz, nl_tx_q_wakeup, na_sc); +} + +static void +nlge_start_locked(struct ifnet *ifp, struct nlge_softc *sc) +{ + struct msgrng_msg msg; + struct mbuf *m; + struct nlge_tx_desc *tx_desc; + uint64_t fr_stid; + uint32_t cpu; + uint32_t n_entries; + uint32_t tid; + int ret; + + cpu = xlr_core_id(); + tid = xlr_thr_id(); + /* H/w threads [0, 2] --> bucket 6 and [1, 3] --> bucket 7 */ + fr_stid = cpu * 8 + 6 + (tid % 2); + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + return; + } + + do { + /* + * First, remove some freeback messages before transmitting + * any new packets. However, cap the number of messages + * drained to permit this thread to continue with its + * transmission. + * + * Mask for buckets {6, 7} is 0xc0 + */ + xlr_msgring_handler(0xc0, 4); + + /* Grab a packet off the queue. */ + IF_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) { + return; + } + + tx_desc = NULL; + ret = prepare_fmn_message(sc, &msg, &n_entries, m, fr_stid, &tx_desc); + if (ret) { + goto fail; + } + ret = send_fmn_msg_tx(sc, &msg, n_entries); + if (ret != 0) { + goto fail; + } + } while(1); + + return; + +fail: + if (tx_desc != NULL) { + uma_zfree(nl_tx_desc_zone, tx_desc); + } + if (m != NULL) { + NLGE_LOCK(sc); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + NLGE_UNLOCK(sc); + IF_PREPEND(&ifp->if_snd, m); + atomic_incr_long(&ifp->if_iqdrops); + } + return; +} + +static void +nlge_rx(struct nlge_softc *sc, vm_paddr_t paddr, int len) +{ + struct ifnet *ifp; + struct mbuf *m; + uint64_t tm, mag; + uint32_t sr; + + sr = xlr_enable_kx(); + tm = xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE); + mag = xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE + sizeof(uint64_t)); + xlr_restore_kx(sr); + + m = (struct mbuf *)(intptr_t)tm; + if (mag != 0xf00bad) { + /* somebody else's packet. Error - FIXME in intialization */ + printf("cpu %d: *ERROR* Not my packet paddr %jx\n", + xlr_core_id(), (uintmax_t)paddr); + return; + } + + ifp = sc->nlge_if; + + /* align the data */ + m->m_data += BYTE_OFFSET; + m->m_pkthdr.len = m->m_len = len; + m->m_pkthdr.rcvif = ifp; + + atomic_incr_long(&ifp->if_ipackets); + (*ifp->if_input)(ifp, m); +} + +static int +nlge_mii_write(struct device *dev, int phyaddr, int regidx, int regval) +{ + struct nlge_softc *sc; + + sc = device_get_softc(dev); + if (sc->port_type != XLR_XGMII) + nlge_mii_write_internal(sc->mii_base, phyaddr, regidx, regval); + + return (0); +} + +static int +nlge_mii_read(struct device *dev, int phyaddr, int regidx) +{ + struct nlge_softc *sc; + int val; + + sc = device_get_softc(dev); + val = (sc->port_type == XLR_XGMII) ? (0xffff) : + nlge_mii_read_internal(sc->mii_base, phyaddr, regidx); + + return (val); +} + +static void +nlge_mac_mii_statchg(device_t dev) +{ +} + +static int +nlge_mediachange(struct ifnet *ifp) +{ + return 0; +} + +static void +nlge_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct nlge_softc *sc; + struct mii_data *md; + + md = NULL; + sc = ifp->if_softc; + if (sc->mii_bus) + md = device_get_softc(sc->mii_bus); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (sc->link == xlr_mac_link_down) + return; + + if (md != NULL) + ifmr->ifm_active = md->mii_media.ifm_cur->ifm_media; + ifmr->ifm_status |= IFM_ACTIVE; +} + +static struct nlna_softc * +nlna_sc_init(device_t dev, struct xlr_gmac_block_t *blk) +{ + struct nlna_softc *sc; + + sc = device_get_softc(dev); + memset(sc, 0, sizeof(*sc)); + sc->nlna_dev = dev; + sc->base = xlr_io_mmio(blk->baseaddr); + sc->rfrbucket = blk->station_rfr; + sc->station_id = blk->station_id; + sc->na_type = blk->type; + sc->mac_type = blk->mode; + sc->num_ports = blk->num_ports; + + sc->mdio_set.port_vec = sc->mdio_sc; + sc->mdio_set.vec_sz = XLR_MAX_MACS; + + return (sc); +} + +/* + * Do: + * - Initialize common GMAC registers (index range 0x100-0x3ff). + */ +static void +nlna_hw_init(struct nlna_softc *sc) +{ + + /* + * Register message ring handler for the NA block, messages from + * the GMAC will have source station id to the first bucket of the + * NA FMN station, so register just that station id. + */ + if (register_msgring_handler(sc->station_id, sc->station_id + 1, + nlge_msgring_handler, sc)) { + panic("Couldn't register msgring handler\n"); + } + nlna_config_fifo_spill_area(sc); + nlna_config_pde(sc); + nlna_config_common(sc); + nlna_config_parser(sc); + nlna_config_classifier(sc); +} + +/* + * Enable interrupts on all the ports controlled by this NA. For now, we + * only care about the MII interrupt and this has to be enabled only + * on the port id0. + * + * This function is not in-sync with the regular way of doing things - it + * executes only in the context of the last active network accelerator (and + * thereby has some ugly accesses in the device tree). Though inelegant, it + * is necessary to do it this way as the per-port interrupts can be + * setup/enabled only after all the network accelerators have been + * initialized. + */ +static void +nlna_setup_intr(struct nlna_softc *sc) +{ + struct nlna_softc *na_sc[XLR_MAX_NLNA]; + struct nlge_port_set *pset; + struct xlr_gmac_port *port_info; + device_t iodi_dev; + int i, j; + + if (!nlna_is_last_active_na(sc)) + return ; + + /* Collect all nlna softc pointers */ + memset(na_sc, 0, sizeof(*na_sc) * XLR_MAX_NLNA); + iodi_dev = device_get_parent(sc->nlna_dev); + nlna_get_all_softc(iodi_dev, na_sc, XLR_MAX_NLNA); + + /* Setup the MDIO interrupt lists. */ + /* + * MDIO interrupts are coarse - a single interrupt line provides + * information about one of many possible ports. To figure out the + * exact port on which action is to be taken, all of the ports + * linked to an MDIO interrupt should be read. To enable this, + * ports need to add themselves to port sets. + */ + for (i = 0; i < XLR_MAX_NLNA; i++) { + if (na_sc[i] == NULL) + continue; + for (j = 0; j < na_sc[i]->num_ports; j++) { + /* processing j-th port on i-th NA */ + port_info = device_get_ivars( + na_sc[i]->child_sc[j]->nlge_dev); + pset = &na_sc[port_info->mdint_id]->mdio_set; + nlna_add_to_port_set(pset, na_sc[i]->child_sc[j]); + } + } + + /* Enable interrupts */ + for (i = 0; i < XLR_MAX_NLNA; i++) { + if (na_sc[i] != NULL && na_sc[i]->na_type != XLR_XGMAC) { + nlna_enable_intr(na_sc[i]); + } + } +} + +static void +nlna_add_to_port_set(struct nlge_port_set *pset, struct nlge_softc *sc) +{ + int i; + + /* step past the non-NULL elements */ + for (i = 0; i < pset->vec_sz && pset->port_vec[i] != NULL; i++) ; + if (i < pset->vec_sz) + pset->port_vec[i] = sc; + else + printf("warning: internal error: out-of-bounds for MDIO array"); +} + +static void +nlna_enable_intr(struct nlna_softc *sc) +{ + int i; + + for (i = 0; i < sc->num_ports; i++) { + if (sc->child_sc[i]->instance == 0) + NLGE_WRITE(sc->child_sc[i]->base, R_INTMASK, + (1 << O_INTMASK__MDInt)); + } +} + +static void +nlna_disable_intr(struct nlna_softc *sc) +{ + int i; + + for (i = 0; i < sc->num_ports; i++) { + if (sc->child_sc[i]->instance == 0) + NLGE_WRITE(sc->child_sc[i]->base, R_INTMASK, 0); + } +} + +static int +nlna_is_last_active_na(struct nlna_softc *sc) +{ + int id; + + id = device_get_unit(sc->nlna_dev); + return (id == 2 || xlr_board_info.gmac_block[id + 1].enabled == 0); +} + +static void +nlna_submit_rx_free_desc(struct nlna_softc *sc, uint32_t n_desc) +{ + struct msgrng_msg msg; + void *ptr; + uint32_t msgrng_flags; + int i, n, stid, ret, code; + + if (n_desc > 1) { + PDEBUG("Sending %d free-in descriptors to station=%d\n", n_desc, + sc->rfrbucket); + } + + stid = sc->rfrbucket; + code = (sc->na_type == XLR_XGMAC) ? MSGRNG_CODE_XGMAC : MSGRNG_CODE_MAC; + memset(&msg, 0, sizeof(msg)); + + for (i = 0; i < n_desc; i++) { + ptr = get_buf(); + if (!ptr) { + ret = -ENOMEM; + device_printf(sc->nlna_dev, "Cannot allocate mbuf\n"); + break; + } + + /* Send the free Rx desc to the MAC */ + msg.msg0 = vtophys(ptr) & 0xffffffffe0ULL; + n = 0; + do { + msgrng_flags = msgrng_access_enable(); + ret = message_send(1, code, stid, &msg); + msgrng_restore(msgrng_flags); + KASSERT(n++ < 100000, ("Too many credit fails in rx path\n")); + } while (ret != 0); + } +} + +static __inline__ void * +nlna_config_spill(xlr_reg_t *base, int reg_start_0, int reg_start_1, + int reg_size, int size) +{ + void *spill; + uint64_t phys_addr; + uint32_t spill_size; + + spill_size = size; + spill = contigmalloc((spill_size + XLR_CACHELINE_SIZE), M_DEVBUF, + M_NOWAIT | M_ZERO, 0, 0xffffffff, XLR_CACHELINE_SIZE, 0); + if (spill == NULL || ((vm_offset_t) spill & (XLR_CACHELINE_SIZE - 1))) { + panic("Unable to allocate memory for spill area!\n"); + } + phys_addr = vtophys(spill); + PDEBUG("Allocated spill %d bytes at %llx\n", size, phys_addr); + NLGE_WRITE(base, reg_start_0, (phys_addr >> 5) & 0xffffffff); + NLGE_WRITE(base, reg_start_1, (phys_addr >> 37) & 0x07); + NLGE_WRITE(base, reg_size, spill_size); + + return (spill); +} + +/* + * Configure the 6 FIFO's that are used by the network accelarator to + * communicate with the rest of the XLx device. 4 of the FIFO's are for + * packets from NA --> cpu (called Class FIFO's) and 2 are for feeding + * the NA with free descriptors. + */ +static void +nlna_config_fifo_spill_area(struct nlna_softc *sc) +{ + sc->frin_spill = nlna_config_spill(sc->base, + R_REG_FRIN_SPILL_MEM_START_0, + R_REG_FRIN_SPILL_MEM_START_1, + R_REG_FRIN_SPILL_MEM_SIZE, + MAX_FRIN_SPILL * + sizeof(struct fr_desc)); + sc->frout_spill = nlna_config_spill(sc->base, + R_FROUT_SPILL_MEM_START_0, + R_FROUT_SPILL_MEM_START_1, + R_FROUT_SPILL_MEM_SIZE, + MAX_FROUT_SPILL * + sizeof(struct fr_desc)); + sc->class_0_spill = nlna_config_spill(sc->base, + R_CLASS0_SPILL_MEM_START_0, + R_CLASS0_SPILL_MEM_START_1, + R_CLASS0_SPILL_MEM_SIZE, + MAX_CLASS_0_SPILL * + sizeof(union rx_tx_desc)); + sc->class_1_spill = nlna_config_spill(sc->base, + R_CLASS1_SPILL_MEM_START_0, + R_CLASS1_SPILL_MEM_START_1, + R_CLASS1_SPILL_MEM_SIZE, + MAX_CLASS_1_SPILL * + sizeof(union rx_tx_desc)); + sc->class_2_spill = nlna_config_spill(sc->base, + R_CLASS2_SPILL_MEM_START_0, + R_CLASS2_SPILL_MEM_START_1, + R_CLASS2_SPILL_MEM_SIZE, + MAX_CLASS_2_SPILL * + sizeof(union rx_tx_desc)); + sc->class_3_spill = nlna_config_spill(sc->base, + R_CLASS3_SPILL_MEM_START_0, + R_CLASS3_SPILL_MEM_START_1, + R_CLASS3_SPILL_MEM_SIZE, + MAX_CLASS_3_SPILL * + sizeof(union rx_tx_desc)); +} + +/* Set the CPU buckets that receive packets from the NA class FIFOs. */ +static void +nlna_config_pde(struct nlna_softc *sc) +{ + uint64_t bucket_map; + uint32_t cpumask; + int i, cpu, bucket; + + cpumask = 0x1; +#ifdef SMP + /* + * rge may be called before SMP start in a BOOTP/NFSROOT + * setup. we will distribute packets to other cpus only when + * the SMP is started. + */ + if (smp_started) + cpumask = xlr_hw_thread_mask; +#endif + bucket_map = 0; + for (i = 0; i < 32; i++) { + if (cpumask & (1 << i)) { + cpu = i; + /* use bucket 0 and 1 on every core for NA msgs */ + bucket = cpu/4 * 8; + bucket_map |= (3ULL << bucket); + } + } + + NLGE_WRITE(sc->base, R_PDE_CLASS_0, (bucket_map & 0xffffffff)); + NLGE_WRITE(sc->base, R_PDE_CLASS_0 + 1, ((bucket_map >> 32) & 0xffffffff)); + + NLGE_WRITE(sc->base, R_PDE_CLASS_1, (bucket_map & 0xffffffff)); + NLGE_WRITE(sc->base, R_PDE_CLASS_1 + 1, ((bucket_map >> 32) & 0xffffffff)); + + NLGE_WRITE(sc->base, R_PDE_CLASS_2, (bucket_map & 0xffffffff)); + NLGE_WRITE(sc->base, R_PDE_CLASS_2 + 1, ((bucket_map >> 32) & 0xffffffff)); + + NLGE_WRITE(sc->base, R_PDE_CLASS_3, (bucket_map & 0xffffffff)); + NLGE_WRITE(sc->base, R_PDE_CLASS_3 + 1, ((bucket_map >> 32) & 0xffffffff)); +} + +/* + * Update the network accelerator packet distribution engine for SMP. + * On bootup, we have just the boot hw thread handling all packets, on SMP + * start, we can start distributing packets across all the cores which are up. + */ +static void +nlna_smp_update_pde(void *dummy __unused) +{ + device_t iodi_dev; + struct nlna_softc *na_sc[XLR_MAX_NLNA]; + int i; + + printf("Updating packet distribution for SMP\n"); + + iodi_dev = devclass_get_device(devclass_find("iodi"), 0); + nlna_get_all_softc(iodi_dev, na_sc, XLR_MAX_NLNA); + + for (i = 0; i < XLR_MAX_NLNA; i++) { + if (na_sc[i] == NULL) + continue; + nlna_disable_ports(na_sc[i]); + nlna_config_pde(na_sc[i]); + nlna_config_translate_table(na_sc[i]); + nlna_enable_ports(na_sc[i]); + } +} + +SYSINIT(nlna_smp_update_pde, SI_SUB_SMP, SI_ORDER_ANY, nlna_smp_update_pde, + NULL); + +static void +nlna_config_translate_table(struct nlna_softc *sc) +{ + uint32_t cpu_mask; + uint32_t val; + int bkts[32]; /* one bucket is assumed for each cpu */ + int b1, b2, c1, c2, i, j, k; + int use_bkt; + + if (!flow_classification) + return; + + use_bkt = 1; + if (smp_started) + cpu_mask = xlr_hw_thread_mask; + else + return; + + printf("Using %s-based distribution\n", (use_bkt) ? "bucket" : "class"); + + j = 0; + for(i = 0; i < 32; i++) { + if ((1 << i) & cpu_mask){ + /* for each cpu, mark the 4+threadid bucket */ + bkts[j] = ((i / 4) * 8) + (i % 4); + j++; + } + } + + /*configure the 128 * 9 Translation table to send to available buckets*/ + k = 0; + c1 = 3; + c2 = 0; + for(i = 0; i < 64; i++) { + /* Get the next 2 pairs of (class, bucket): + (c1, b1), (c2, b2). + + c1, c2 limited to {0, 1, 2, 3} + i.e, the 4 classes defined by h/w + b1, b2 limited to { bkts[i], where 0 <= i < j} + i.e, the set of buckets computed in the + above loop. + */ + + c1 = (c1 + 1) & 3; + c2 = (c1 + 1) & 3; + b1 = bkts[k]; + k = (k + 1) % j; + b2 = bkts[k]; + k = (k + 1) % j; + PDEBUG("Translation table[%d] b1=%d b2=%d c1=%d c2=%d\n", + i, b1, b2, c1, c2); + val = ((c1 << 23) | (b1 << 17) | (use_bkt << 16) | + (c2 << 7) | (b2 << 1) | (use_bkt << 0)); + NLGE_WRITE(sc->base, R_TRANSLATETABLE + i, val); + c1 = c2; + } +} + +static void +nlna_config_parser(struct nlna_softc *sc) +{ + uint32_t val; + + /* + * Mark it as ETHERNET type. + */ + NLGE_WRITE(sc->base, R_L2TYPE_0, 0x01); + + if (!flow_classification) + return; + + /* Use 7bit CRChash for flow classification with 127 as CRC polynomial*/ + NLGE_WRITE(sc->base, R_PARSERCONFIGREG, ((0x7f << 8) | (1 << 1))); + + /* configure the parser : L2 Type is configured in the bootloader */ + /* extract IP: src, dest protocol */ + NLGE_WRITE(sc->base, R_L3CTABLE, + (9 << 20) | (1 << 19) | (1 << 18) | (0x01 << 16) | + (0x0800 << 0)); + NLGE_WRITE(sc->base, R_L3CTABLE + 1, + (9 << 25) | (1 << 21) | (12 << 14) | (4 << 10) | (16 << 4) | 4); + + /* Configure to extract SRC port and Dest port for TCP and UDP pkts */ + NLGE_WRITE(sc->base, R_L4CTABLE, 6); + NLGE_WRITE(sc->base, R_L4CTABLE+2, 17); + val = ((0 << 21) | (2 << 17) | (2 << 11) | (2 << 7)); + NLGE_WRITE(sc->base, R_L4CTABLE+1, val); + NLGE_WRITE(sc->base, R_L4CTABLE+3, val); +} + +static void +nlna_config_classifier(struct nlna_softc *sc) +{ + int i; + + if (sc->mac_type == XLR_XGMII) { /* TBD: XGMII init sequence */ + /* xgmac translation table doesn't have sane values on reset */ + for (i = 0; i < 64; i++) + NLGE_WRITE(sc->base, R_TRANSLATETABLE + i, 0x0); + + /* + * use upper 7 bits of the parser extract to index the + * translate table + */ + NLGE_WRITE(sc->base, R_PARSERCONFIGREG, 0x0); + } +} + +/* + * Complete a bunch of h/w register initializations that are common for all the + * ports controlled by a NA. + */ +static void +nlna_config_common(struct nlna_softc *sc) +{ + struct xlr_gmac_block_t *block_info; + struct stn_cc *gmac_cc_config; + int i; + + block_info = device_get_ivars(sc->nlna_dev); + gmac_cc_config = block_info->credit_config; + for (i = 0; i < MAX_NUM_MSGRNG_STN_CC; i++) { + NLGE_WRITE(sc->base, R_CC_CPU0_0 + i, + gmac_cc_config->counters[i >> 3][i & 0x07]); + } + + NLGE_WRITE(sc->base, R_MSG_TX_THRESHOLD, 3); + + NLGE_WRITE(sc->base, R_DMACR0, 0xffffffff); + NLGE_WRITE(sc->base, R_DMACR1, 0xffffffff); + NLGE_WRITE(sc->base, R_DMACR2, 0xffffffff); + NLGE_WRITE(sc->base, R_DMACR3, 0xffffffff); + NLGE_WRITE(sc->base, R_FREEQCARVE, 0); + + nlna_media_specific_config(sc); +} + +static void +nlna_media_specific_config(struct nlna_softc *sc) +{ + struct bucket_size *bucket_sizes; + + bucket_sizes = xlr_board_info.bucket_sizes; + switch (sc->mac_type) { + case XLR_RGMII: + case XLR_SGMII: + case XLR_XAUI: + NLGE_WRITE(sc->base, R_GMAC_JFR0_BUCKET_SIZE, + bucket_sizes->bucket[MSGRNG_STNID_GMACJFR_0]); + NLGE_WRITE(sc->base, R_GMAC_RFR0_BUCKET_SIZE, + bucket_sizes->bucket[MSGRNG_STNID_GMACRFR_0]); + NLGE_WRITE(sc->base, R_GMAC_JFR1_BUCKET_SIZE, + bucket_sizes->bucket[MSGRNG_STNID_GMACJFR_1]); + NLGE_WRITE(sc->base, R_GMAC_RFR1_BUCKET_SIZE, + bucket_sizes->bucket[MSGRNG_STNID_GMACRFR_1]); + + if (sc->mac_type == XLR_XAUI) { + NLGE_WRITE(sc->base, R_TXDATAFIFO0, (224 << 16)); + } + break; + + case XLR_XGMII: + NLGE_WRITE(sc->base, R_XGS_RFR_BUCKET_SIZE, + bucket_sizes->bucket[sc->rfrbucket]); + + default: + break; + } +} + +static void +nlna_reset_ports(struct nlna_softc *sc, struct xlr_gmac_block_t *blk) +{ + xlr_reg_t *addr; + int i; + uint32_t rx_ctrl; + + /* Refer Section 13.9.3 in the PRM for the reset sequence */ + + for (i = 0; i < sc->num_ports; i++) { + addr = xlr_io_mmio(blk->gmac_port[i].base_addr); + + /* 1. Reset RxEnable in MAC_CONFIG */ + switch (sc->mac_type) { + case XLR_RGMII: + case XLR_SGMII: + NLGE_UPDATE(addr, R_MAC_CONFIG_1, 0, + (1 << O_MAC_CONFIG_1__rxen)); + break; + case XLR_XAUI: + case XLR_XGMII: + NLGE_UPDATE(addr, R_RX_CONTROL, 0, + (1 << O_RX_CONTROL__RxEnable)); + break; + default: + printf("Error: Unsupported port_type=%d\n", + sc->mac_type); + } + + /* 1.1 Wait for RxControl.RxHalt to be set */ + do { + rx_ctrl = NLGE_READ(addr, R_RX_CONTROL); + } while (!(rx_ctrl & 0x2)); + + /* 2. Set the soft reset bit in RxControl */ + NLGE_UPDATE(addr, R_RX_CONTROL, (1 << O_RX_CONTROL__SoftReset), + (1 << O_RX_CONTROL__SoftReset)); + + /* 2.1 Wait for RxControl.SoftResetDone to be set */ + do { + rx_ctrl = NLGE_READ(addr, R_RX_CONTROL); + } while (!(rx_ctrl & 0x8)); + + /* 3. Clear the soft reset bit in RxControl */ + NLGE_UPDATE(addr, R_RX_CONTROL, 0, + (1 << O_RX_CONTROL__SoftReset)); + + /* Turn off tx/rx on the port. */ + NLGE_UPDATE(addr, R_RX_CONTROL, 0, + (1 << O_RX_CONTROL__RxEnable)); + NLGE_UPDATE(addr, R_TX_CONTROL, 0, + (1 << O_TX_CONTROL__TxEnable)); + } +} + +static void +nlna_disable_ports(struct nlna_softc *sc) +{ + int i; + + for (i = 0; i < sc->num_ports; i++) { + if (sc->child_sc[i] != NULL) + nlge_port_disable(sc->child_sc[i]); + } +} + +static void +nlna_enable_ports(struct nlna_softc *sc) +{ + device_t nlge_dev, *devlist; + struct nlge_softc *port_sc; + int i, numdevs; + + device_get_children(sc->nlna_dev, &devlist, &numdevs); + for (i = 0; i < numdevs; i++) { + nlge_dev = devlist[i]; + if (nlge_dev == NULL) + continue; + port_sc = device_get_softc(nlge_dev); + if (port_sc->nlge_if->if_drv_flags & IFF_DRV_RUNNING) + nlge_port_enable(port_sc); + } + free(devlist, M_TEMP); +} + +static void +nlna_get_all_softc(device_t iodi_dev, struct nlna_softc **sc_vec, + uint32_t vec_sz) +{ + device_t na_dev; + int i; + + for (i = 0; i < vec_sz; i++) { + sc_vec[i] = NULL; + na_dev = device_find_child(iodi_dev, "nlna", i); + if (na_dev != NULL) + sc_vec[i] = device_get_softc(na_dev); + } +} + +static void +nlge_port_disable(struct nlge_softc *sc) +{ + struct ifnet *ifp; + xlr_reg_t *base; + uint32_t rd; + int id, port_type; + + id = sc->id; + port_type = sc->port_type; + base = sc->base; + ifp = sc->nlge_if; + + NLGE_UPDATE(base, R_RX_CONTROL, 0x0, 1 << O_RX_CONTROL__RxEnable); + do { + rd = NLGE_READ(base, R_RX_CONTROL); + } while (!(rd & (1 << O_RX_CONTROL__RxHalt))); + + NLGE_UPDATE(base, R_TX_CONTROL, 0, 1 << O_TX_CONTROL__TxEnable); + do { + rd = NLGE_READ(base, R_TX_CONTROL); + } while (!(rd & (1 << O_TX_CONTROL__TxIdle))); + + switch (port_type) { + case XLR_RGMII: + case XLR_SGMII: + NLGE_UPDATE(base, R_MAC_CONFIG_1, 0, + ((1 << O_MAC_CONFIG_1__rxen) | + (1 << O_MAC_CONFIG_1__txen))); + break; + case XLR_XGMII: + case XLR_XAUI: + NLGE_UPDATE(base, R_XGMAC_CONFIG_1, 0, + ((1 << O_XGMAC_CONFIG_1__hsttfen) | + (1 << O_XGMAC_CONFIG_1__hstrfen))); + break; + default: + panic("Unknown MAC type on port %d\n", id); + } + + if (ifp) { + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + } +} + +static void +nlge_port_enable(struct nlge_softc *sc) +{ + struct xlr_gmac_port *self; + xlr_reg_t *base; + + base = sc->base; + self = device_get_ivars(sc->nlge_dev); + if (xlr_board_info.is_xls && sc->port_type == XLR_RGMII) + NLGE_UPDATE(base, R_RX_CONTROL, (1 << O_RX_CONTROL__RGMII), + (1 << O_RX_CONTROL__RGMII)); + + NLGE_UPDATE(base, R_RX_CONTROL, (1 << O_RX_CONTROL__RxEnable), + (1 << O_RX_CONTROL__RxEnable)); + NLGE_UPDATE(base, R_TX_CONTROL, + (1 << O_TX_CONTROL__TxEnable | RGE_TX_THRESHOLD_BYTES), + (1 << O_TX_CONTROL__TxEnable | 0x3fff)); + switch (sc->port_type) { + case XLR_RGMII: + case XLR_SGMII: + NLGE_UPDATE(base, R_MAC_CONFIG_1, + ((1 << O_MAC_CONFIG_1__rxen) | (1 << O_MAC_CONFIG_1__txen)), + ((1 << O_MAC_CONFIG_1__rxen) | (1 << O_MAC_CONFIG_1__txen))); + break; + case XLR_XGMII: + case XLR_XAUI: + NLGE_UPDATE(base, R_XGMAC_CONFIG_1, + ((1 << O_XGMAC_CONFIG_1__hsttfen) | (1 << O_XGMAC_CONFIG_1__hstrfen)), + ((1 << O_XGMAC_CONFIG_1__hsttfen) | (1 << O_XGMAC_CONFIG_1__hstrfen))); + break; + default: + panic("Unknown MAC type on port %d\n", sc->id); + } +} + +static void +nlge_mac_set_rx_mode(struct nlge_softc *sc) +{ + uint32_t regval; + + regval = NLGE_READ(sc->base, R_MAC_FILTER_CONFIG); + + if (sc->if_flags & IFF_PROMISC) { + regval |= (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) | + (1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) | + (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) | + (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN); + } else { + regval &= ~((1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) | + (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN)); + } + + NLGE_WRITE(sc->base, R_MAC_FILTER_CONFIG, regval); +} + +static void +nlge_sgmii_init(struct nlge_softc *sc) +{ + xlr_reg_t *mmio_gpio; + int phy; + + if (sc->port_type != XLR_SGMII) + return; + + nlge_mii_write_internal(sc->serdes_addr, 26, 0, 0x6DB0); + nlge_mii_write_internal(sc->serdes_addr, 26, 1, 0xFFFF); + nlge_mii_write_internal(sc->serdes_addr, 26, 2, 0xB6D0); + nlge_mii_write_internal(sc->serdes_addr, 26, 3, 0x00FF); + nlge_mii_write_internal(sc->serdes_addr, 26, 4, 0x0000); + nlge_mii_write_internal(sc->serdes_addr, 26, 5, 0x0000); + nlge_mii_write_internal(sc->serdes_addr, 26, 6, 0x0005); + nlge_mii_write_internal(sc->serdes_addr, 26, 7, 0x0001); + nlge_mii_write_internal(sc->serdes_addr, 26, 8, 0x0000); + nlge_mii_write_internal(sc->serdes_addr, 26, 9, 0x0000); + nlge_mii_write_internal(sc->serdes_addr, 26,10, 0x0000); + + /* program GPIO values for serdes init parameters */ + DELAY(100); + mmio_gpio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); + xlr_write_reg(mmio_gpio, 0x20, 0x7e6802); + xlr_write_reg(mmio_gpio, 0x10, 0x7104); + DELAY(100); + + /* + * This kludge is needed to setup serdes (?) clock correctly on some + * XLS boards + */ + if ((xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_XI || + xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_XII) && + xlr_boot1_info.board_minor_version == 4) { + /* use 125 Mhz instead of 156.25Mhz ref clock */ + DELAY(100); + xlr_write_reg(mmio_gpio, 0x10, 0x7103); + xlr_write_reg(mmio_gpio, 0x21, 0x7103); + DELAY(100); + } + + /* enable autoneg - more magic */ + phy = sc->phy_addr % 4 + 27; + nlge_mii_write_internal(sc->pcs_addr, phy, 0, 0x1000); + DELAY(100000); + nlge_mii_write_internal(sc->pcs_addr, phy, 0, 0x0200); + DELAY(100000); +} + +static void +nlge_intr(void *arg) +{ + struct nlge_port_set *pset; + struct nlge_softc *sc; + struct nlge_softc *port_sc; + xlr_reg_t *base; + uint32_t intreg; + uint32_t intr_status; + int i; + + sc = arg; + if (sc == NULL) { + printf("warning: No port registered for interrupt\n"); + return; + } + base = sc->base; + + intreg = NLGE_READ(base, R_INTREG); + if (intreg & (1 << O_INTREG__MDInt)) { + pset = sc->mdio_pset; + if (pset == NULL) { + printf("warning: No ports for MDIO interrupt\n"); + return; + } + for (i = 0; i < pset->vec_sz; i++) { + port_sc = pset->port_vec[i]; + + if (port_sc == NULL) + continue; + + /* Ack phy interrupt - clear on read*/ + intr_status = nlge_mii_read_internal(port_sc->mii_base, + port_sc->phy_addr, 26); + PDEBUG("Phy_%d: int_status=0x%08x\n", port_sc->phy_addr, + intr_status); + + if (!(intr_status & 0x8000)) { + /* no interrupt for this port */ + continue; + } + + if (intr_status & 0x2410) { + /* update link status for port */ + nlge_gmac_config_speed(port_sc, 1); + } else { + printf("%s: Unsupported phy interrupt" + " (0x%08x)\n", + device_get_nameunit(port_sc->nlge_dev), + intr_status); + } + } + } + + /* Clear the NA interrupt */ + xlr_write_reg(base, R_INTREG, 0xffffffff); + + return; +} + +static int +nlge_irq_init(struct nlge_softc *sc) +{ + struct resource irq_res; + struct nlna_softc *na_sc; + struct xlr_gmac_block_t *block_info; + device_t na_dev; + int ret; + int irq_num; + + na_dev = device_get_parent(sc->nlge_dev); + block_info = device_get_ivars(na_dev); + + irq_num = block_info->baseirq + sc->instance; + irq_res.__r_i = (struct resource_i *)(intptr_t) (irq_num); + ret = bus_setup_intr(sc->nlge_dev, &irq_res, (INTR_FAST | + INTR_TYPE_NET | INTR_MPSAFE), NULL, nlge_intr, sc, NULL); + if (ret) { + nlge_detach(sc->nlge_dev); + device_printf(sc->nlge_dev, "couldn't set up irq: error=%d\n", + ret); + return (ENXIO); + } + PDEBUG("Setup intr for dev=%s, irq=%d\n", + device_get_nameunit(sc->nlge_dev), irq_num); + + if (sc->instance == 0) { + na_sc = device_get_softc(na_dev); + sc->mdio_pset = &na_sc->mdio_set; + } + return (0); +} + +static void +nlge_irq_fini(struct nlge_softc *sc) +{ +} + +static void +nlge_hw_init(struct nlge_softc *sc) +{ + struct xlr_gmac_port *port_info; + xlr_reg_t *base; + + base = sc->base; + port_info = device_get_ivars(sc->nlge_dev); + sc->tx_bucket_id = port_info->tx_bucket_id; + + /* each packet buffer is 1536 bytes */ + NLGE_WRITE(base, R_DESC_PACK_CTRL, + (1 << O_DESC_PACK_CTRL__MaxEntry) | + (MAX_FRAME_SIZE << O_DESC_PACK_CTRL__RegularSize)); + NLGE_WRITE(base, R_STATCTRL, ((1 << O_STATCTRL__Sten) | + (1 << O_STATCTRL__ClrCnt))); + NLGE_WRITE(base, R_L2ALLOCCTRL, 0xffffffff); + NLGE_WRITE(base, R_INTMASK, 0); + nlge_set_mac_addr(sc); + nlge_media_specific_init(sc); +} + +static void +nlge_sc_init(struct nlge_softc *sc, device_t dev, + struct xlr_gmac_port *port_info) +{ + memset(sc, 0, sizeof(*sc)); + sc->nlge_dev = dev; + sc->id = device_get_unit(dev); + nlge_set_port_attribs(sc, port_info); +} + +static void +nlge_media_specific_init(struct nlge_softc *sc) +{ + struct mii_data *media; + struct bucket_size *bucket_sizes; + + bucket_sizes = xlr_board_info.bucket_sizes; + switch (sc->port_type) { + case XLR_RGMII: + case XLR_SGMII: + case XLR_XAUI: + NLGE_UPDATE(sc->base, R_DESC_PACK_CTRL, + (BYTE_OFFSET << O_DESC_PACK_CTRL__ByteOffset), + (W_DESC_PACK_CTRL__ByteOffset << + O_DESC_PACK_CTRL__ByteOffset)); + NLGE_WRITE(sc->base, R_GMAC_TX0_BUCKET_SIZE + sc->instance, + bucket_sizes->bucket[sc->tx_bucket_id]); + if (sc->port_type != XLR_XAUI) { + nlge_gmac_config_speed(sc, 1); + if (sc->mii_bus) { + media = (struct mii_data *)device_get_softc( + sc->mii_bus); + } + } + break; + + case XLR_XGMII: + NLGE_WRITE(sc->base, R_BYTEOFFSET0, 0x2); + NLGE_WRITE(sc->base, R_XGMACPADCALIBRATION, 0x30); + NLGE_WRITE(sc->base, R_XGS_TX0_BUCKET_SIZE, + bucket_sizes->bucket[sc->tx_bucket_id]); + break; + default: + break; + } +} + +/* + * Read the MAC address from the XLR boot registers. All port addresses + * are identical except for the lowest octet. + */ +static void +nlge_read_mac_addr(struct nlge_softc *sc) +{ + int i, j; + + for (i = 0, j = 40; i < ETHER_ADDR_LEN && j >= 0; i++, j-= 8) + sc->dev_addr[i] = (xlr_boot1_info.mac_addr >> j) & 0xff; + + sc->dev_addr[i - 1] += sc->id; /* last octet is port-specific */ +} + +/* + * Write the MAC address to the XLR MAC port. Also, set the address + * masks and MAC filter configuration. + */ +static void +nlge_set_mac_addr(struct nlge_softc *sc) +{ + NLGE_WRITE(sc->base, R_MAC_ADDR0, + ((sc->dev_addr[5] << 24) | (sc->dev_addr[4] << 16) | + (sc->dev_addr[3] << 8) | (sc->dev_addr[2]))); + NLGE_WRITE(sc->base, R_MAC_ADDR0 + 1, + ((sc->dev_addr[1] << 24) | (sc-> dev_addr[0] << 16))); + + NLGE_WRITE(sc->base, R_MAC_ADDR_MASK2, 0xffffffff); + NLGE_WRITE(sc->base, R_MAC_ADDR_MASK2 + 1, 0xffffffff); + NLGE_WRITE(sc->base, R_MAC_ADDR_MASK3, 0xffffffff); + NLGE_WRITE(sc->base, R_MAC_ADDR_MASK3 + 1, 0xffffffff); + + NLGE_WRITE(sc->base, R_MAC_FILTER_CONFIG, + (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) | + (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) | + (1 << O_MAC_FILTER_CONFIG__MAC_ADDR0_VALID)); + + if (sc->port_type == XLR_RGMII || sc->port_type == XLR_SGMII) { + NLGE_UPDATE(sc->base, R_IPG_IFG, MAC_B2B_IPG, 0x7f); + } +} + +static int +nlge_if_init(struct nlge_softc *sc) +{ + struct ifnet *ifp; + device_t dev; + int error; + + error = 0; + dev = sc->nlge_dev; + NLGE_LOCK_INIT(sc, device_get_nameunit(dev)); + + ifp = sc->nlge_if = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + error = ENOSPC; + goto fail; + } + ifp->if_softc = sc; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_capabilities = 0; + ifp->if_capenable = ifp->if_capabilities; + ifp->if_ioctl = nlge_ioctl; + ifp->if_start = nlge_start; + ifp->if_init = nlge_init; + ifp->if_hwassist = 0; + ifp->if_snd.ifq_drv_maxlen = RGE_TX_Q_SIZE; + IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); + IFQ_SET_READY(&ifp->if_snd); + + ifmedia_init(&sc->nlge_mii.mii_media, 0, nlge_mediachange, + nlge_mediastatus); + ifmedia_add(&sc->nlge_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&sc->nlge_mii.mii_media, IFM_ETHER | IFM_AUTO); + sc->nlge_mii.mii_media.ifm_media = sc->nlge_mii.mii_media.ifm_cur->ifm_media; + nlge_read_mac_addr(sc); + + ether_ifattach(ifp, sc->dev_addr); + +fail: + return (error); +} + +static void +nlge_mii_init(device_t dev, struct nlge_softc *sc) +{ + int error; + + if (sc->port_type != XLR_XAUI && sc->port_type != XLR_XGMII) { + NLGE_WRITE(sc->mii_base, R_MII_MGMT_CONFIG, 0x07); + } + error = mii_attach(dev, &sc->mii_bus, sc->nlge_if, nlge_mediachange, + nlge_mediastatus, BMSR_DEFCAPMASK, sc->phy_addr, MII_OFFSET_ANY, + 0); + if (error) { + device_printf(dev, "attaching PHYs failed\n"); + sc->mii_bus = NULL; + } + if (sc->mii_bus != NULL) { + /* + * Enable all MDIO interrupts in the phy. RX_ER bit seems to get + * set about every 1 sec in GigE mode, ignore it for now... + */ + nlge_mii_write_internal(sc->mii_base, sc->phy_addr, 25, + 0xfffffffe); + } +} + +/* + * Read a PHY register. + * + * Input parameters: + * mii_base - Base address of MII + * phyaddr - PHY's address + * regidx = index of register to read + * + * Return value: + * value read, or 0 if an error occurred. + */ + +static int +nlge_mii_read_internal(xlr_reg_t *mii_base, int phyaddr, int regidx) +{ + int i, val; + + /* setup the phy reg to be used */ + NLGE_WRITE(mii_base, R_MII_MGMT_ADDRESS, + (phyaddr << 8) | (regidx << 0)); + /* Issue the read command */ + NLGE_WRITE(mii_base, R_MII_MGMT_COMMAND, + (1 << O_MII_MGMT_COMMAND__rstat)); + + /* poll for the read cycle to complete */ + for (i = 0; i < PHY_STATUS_RETRIES; i++) { + if (NLGE_READ(mii_base, R_MII_MGMT_INDICATORS) == 0) + break; + } + + /* clear the read cycle */ + NLGE_WRITE(mii_base, R_MII_MGMT_COMMAND, 0); + + if (i == PHY_STATUS_RETRIES) { + return (0xffffffff); + } + + val = NLGE_READ(mii_base, R_MII_MGMT_STATUS); + + return (val); +} + +/* + * Write a value to a PHY register. + * + * Input parameters: + * mii_base - Base address of MII + * phyaddr - PHY to use + * regidx - register within the PHY + * regval - data to write to register + * + * Return value: + * nothing + */ +static void +nlge_mii_write_internal(xlr_reg_t *mii_base, int phyaddr, int regidx, + int regval) +{ + int i; + + NLGE_WRITE(mii_base, R_MII_MGMT_ADDRESS, + (phyaddr << 8) | (regidx << 0)); + + /* Write the data which starts the write cycle */ + NLGE_WRITE(mii_base, R_MII_MGMT_WRITE_DATA, regval); + + /* poll for the write cycle to complete */ + for (i = 0; i < PHY_STATUS_RETRIES; i++) { + if (NLGE_READ(mii_base, R_MII_MGMT_INDICATORS) == 0) + break; + } +} + +/* + * Function to optimize the use of p2d descriptors for the given PDU. + * As it is on the fast-path (called during packet transmission), it + * described in more detail than the initialization functions. + * + * Input: mbuf chain (MC), pointer to fmn message + * Input constraints: None + * Output: FMN message to transmit the data in MC + * Return values: 0 - success + * 1 - MC cannot be handled (see Limitations below) + * 2 - MC cannot be handled presently (maybe worth re-trying) + * Other output: Number of entries filled in the FMN message + * + * Output structure/constraints: + * 1. Max 3 p2d's + 1 zero-len (ZL) p2d with virtual address of MC. + * 2. 3 p2d's + 1 p2p with max 14 p2d's (ZL p2d not required in this case). + * 3. Each p2d points to physically contiguous chunk of data (subject to + * entire MC requiring max 17 p2d's). + * Limitations: + * 1. MC's that require more than 17 p2d's are not handled. + * Benefits: MC's that require <= 3 p2d's avoid the overhead of allocating + * the p2p structure. Small packets (which typically give low + * performance) are expected to have a small MC that takes + * advantage of this. + */ +static int +prepare_fmn_message(struct nlge_softc *sc, struct msgrng_msg *fmn_msg, + uint32_t *n_entries, struct mbuf *mbuf_chain, uint64_t fb_stn_id, + struct nlge_tx_desc **tx_desc) +{ + struct mbuf *m; + struct nlge_tx_desc *p2p; + uint64_t *cur_p2d; + uint64_t fbpaddr; + vm_offset_t buf; + vm_paddr_t paddr; + int msg_sz, p2p_sz, len, frag_sz; + /* Num entries per FMN msg is 4 for XLR/XLS */ + const int FMN_SZ = sizeof(*fmn_msg) / sizeof(uint64_t); + + msg_sz = p2p_sz = 0; + p2p = NULL; + cur_p2d = &fmn_msg->msg0; + + for (m = mbuf_chain; m != NULL; m = m->m_next) { + buf = (vm_offset_t) m->m_data; + len = m->m_len; + + while (len) { + if (msg_sz == (FMN_SZ - 1)) { + p2p = uma_zalloc(nl_tx_desc_zone, M_NOWAIT); + if (p2p == NULL) { + return (2); + } + /* + * Save the virtual address in the descriptor, + * it makes freeing easy. + */ + p2p->frag[XLR_MAX_TX_FRAGS] = + (uint64_t)(vm_offset_t)p2p; + cur_p2d = &p2p->frag[0]; + } else if (msg_sz == (FMN_SZ - 2 + XLR_MAX_TX_FRAGS)) { + uma_zfree(nl_tx_desc_zone, p2p); + return (1); + } + paddr = vtophys(buf); + frag_sz = PAGE_SIZE - (buf & PAGE_MASK); + if (len < frag_sz) + frag_sz = len; + *cur_p2d++ = (127ULL << 54) | ((uint64_t)frag_sz << 40) + | paddr; + msg_sz++; + if (p2p != NULL) + p2p_sz++; + len -= frag_sz; + buf += frag_sz; + } + } + + if (msg_sz == 0) { + printf("Zero-length mbuf chain ??\n"); + *n_entries = msg_sz ; + return (0); + } + + /* set eop in most-recent p2d */ + cur_p2d[-1] |= (1ULL << 63); + +#ifdef __mips_n64 + /* + * On n64, we cannot store our mbuf pointer(64 bit) in the freeback + * message (40bit available), so we put the mbuf in m_nextpkt and + * use the physical addr of that in freeback message. + */ + mbuf_chain->m_nextpkt = mbuf_chain; + fbpaddr = vtophys(&mbuf_chain->m_nextpkt); +#else + /* Careful, don't sign extend when going to 64bit */ + fbpaddr = (uint64_t)(uintptr_t)mbuf_chain; +#endif + *cur_p2d = (1ULL << 63) | ((uint64_t)fb_stn_id << 54) | fbpaddr; + *tx_desc = p2p; + + if (p2p != NULL) { + paddr = vtophys(p2p); + p2p_sz++; + fmn_msg->msg3 = (1ULL << 62) | ((uint64_t)fb_stn_id << 54) | + ((uint64_t)(p2p_sz * 8) << 40) | paddr; + *n_entries = FMN_SZ; + } else { + *n_entries = msg_sz + 1; + } + + return (0); +} + +static int +send_fmn_msg_tx(struct nlge_softc *sc, struct msgrng_msg *msg, + uint32_t n_entries) +{ + uint32_t msgrng_flags; + int ret; + int i = 0; + + do { + msgrng_flags = msgrng_access_enable(); + ret = message_send(n_entries, MSGRNG_CODE_MAC, + sc->tx_bucket_id, msg); + msgrng_restore(msgrng_flags); + if (ret == 0) + return (0); + i++; + } while (i < 100000); + + device_printf(sc->nlge_dev, "Too many credit fails in tx path\n"); + + return (1); +} + +static void +release_tx_desc(vm_paddr_t paddr) +{ + struct nlge_tx_desc *tx_desc; + uint32_t sr; + uint64_t vaddr; + + paddr += (XLR_MAX_TX_FRAGS * sizeof(uint64_t)); + sr = xlr_enable_kx(); + vaddr = xlr_paddr_ld(paddr); + xlr_restore_kx(sr); + + tx_desc = (struct nlge_tx_desc*)(intptr_t)vaddr; + uma_zfree(nl_tx_desc_zone, tx_desc); +} + +static void * +get_buf(void) +{ + struct mbuf *m_new; + uint64_t *md; +#ifdef INVARIANTS + vm_paddr_t temp1, temp2; +#endif + + if ((m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR)) == NULL) + return (NULL); + m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; + m_adj(m_new, XLR_CACHELINE_SIZE - ((uintptr_t)m_new->m_data & 0x1f)); + md = (uint64_t *)m_new->m_data; + md[0] = (intptr_t)m_new; /* Back Ptr */ + md[1] = 0xf00bad; + m_adj(m_new, XLR_CACHELINE_SIZE); + +#ifdef INVARIANTS + temp1 = vtophys((vm_offset_t) m_new->m_data); + temp2 = vtophys((vm_offset_t) m_new->m_data + 1536); + if ((temp1 + 1536) != temp2) + panic("ALLOCED BUFFER IS NOT CONTIGUOUS\n"); +#endif + + return ((void *)m_new->m_data); +} + +static int +nlge_gmac_config_speed(struct nlge_softc *sc, int quick) +{ + struct mii_data *md; + xlr_reg_t *mmio; + int bmsr, n_tries, max_tries; + int core_ctl[] = { 0x2, 0x1, 0x0, 0x1 }; + int sgmii_speed[] = { SGMII_SPEED_10, + SGMII_SPEED_100, + SGMII_SPEED_1000, + SGMII_SPEED_100 }; /* default to 100Mbps */ + char *speed_str[] = { "10", + "100", + "1000", + "unknown, defaulting to 100" }; + int link_state = LINK_STATE_DOWN; + + if (sc->port_type == XLR_XAUI || sc->port_type == XLR_XGMII) + return 0; + + md = NULL; + mmio = sc->base; + if (sc->mii_base != NULL) { + max_tries = (quick == 1) ? 100 : 4000; + bmsr = 0; + for (n_tries = 0; n_tries < max_tries; n_tries++) { + bmsr = nlge_mii_read_internal(sc->mii_base, + sc->phy_addr, MII_BMSR); + if ((bmsr & BMSR_ACOMP) && (bmsr & BMSR_LINK)) + break; /* Auto-negotiation is complete + and link is up */ + DELAY(1000); + } + bmsr &= BMSR_LINK; + sc->link = (bmsr == 0) ? xlr_mac_link_down : xlr_mac_link_up; + sc->speed = nlge_mii_read_internal(sc->mii_base, sc->phy_addr, 28); + sc->speed = (sc->speed >> 3) & 0x03; + if (sc->link == xlr_mac_link_up) { + link_state = LINK_STATE_UP; + nlge_sgmii_init(sc); + } + if (sc->mii_bus) + md = (struct mii_data *)device_get_softc(sc->mii_bus); + } + + if (sc->port_type != XLR_RGMII) + NLGE_WRITE(mmio, R_INTERFACE_CONTROL, sgmii_speed[sc->speed]); + if (sc->speed == xlr_mac_speed_10 || sc->speed == xlr_mac_speed_100 || + sc->speed == xlr_mac_speed_rsvd) { + NLGE_WRITE(mmio, R_MAC_CONFIG_2, 0x7117); + } else if (sc->speed == xlr_mac_speed_1000) { + NLGE_WRITE(mmio, R_MAC_CONFIG_2, 0x7217); + if (md != NULL) { + ifmedia_set(&md->mii_media, IFM_MAKEWORD(IFM_ETHER, + IFM_1000_T, IFM_FDX, md->mii_instance)); + } + } + NLGE_WRITE(mmio, R_CORECONTROL, core_ctl[sc->speed]); + if_link_state_change(sc->nlge_if, link_state); + printf("%s: [%sMbps]\n", device_get_nameunit(sc->nlge_dev), + speed_str[sc->speed]); + + return (0); +} + +/* + * This function is called for each port that was added to the device tree + * and it initializes the following port attributes: + * - type + * - base (base address to access port-specific registers) + * - mii_base + * - phy_addr + */ +static void +nlge_set_port_attribs(struct nlge_softc *sc, + struct xlr_gmac_port *port_info) +{ + sc->instance = port_info->instance % 4; /* TBD: will not work for SPI-4 */ + sc->port_type = port_info->type; + sc->base = xlr_io_mmio(port_info->base_addr); + sc->mii_base = xlr_io_mmio(port_info->mii_addr); + if (port_info->pcs_addr != 0) + sc->pcs_addr = xlr_io_mmio(port_info->pcs_addr); + if (port_info->serdes_addr != 0) + sc->serdes_addr = xlr_io_mmio(port_info->serdes_addr); + sc->phy_addr = port_info->phy_addr; + + PDEBUG("Port%d: base=%p, mii_base=%p, phy_addr=%d\n", sc->id, sc->base, + sc->mii_base, sc->phy_addr); +} + +/* ------------------------------------------------------------------------ */ + +/* Debug dump functions */ + +#ifdef DEBUG + +static void +dump_reg(xlr_reg_t *base, uint32_t offset, char *name) +{ + int val; + + val = NLGE_READ(base, offset); + printf("%-30s: 0x%8x 0x%8x\n", name, offset, val); +} + +#define STRINGIFY(x) #x + +static void +dump_na_registers(xlr_reg_t *base_addr, int port_id) +{ + PDEBUG("Register dump for NA (of port=%d)\n", port_id); + dump_reg(base_addr, R_PARSERCONFIGREG, STRINGIFY(R_PARSERCONFIGREG)); + PDEBUG("Tx bucket sizes\n"); + dump_reg(base_addr, R_GMAC_JFR0_BUCKET_SIZE, + STRINGIFY(R_GMAC_JFR0_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_RFR0_BUCKET_SIZE, + STRINGIFY(R_GMAC_RFR0_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_TX0_BUCKET_SIZE, + STRINGIFY(R_GMAC_TX0_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_TX1_BUCKET_SIZE, + STRINGIFY(R_GMAC_TX1_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_TX2_BUCKET_SIZE, + STRINGIFY(R_GMAC_TX2_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_TX3_BUCKET_SIZE, + STRINGIFY(R_GMAC_TX3_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_JFR1_BUCKET_SIZE, + STRINGIFY(R_GMAC_JFR1_BUCKET_SIZE)); + dump_reg(base_addr, R_GMAC_RFR1_BUCKET_SIZE, + STRINGIFY(R_GMAC_RFR1_BUCKET_SIZE)); + dump_reg(base_addr, R_TXDATAFIFO0, STRINGIFY(R_TXDATAFIFO0)); + dump_reg(base_addr, R_TXDATAFIFO1, STRINGIFY(R_TXDATAFIFO1)); +} + +static void +dump_gmac_registers(struct nlge_softc *sc) +{ + xlr_reg_t *base_addr = sc->base; + int port_id = sc->instance; + + PDEBUG("Register dump for port=%d\n", port_id); + if (sc->port_type == XLR_RGMII || sc->port_type == XLR_SGMII) { + dump_reg(base_addr, R_MAC_CONFIG_1, STRINGIFY(R_MAC_CONFIG_1)); + dump_reg(base_addr, R_MAC_CONFIG_2, STRINGIFY(R_MAC_CONFIG_2)); + dump_reg(base_addr, R_IPG_IFG, STRINGIFY(R_IPG_IFG)); + dump_reg(base_addr, R_HALF_DUPLEX, STRINGIFY(R_HALF_DUPLEX)); + dump_reg(base_addr, R_MAXIMUM_FRAME_LENGTH, + STRINGIFY(R_MAXIMUM_FRAME_LENGTH)); + dump_reg(base_addr, R_TEST, STRINGIFY(R_TEST)); + dump_reg(base_addr, R_MII_MGMT_CONFIG, + STRINGIFY(R_MII_MGMT_CONFIG)); + dump_reg(base_addr, R_MII_MGMT_COMMAND, + STRINGIFY(R_MII_MGMT_COMMAND)); + dump_reg(base_addr, R_MII_MGMT_ADDRESS, + STRINGIFY(R_MII_MGMT_ADDRESS)); + dump_reg(base_addr, R_MII_MGMT_WRITE_DATA, + STRINGIFY(R_MII_MGMT_WRITE_DATA)); + dump_reg(base_addr, R_MII_MGMT_STATUS, + STRINGIFY(R_MII_MGMT_STATUS)); + dump_reg(base_addr, R_MII_MGMT_INDICATORS, + STRINGIFY(R_MII_MGMT_INDICATORS)); + dump_reg(base_addr, R_INTERFACE_CONTROL, + STRINGIFY(R_INTERFACE_CONTROL)); + dump_reg(base_addr, R_INTERFACE_STATUS, + STRINGIFY(R_INTERFACE_STATUS)); + } else if (sc->port_type == XLR_XAUI || sc->port_type == XLR_XGMII) { + dump_reg(base_addr, R_XGMAC_CONFIG_0, + STRINGIFY(R_XGMAC_CONFIG_0)); + dump_reg(base_addr, R_XGMAC_CONFIG_1, + STRINGIFY(R_XGMAC_CONFIG_1)); + dump_reg(base_addr, R_XGMAC_CONFIG_2, + STRINGIFY(R_XGMAC_CONFIG_2)); + dump_reg(base_addr, R_XGMAC_CONFIG_3, + STRINGIFY(R_XGMAC_CONFIG_3)); + dump_reg(base_addr, R_XGMAC_STATION_ADDRESS_LS, + STRINGIFY(R_XGMAC_STATION_ADDRESS_LS)); + dump_reg(base_addr, R_XGMAC_STATION_ADDRESS_MS, + STRINGIFY(R_XGMAC_STATION_ADDRESS_MS)); + dump_reg(base_addr, R_XGMAC_MAX_FRAME_LEN, + STRINGIFY(R_XGMAC_MAX_FRAME_LEN)); + dump_reg(base_addr, R_XGMAC_REV_LEVEL, + STRINGIFY(R_XGMAC_REV_LEVEL)); + dump_reg(base_addr, R_XGMAC_MIIM_COMMAND, + STRINGIFY(R_XGMAC_MIIM_COMMAND)); + dump_reg(base_addr, R_XGMAC_MIIM_FILED, + STRINGIFY(R_XGMAC_MIIM_FILED)); + dump_reg(base_addr, R_XGMAC_MIIM_CONFIG, + STRINGIFY(R_XGMAC_MIIM_CONFIG)); + dump_reg(base_addr, R_XGMAC_MIIM_LINK_FAIL_VECTOR, + STRINGIFY(R_XGMAC_MIIM_LINK_FAIL_VECTOR)); + dump_reg(base_addr, R_XGMAC_MIIM_INDICATOR, + STRINGIFY(R_XGMAC_MIIM_INDICATOR)); + } + + dump_reg(base_addr, R_MAC_ADDR0, STRINGIFY(R_MAC_ADDR0)); + dump_reg(base_addr, R_MAC_ADDR0 + 1, STRINGIFY(R_MAC_ADDR0+1)); + dump_reg(base_addr, R_MAC_ADDR1, STRINGIFY(R_MAC_ADDR1)); + dump_reg(base_addr, R_MAC_ADDR2, STRINGIFY(R_MAC_ADDR2)); + dump_reg(base_addr, R_MAC_ADDR3, STRINGIFY(R_MAC_ADDR3)); + dump_reg(base_addr, R_MAC_ADDR_MASK2, STRINGIFY(R_MAC_ADDR_MASK2)); + dump_reg(base_addr, R_MAC_ADDR_MASK3, STRINGIFY(R_MAC_ADDR_MASK3)); + dump_reg(base_addr, R_MAC_FILTER_CONFIG, STRINGIFY(R_MAC_FILTER_CONFIG)); + dump_reg(base_addr, R_TX_CONTROL, STRINGIFY(R_TX_CONTROL)); + dump_reg(base_addr, R_RX_CONTROL, STRINGIFY(R_RX_CONTROL)); + dump_reg(base_addr, R_DESC_PACK_CTRL, STRINGIFY(R_DESC_PACK_CTRL)); + dump_reg(base_addr, R_STATCTRL, STRINGIFY(R_STATCTRL)); + dump_reg(base_addr, R_L2ALLOCCTRL, STRINGIFY(R_L2ALLOCCTRL)); + dump_reg(base_addr, R_INTMASK, STRINGIFY(R_INTMASK)); + dump_reg(base_addr, R_INTREG, STRINGIFY(R_INTREG)); + dump_reg(base_addr, R_TXRETRY, STRINGIFY(R_TXRETRY)); + dump_reg(base_addr, R_CORECONTROL, STRINGIFY(R_CORECONTROL)); + dump_reg(base_addr, R_BYTEOFFSET0, STRINGIFY(R_BYTEOFFSET0)); + dump_reg(base_addr, R_BYTEOFFSET1, STRINGIFY(R_BYTEOFFSET1)); + dump_reg(base_addr, R_L2TYPE_0, STRINGIFY(R_L2TYPE_0)); + dump_na_registers(base_addr, port_id); +} + +static void +dump_fmn_cpu_credits_for_gmac(struct xlr_board_info *board, int gmac_id) +{ + struct stn_cc *cc; + int gmac_bucket_ids[] = { 97, 98, 99, 100, 101, 103 }; + int j, k, r, c; + int n_gmac_buckets; + + n_gmac_buckets = sizeof (gmac_bucket_ids) / sizeof (gmac_bucket_ids[0]); + for (j = 0; j < 8; j++) { // for each cpu + cc = board->credit_configs[j]; + printf("Credits for Station CPU_%d ---> GMAC buckets (tx path)\n", j); + for (k = 0; k < n_gmac_buckets; k++) { + r = gmac_bucket_ids[k] / 8; + c = gmac_bucket_ids[k] % 8; + printf (" --> gmac%d_bucket_%-3d: credits=%d\n", gmac_id, + gmac_bucket_ids[k], cc->counters[r][c]); + } + } +} + +static void +dump_fmn_gmac_credits(struct xlr_board_info *board, int gmac_id) +{ + struct stn_cc *cc; + int j, k; + + cc = board->gmac_block[gmac_id].credit_config; + printf("Credits for Station: GMAC_%d ---> CPU buckets (rx path)\n", gmac_id); + for (j = 0; j < 8; j++) { // for each cpu + printf(" ---> cpu_%d\n", j); + for (k = 0; k < 8; k++) { // for each bucket in cpu + printf(" ---> bucket_%d: credits=%d\n", j * 8 + k, + cc->counters[j][k]); + } + } +} + +static void +dump_board_info(struct xlr_board_info *board) +{ + struct xlr_gmac_block_t *gm; + int i, k; + + printf("cpu=%x ", xlr_revision()); + printf("board_version: major=%llx, minor=%llx\n", + xlr_boot1_info.board_major_version, + xlr_boot1_info.board_minor_version); + printf("is_xls=%d, nr_cpus=%d, usb=%s, cfi=%s, ata=%s\npci_irq=%d," + "gmac_ports=%d\n", board->is_xls, board->nr_cpus, + board->usb ? "Yes" : "No", board->cfi ? "Yes": "No", + board->ata ? "Yes" : "No", board->pci_irq, board->gmacports); + printf("FMN: Core-station bucket sizes\n"); + for (i = 0; i < 128; i++) { + if (i && ((i % 16) == 0)) + printf("\n"); + printf ("b[%d] = %d ", i, board->bucket_sizes->bucket[i]); + } + printf("\n"); + for (i = 0; i < 3; i++) { + gm = &board->gmac_block[i]; + printf("RNA_%d: type=%d, enabled=%s, mode=%d, station_id=%d," + "station_txbase=%d, station_rfr=%d ", i, gm->type, + gm->enabled ? "Yes" : "No", gm->mode, gm->station_id, + gm->station_txbase, gm->station_rfr); + printf("n_ports=%d, baseaddr=%p, baseirq=%d, baseinst=%d\n", + gm->num_ports, (xlr_reg_t *)gm->baseaddr, gm->baseirq, + gm->baseinst); + } + for (k = 0; k < 3; k++) { // for each NA + dump_fmn_cpu_credits_for_gmac(board, k); + dump_fmn_gmac_credits(board, k); + } +} + +static void +dump_mac_stats(struct nlge_softc *sc) +{ + xlr_reg_t *addr; + uint32_t pkts_tx, pkts_rx; + + addr = sc->base; + pkts_rx = NLGE_READ(sc->base, R_RPKT); + pkts_tx = NLGE_READ(sc->base, R_TPKT); + + printf("[nlge_%d mac stats]: pkts_tx=%u, pkts_rx=%u\n", sc->id, pkts_tx, + pkts_rx); + if (pkts_rx > 0) { + uint32_t r; + + /* dump all rx counters. we need this because pkts_rx includes + bad packets. */ + for (r = R_RFCS; r <= R_ROVR; r++) + printf("[nlge_%d mac stats]: [0x%x]=%u\n", sc->id, r, + NLGE_READ(sc->base, r)); + } + if (pkts_tx > 0) { + uint32_t r; + + /* dump all tx counters. might be useful for debugging. */ + for (r = R_TMCA; r <= R_TFRG; r++) { + if ((r == (R_TNCL + 1)) || (r == (R_TNCL + 2))) + continue; + printf("[nlge_%d mac stats]: [0x%x]=%u\n", sc->id, r, + NLGE_READ(sc->base, r)); + } + } + +} + +static void +dump_mii_regs(struct nlge_softc *sc) +{ + uint32_t mii_regs[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xf, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e}; + int i, n_regs; + + if (sc->mii_base == NULL || sc->mii_bus == NULL) + return; + + n_regs = sizeof (mii_regs) / sizeof (mii_regs[0]); + for (i = 0; i < n_regs; i++) { + printf("[mii_0x%x] = %x\n", mii_regs[i], + nlge_mii_read_internal(sc->mii_base, sc->phy_addr, + mii_regs[i])); + } +} + +static void +dump_ifmedia(struct ifmedia *ifm) +{ + printf("ifm_mask=%08x, ifm_media=%08x, cur=%p\n", ifm->ifm_mask, + ifm->ifm_media, ifm->ifm_cur); + if (ifm->ifm_cur != NULL) { + printf("Cur attribs: ifmedia_entry.ifm_media=%08x," + " ifmedia_entry.ifm_data=%08x\n", ifm->ifm_cur->ifm_media, + ifm->ifm_cur->ifm_data); + } +} + +static void +dump_mii_data(struct mii_data *mii) +{ + dump_ifmedia(&mii->mii_media); + printf("ifp=%p, mii_instance=%d, mii_media_status=%08x," + " mii_media_active=%08x\n", mii->mii_ifp, mii->mii_instance, + mii->mii_media_status, mii->mii_media_active); +} + +static void +dump_pcs_regs(struct nlge_softc *sc, int phy) +{ + int i, val; + + printf("PCS regs from %p for phy=%d\n", sc->pcs_addr, phy); + for (i = 0; i < 18; i++) { + if (i == 2 || i == 3 || (i >= 9 && i <= 14)) + continue; + val = nlge_mii_read_internal(sc->pcs_addr, phy, i); + printf("PHY:%d pcs[0x%x] is 0x%x\n", phy, i, val); + } +} +#endif diff --git a/sys/mips/rmi/dev/nlge/if_nlge.h b/sys/mips/rmi/dev/nlge/if_nlge.h new file mode 100644 index 00000000000..0b24bc074a8 --- /dev/null +++ b/sys/mips/rmi/dev/nlge/if_nlge.h @@ -0,0 +1,1182 @@ +/*- + * Copyright (c) 2003-2009 RMI Corporation + * 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 RMI Corporation, 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 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$ + * + * RMI_BSD + */ + +/* #define MAC_SPLIT_MODE */ + +#define MAC_SPACING 0x400 +#define XGMAC_SPACING 0x400 + +/* PE-MCXMAC register and bit field definitions */ +#define R_MAC_CONFIG_1 0x00 +#define O_MAC_CONFIG_1__srst 31 +#define O_MAC_CONFIG_1__simr 30 +#define O_MAC_CONFIG_1__hrrmc 18 +#define W_MAC_CONFIG_1__hrtmc 2 +#define O_MAC_CONFIG_1__hrrfn 16 +#define W_MAC_CONFIG_1__hrtfn 2 +#define O_MAC_CONFIG_1__intlb 8 +#define O_MAC_CONFIG_1__rxfc 5 +#define O_MAC_CONFIG_1__txfc 4 +#define O_MAC_CONFIG_1__srxen 3 +#define O_MAC_CONFIG_1__rxen 2 +#define O_MAC_CONFIG_1__stxen 1 +#define O_MAC_CONFIG_1__txen 0 +#define R_MAC_CONFIG_2 0x01 +#define O_MAC_CONFIG_2__prlen 12 +#define W_MAC_CONFIG_2__prlen 4 +#define O_MAC_CONFIG_2__speed 8 +#define W_MAC_CONFIG_2__speed 2 +#define O_MAC_CONFIG_2__hugen 5 +#define O_MAC_CONFIG_2__flchk 4 +#define O_MAC_CONFIG_2__crce 1 +#define O_MAC_CONFIG_2__fulld 0 +#define R_IPG_IFG 0x02 +#define O_IPG_IFG__ipgr1 24 +#define W_IPG_IFG__ipgr1 7 +#define O_IPG_IFG__ipgr2 16 +#define W_IPG_IFG__ipgr2 7 +#define O_IPG_IFG__mifg 8 +#define W_IPG_IFG__mifg 8 +#define O_IPG_IFG__ipgt 0 +#define W_IPG_IFG__ipgt 7 +#define R_HALF_DUPLEX 0x03 +#define O_HALF_DUPLEX__abebt 24 +#define W_HALF_DUPLEX__abebt 4 +#define O_HALF_DUPLEX__abebe 19 +#define O_HALF_DUPLEX__bpnb 18 +#define O_HALF_DUPLEX__nobo 17 +#define O_HALF_DUPLEX__edxsdfr 16 +#define O_HALF_DUPLEX__retry 12 +#define W_HALF_DUPLEX__retry 4 +#define O_HALF_DUPLEX__lcol 0 +#define W_HALF_DUPLEX__lcol 10 +#define R_MAXIMUM_FRAME_LENGTH 0x04 +#define O_MAXIMUM_FRAME_LENGTH__maxf 0 +#define W_MAXIMUM_FRAME_LENGTH__maxf 16 +#define R_TEST 0x07 +#define O_TEST__mbof 3 +#define O_TEST__rthdf 2 +#define O_TEST__tpause 1 +#define O_TEST__sstct 0 +#define R_MII_MGMT_CONFIG 0x08 +#define O_MII_MGMT_CONFIG__scinc 5 +#define O_MII_MGMT_CONFIG__spre 4 +#define O_MII_MGMT_CONFIG__clks 3 +#define W_MII_MGMT_CONFIG__clks 3 +#define R_MII_MGMT_COMMAND 0x09 +#define O_MII_MGMT_COMMAND__scan 1 +#define O_MII_MGMT_COMMAND__rstat 0 +#define R_MII_MGMT_ADDRESS 0x0A +#define O_MII_MGMT_ADDRESS__fiad 8 +#define W_MII_MGMT_ADDRESS__fiad 5 +#define O_MII_MGMT_ADDRESS__fgad 5 +#define W_MII_MGMT_ADDRESS__fgad 0 +#define R_MII_MGMT_WRITE_DATA 0x0B +#define O_MII_MGMT_WRITE_DATA__ctld 0 +#define W_MII_MGMT_WRITE_DATA__ctld 16 +#define R_MII_MGMT_STATUS 0x0C +#define R_MII_MGMT_INDICATORS 0x0D +#define O_MII_MGMT_INDICATORS__nvalid 2 +#define O_MII_MGMT_INDICATORS__scan 1 +#define O_MII_MGMT_INDICATORS__busy 0 +#define R_INTERFACE_CONTROL 0x0E +#define O_INTERFACE_CONTROL__hrstint 31 +#define O_INTERFACE_CONTROL__tbimode 27 +#define O_INTERFACE_CONTROL__ghdmode 26 +#define O_INTERFACE_CONTROL__lhdmode 25 +#define O_INTERFACE_CONTROL__phymod 24 +#define O_INTERFACE_CONTROL__hrrmi 23 +#define O_INTERFACE_CONTROL__rspd 16 +#define O_INTERFACE_CONTROL__hr100 15 +#define O_INTERFACE_CONTROL__frcq 10 +#define O_INTERFACE_CONTROL__nocfr 9 +#define O_INTERFACE_CONTROL__dlfct 8 +#define O_INTERFACE_CONTROL__enjab 0 +#define R_INTERFACE_STATUS 0x0F +#define O_INTERFACE_STATUS__xsdfr 9 +#define O_INTERFACE_STATUS__ssrr 8 +#define W_INTERFACE_STATUS__ssrr 5 +#define O_INTERFACE_STATUS__miilf 3 +#define O_INTERFACE_STATUS__locar 2 +#define O_INTERFACE_STATUS__sqerr 1 +#define O_INTERFACE_STATUS__jabber 0 +#define R_STATION_ADDRESS_LS 0x10 +#define R_STATION_ADDRESS_MS 0x11 + +/* A-XGMAC register and bit field definitions */ +#define R_XGMAC_CONFIG_0 0x00 +#define O_XGMAC_CONFIG_0__hstmacrst 31 +#define O_XGMAC_CONFIG_0__hstrstrctl 23 +#define O_XGMAC_CONFIG_0__hstrstrfn 22 +#define O_XGMAC_CONFIG_0__hstrsttctl 18 +#define O_XGMAC_CONFIG_0__hstrsttfn 17 +#define O_XGMAC_CONFIG_0__hstrstmiim 16 +#define O_XGMAC_CONFIG_0__hstloopback 8 +#define R_XGMAC_CONFIG_1 0x01 +#define O_XGMAC_CONFIG_1__hsttctlen 31 +#define O_XGMAC_CONFIG_1__hsttfen 30 +#define O_XGMAC_CONFIG_1__hstrctlen 29 +#define O_XGMAC_CONFIG_1__hstrfen 28 +#define O_XGMAC_CONFIG_1__tfen 26 +#define O_XGMAC_CONFIG_1__rfen 24 +#define O_XGMAC_CONFIG_1__hstrctlshrtp 12 +#define O_XGMAC_CONFIG_1__hstdlyfcstx 10 +#define W_XGMAC_CONFIG_1__hstdlyfcstx 2 +#define O_XGMAC_CONFIG_1__hstdlyfcsrx 8 +#define W_XGMAC_CONFIG_1__hstdlyfcsrx 2 +#define O_XGMAC_CONFIG_1__hstppen 7 +#define O_XGMAC_CONFIG_1__hstbytswp 6 +#define O_XGMAC_CONFIG_1__hstdrplt64 5 +#define O_XGMAC_CONFIG_1__hstprmscrx 4 +#define O_XGMAC_CONFIG_1__hstlenchk 3 +#define O_XGMAC_CONFIG_1__hstgenfcs 2 +#define O_XGMAC_CONFIG_1__hstpadmode 0 +#define W_XGMAC_CONFIG_1__hstpadmode 2 +#define R_XGMAC_CONFIG_2 0x02 +#define O_XGMAC_CONFIG_2__hsttctlfrcp 31 +#define O_XGMAC_CONFIG_2__hstmlnkflth 27 +#define O_XGMAC_CONFIG_2__hstalnkflth 26 +#define O_XGMAC_CONFIG_2__rflnkflt 24 +#define W_XGMAC_CONFIG_2__rflnkflt 2 +#define O_XGMAC_CONFIG_2__hstipgextmod 16 +#define W_XGMAC_CONFIG_2__hstipgextmod 5 +#define O_XGMAC_CONFIG_2__hstrctlfrcp 15 +#define O_XGMAC_CONFIG_2__hstipgexten 5 +#define O_XGMAC_CONFIG_2__hstmipgext 0 +#define W_XGMAC_CONFIG_2__hstmipgext 5 +#define R_XGMAC_CONFIG_3 0x03 +#define O_XGMAC_CONFIG_3__hstfltrfrm 31 +#define W_XGMAC_CONFIG_3__hstfltrfrm 16 +#define O_XGMAC_CONFIG_3__hstfltrfrmdc 15 +#define W_XGMAC_CONFIG_3__hstfltrfrmdc 16 +#define R_XGMAC_STATION_ADDRESS_LS 0x04 +#define O_XGMAC_STATION_ADDRESS_LS__hstmacadr0 0 +#define W_XGMAC_STATION_ADDRESS_LS__hstmacadr0 32 +#define R_XGMAC_STATION_ADDRESS_MS 0x05 +#define R_XGMAC_MAX_FRAME_LEN 0x08 +#define O_XGMAC_MAX_FRAME_LEN__hstmxfrmwctx 16 +#define W_XGMAC_MAX_FRAME_LEN__hstmxfrmwctx 14 +#define O_XGMAC_MAX_FRAME_LEN__hstmxfrmbcrx 0 +#define W_XGMAC_MAX_FRAME_LEN__hstmxfrmbcrx 16 +#define R_XGMAC_REV_LEVEL 0x0B +#define O_XGMAC_REV_LEVEL__revlvl 0 +#define W_XGMAC_REV_LEVEL__revlvl 15 +#define R_XGMAC_MIIM_COMMAND 0x10 +#define O_XGMAC_MIIM_COMMAND__hstldcmd 3 +#define O_XGMAC_MIIM_COMMAND__hstmiimcmd 0 +#define W_XGMAC_MIIM_COMMAND__hstmiimcmd 3 +#define R_XGMAC_MIIM_FILED 0x11 +#define O_XGMAC_MIIM_FILED__hststfield 30 +#define W_XGMAC_MIIM_FILED__hststfield 2 +#define O_XGMAC_MIIM_FILED__hstopfield 28 +#define W_XGMAC_MIIM_FILED__hstopfield 2 +#define O_XGMAC_MIIM_FILED__hstphyadx 23 +#define W_XGMAC_MIIM_FILED__hstphyadx 5 +#define O_XGMAC_MIIM_FILED__hstregadx 18 +#define W_XGMAC_MIIM_FILED__hstregadx 5 +#define O_XGMAC_MIIM_FILED__hsttafield 16 +#define W_XGMAC_MIIM_FILED__hsttafield 2 +#define O_XGMAC_MIIM_FILED__miimrddat 0 +#define W_XGMAC_MIIM_FILED__miimrddat 16 +#define R_XGMAC_MIIM_CONFIG 0x12 +#define O_XGMAC_MIIM_CONFIG__hstnopram 7 +#define O_XGMAC_MIIM_CONFIG__hstclkdiv 0 +#define W_XGMAC_MIIM_CONFIG__hstclkdiv 7 +#define R_XGMAC_MIIM_LINK_FAIL_VECTOR 0x13 +#define O_XGMAC_MIIM_LINK_FAIL_VECTOR__miimlfvec 0 +#define W_XGMAC_MIIM_LINK_FAIL_VECTOR__miimlfvec 32 +#define R_XGMAC_MIIM_INDICATOR 0x14 +#define O_XGMAC_MIIM_INDICATOR__miimphylf 4 +#define O_XGMAC_MIIM_INDICATOR__miimmoncplt 3 +#define O_XGMAC_MIIM_INDICATOR__miimmonvld 2 +#define O_XGMAC_MIIM_INDICATOR__miimmon 1 +#define O_XGMAC_MIIM_INDICATOR__miimbusy 0 + +/* GMAC stats registers */ +#define R_RBYT 0x27 +#define R_RPKT 0x28 +#define R_RFCS 0x29 +#define R_RMCA 0x2A +#define R_RBCA 0x2B +#define R_RXCF 0x2C +#define R_RXPF 0x2D +#define R_RXUO 0x2E +#define R_RALN 0x2F +#define R_RFLR 0x30 +#define R_RCDE 0x31 +#define R_RCSE 0x32 +#define R_RUND 0x33 +#define R_ROVR 0x34 +#define R_TBYT 0x38 +#define R_TPKT 0x39 +#define R_TMCA 0x3A +#define R_TBCA 0x3B +#define R_TXPF 0x3C +#define R_TDFR 0x3D +#define R_TEDF 0x3E +#define R_TSCL 0x3F +#define R_TMCL 0x40 +#define R_TLCL 0x41 +#define R_TXCL 0x42 +#define R_TNCL 0x43 +#define R_TJBR 0x46 +#define R_TFCS 0x47 +#define R_TXCF 0x48 +#define R_TOVR 0x49 +#define R_TUND 0x4A +#define R_TFRG 0x4B + +/* Glue logic register and bit field definitions */ +#define R_MAC_ADDR0 0x50 +#define R_MAC_ADDR1 0x52 +#define R_MAC_ADDR2 0x54 +#define R_MAC_ADDR3 0x56 +#define R_MAC_ADDR_MASK2 0x58 +#define R_MAC_ADDR_MASK3 0x5A +#define R_MAC_FILTER_CONFIG 0x5C +#define O_MAC_FILTER_CONFIG__BROADCAST_EN 10 +#define O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN 9 +#define O_MAC_FILTER_CONFIG__ALL_MCAST_EN 8 +#define O_MAC_FILTER_CONFIG__ALL_UCAST_EN 7 +#define O_MAC_FILTER_CONFIG__HASH_MCAST_EN 6 +#define O_MAC_FILTER_CONFIG__HASH_UCAST_EN 5 +#define O_MAC_FILTER_CONFIG__ADDR_MATCH_DISC 4 +#define O_MAC_FILTER_CONFIG__MAC_ADDR3_VALID 3 +#define O_MAC_FILTER_CONFIG__MAC_ADDR2_VALID 2 +#define O_MAC_FILTER_CONFIG__MAC_ADDR1_VALID 1 +#define O_MAC_FILTER_CONFIG__MAC_ADDR0_VALID 0 +#define R_HASH_TABLE_VECTOR 0x30 +#define R_TX_CONTROL 0x0A0 +#define O_TX_CONTROL__Tx15Halt 31 +#define O_TX_CONTROL__Tx14Halt 30 +#define O_TX_CONTROL__Tx13Halt 29 +#define O_TX_CONTROL__Tx12Halt 28 +#define O_TX_CONTROL__Tx11Halt 27 +#define O_TX_CONTROL__Tx10Halt 26 +#define O_TX_CONTROL__Tx9Halt 25 +#define O_TX_CONTROL__Tx8Halt 24 +#define O_TX_CONTROL__Tx7Halt 23 +#define O_TX_CONTROL__Tx6Halt 22 +#define O_TX_CONTROL__Tx5Halt 21 +#define O_TX_CONTROL__Tx4Halt 20 +#define O_TX_CONTROL__Tx3Halt 19 +#define O_TX_CONTROL__Tx2Halt 18 +#define O_TX_CONTROL__Tx1Halt 17 +#define O_TX_CONTROL__Tx0Halt 16 +#define O_TX_CONTROL__TxIdle 15 +#define O_TX_CONTROL__TxEnable 14 +#define O_TX_CONTROL__TxThreshold 0 +#define W_TX_CONTROL__TxThreshold 14 +#define R_RX_CONTROL 0x0A1 +#define O_RX_CONTROL__RGMII 10 +#define O_RX_CONTROL__SoftReset 2 +#define O_RX_CONTROL__RxHalt 1 +#define O_RX_CONTROL__RxEnable 0 +#define R_DESC_PACK_CTRL 0x0A2 +#define O_DESC_PACK_CTRL__ByteOffset 17 +#define W_DESC_PACK_CTRL__ByteOffset 3 +#define O_DESC_PACK_CTRL__PrePadEnable 16 +#define O_DESC_PACK_CTRL__MaxEntry 14 +#define W_DESC_PACK_CTRL__MaxEntry 2 +#define O_DESC_PACK_CTRL__RegularSize 0 +#define W_DESC_PACK_CTRL__RegularSize 14 +#define R_STATCTRL 0x0A3 +#define O_STATCTRL__OverFlowEn 4 +#define O_STATCTRL__GIG 3 +#define O_STATCTRL__Sten 2 +#define O_STATCTRL__ClrCnt 1 +#define O_STATCTRL__AutoZ 0 +#define R_L2ALLOCCTRL 0x0A4 +#define O_L2ALLOCCTRL__TxL2Allocate 9 +#define W_L2ALLOCCTRL__TxL2Allocate 9 +#define O_L2ALLOCCTRL__RxL2Allocate 0 +#define W_L2ALLOCCTRL__RxL2Allocate 9 +#define R_INTMASK 0x0A5 +#define O_INTMASK__Spi4TxError 28 +#define O_INTMASK__Spi4RxError 27 +#define O_INTMASK__RGMIIHalfDupCollision 27 +#define O_INTMASK__Abort 26 +#define O_INTMASK__Underrun 25 +#define O_INTMASK__DiscardPacket 24 +#define O_INTMASK__AsyncFifoFull 23 +#define O_INTMASK__TagFull 22 +#define O_INTMASK__Class3Full 21 +#define O_INTMASK__C3EarlyFull 20 +#define O_INTMASK__Class2Full 19 +#define O_INTMASK__C2EarlyFull 18 +#define O_INTMASK__Class1Full 17 +#define O_INTMASK__C1EarlyFull 16 +#define O_INTMASK__Class0Full 15 +#define O_INTMASK__C0EarlyFull 14 +#define O_INTMASK__RxDataFull 13 +#define O_INTMASK__RxEarlyFull 12 +#define O_INTMASK__RFreeEmpty 9 +#define O_INTMASK__RFEarlyEmpty 8 +#define O_INTMASK__P2PSpillEcc 7 +#define O_INTMASK__FreeDescFull 5 +#define O_INTMASK__FreeEarlyFull 4 +#define O_INTMASK__TxFetchError 3 +#define O_INTMASK__StatCarry 2 +#define O_INTMASK__MDInt 1 +#define O_INTMASK__TxIllegal 0 +#define R_INTREG 0x0A6 +#define O_INTREG__Spi4TxError 28 +#define O_INTREG__Spi4RxError 27 +#define O_INTREG__RGMIIHalfDupCollision 27 +#define O_INTREG__Abort 26 +#define O_INTREG__Underrun 25 +#define O_INTREG__DiscardPacket 24 +#define O_INTREG__AsyncFifoFull 23 +#define O_INTREG__TagFull 22 +#define O_INTREG__Class3Full 21 +#define O_INTREG__C3EarlyFull 20 +#define O_INTREG__Class2Full 19 +#define O_INTREG__C2EarlyFull 18 +#define O_INTREG__Class1Full 17 +#define O_INTREG__C1EarlyFull 16 +#define O_INTREG__Class0Full 15 +#define O_INTREG__C0EarlyFull 14 +#define O_INTREG__RxDataFull 13 +#define O_INTREG__RxEarlyFull 12 +#define O_INTREG__RFreeEmpty 9 +#define O_INTREG__RFEarlyEmpty 8 +#define O_INTREG__P2PSpillEcc 7 +#define O_INTREG__FreeDescFull 5 +#define O_INTREG__FreeEarlyFull 4 +#define O_INTREG__TxFetchError 3 +#define O_INTREG__StatCarry 2 +#define O_INTREG__MDInt 1 +#define O_INTREG__TxIllegal 0 +#define R_TXRETRY 0x0A7 +#define O_TXRETRY__CollisionRetry 6 +#define O_TXRETRY__BusErrorRetry 5 +#define O_TXRETRY__UnderRunRetry 4 +#define O_TXRETRY__Retries 0 +#define W_TXRETRY__Retries 4 +#define R_CORECONTROL 0x0A8 +#define O_CORECONTROL__ErrorThread 4 +#define W_CORECONTROL__ErrorThread 7 +#define O_CORECONTROL__Shutdown 2 +#define O_CORECONTROL__Speed 0 +#define W_CORECONTROL__Speed 2 +#define R_BYTEOFFSET0 0x0A9 +#define R_BYTEOFFSET1 0x0AA +#define R_L2TYPE_0 0x0F0 +#define O_L2TYPE__ExtraHdrProtoSize 26 +#define W_L2TYPE__ExtraHdrProtoSize 5 +#define O_L2TYPE__ExtraHdrProtoOffset 20 +#define W_L2TYPE__ExtraHdrProtoOffset 6 +#define O_L2TYPE__ExtraHeaderSize 14 +#define W_L2TYPE__ExtraHeaderSize 6 +#define O_L2TYPE__ProtoOffset 8 +#define W_L2TYPE__ProtoOffset 6 +#define O_L2TYPE__L2HdrOffset 2 +#define W_L2TYPE__L2HdrOffset 6 +#define O_L2TYPE__L2Proto 0 +#define W_L2TYPE__L2Proto 2 +#define R_L2TYPE_1 0xF0 +#define R_L2TYPE_2 0xF0 +#define R_L2TYPE_3 0xF0 +#define R_PARSERCONFIGREG 0x100 +#define O_PARSERCONFIGREG__CRCHashPoly 8 +#define W_PARSERCONFIGREG__CRCHashPoly 7 +#define O_PARSERCONFIGREG__PrePadOffset 4 +#define W_PARSERCONFIGREG__PrePadOffset 4 +#define O_PARSERCONFIGREG__UseCAM 2 +#define O_PARSERCONFIGREG__UseHASH 1 +#define O_PARSERCONFIGREG__UseProto 0 +#define R_L3CTABLE 0x140 +#define O_L3CTABLE__Offset0 25 +#define W_L3CTABLE__Offset0 7 +#define O_L3CTABLE__Len0 21 +#define W_L3CTABLE__Len0 4 +#define O_L3CTABLE__Offset1 14 +#define W_L3CTABLE__Offset1 7 +#define O_L3CTABLE__Len1 10 +#define W_L3CTABLE__Len1 4 +#define O_L3CTABLE__Offset2 4 +#define W_L3CTABLE__Offset2 6 +#define O_L3CTABLE__Len2 0 +#define W_L3CTABLE__Len2 4 +#define O_L3CTABLE__L3HdrOffset 26 +#define W_L3CTABLE__L3HdrOffset 6 +#define O_L3CTABLE__L4ProtoOffset 20 +#define W_L3CTABLE__L4ProtoOffset 6 +#define O_L3CTABLE__IPChksumCompute 19 +#define O_L3CTABLE__L4Classify 18 +#define O_L3CTABLE__L2Proto 16 +#define W_L3CTABLE__L2Proto 2 +#define O_L3CTABLE__L3ProtoKey 0 +#define W_L3CTABLE__L3ProtoKey 16 +#define R_L4CTABLE 0x160 +#define O_L4CTABLE__Offset0 21 +#define W_L4CTABLE__Offset0 6 +#define O_L4CTABLE__Len0 17 +#define W_L4CTABLE__Len0 4 +#define O_L4CTABLE__Offset1 11 +#define W_L4CTABLE__Offset1 6 +#define O_L4CTABLE__Len1 7 +#define W_L4CTABLE__Len1 4 +#define O_L4CTABLE__TCPChksumEnable 0 +#define R_CAM4X128TABLE 0x172 +#define O_CAM4X128TABLE__ClassId 7 +#define W_CAM4X128TABLE__ClassId 2 +#define O_CAM4X128TABLE__BucketId 1 +#define W_CAM4X128TABLE__BucketId 6 +#define O_CAM4X128TABLE__UseBucket 0 +#define R_CAM4X128KEY 0x180 +#define R_TRANSLATETABLE 0x1A0 +#define R_DMACR0 0x200 +#define O_DMACR0__Data0WrMaxCr 27 +#define W_DMACR0__Data0WrMaxCr 3 +#define O_DMACR0__Data0RdMaxCr 24 +#define W_DMACR0__Data0RdMaxCr 3 +#define O_DMACR0__Data1WrMaxCr 21 +#define W_DMACR0__Data1WrMaxCr 3 +#define O_DMACR0__Data1RdMaxCr 18 +#define W_DMACR0__Data1RdMaxCr 3 +#define O_DMACR0__Data2WrMaxCr 15 +#define W_DMACR0__Data2WrMaxCr 3 +#define O_DMACR0__Data2RdMaxCr 12 +#define W_DMACR0__Data2RdMaxCr 3 +#define O_DMACR0__Data3WrMaxCr 9 +#define W_DMACR0__Data3WrMaxCr 3 +#define O_DMACR0__Data3RdMaxCr 6 +#define W_DMACR0__Data3RdMaxCr 3 +#define O_DMACR0__Data4WrMaxCr 3 +#define W_DMACR0__Data4WrMaxCr 3 +#define O_DMACR0__Data4RdMaxCr 0 +#define W_DMACR0__Data4RdMaxCr 3 +#define R_DMACR1 0x201 +#define O_DMACR1__Data5WrMaxCr 27 +#define W_DMACR1__Data5WrMaxCr 3 +#define O_DMACR1__Data5RdMaxCr 24 +#define W_DMACR1__Data5RdMaxCr 3 +#define O_DMACR1__Data6WrMaxCr 21 +#define W_DMACR1__Data6WrMaxCr 3 +#define O_DMACR1__Data6RdMaxCr 18 +#define W_DMACR1__Data6RdMaxCr 3 +#define O_DMACR1__Data7WrMaxCr 15 +#define W_DMACR1__Data7WrMaxCr 3 +#define O_DMACR1__Data7RdMaxCr 12 +#define W_DMACR1__Data7RdMaxCr 3 +#define O_DMACR1__Data8WrMaxCr 9 +#define W_DMACR1__Data8WrMaxCr 3 +#define O_DMACR1__Data8RdMaxCr 6 +#define W_DMACR1__Data8RdMaxCr 3 +#define O_DMACR1__Data9WrMaxCr 3 +#define W_DMACR1__Data9WrMaxCr 3 +#define O_DMACR1__Data9RdMaxCr 0 +#define W_DMACR1__Data9RdMaxCr 3 +#define R_DMACR2 0x202 +#define O_DMACR2__Data10WrMaxCr 27 +#define W_DMACR2__Data10WrMaxCr 3 +#define O_DMACR2__Data10RdMaxCr 24 +#define W_DMACR2__Data10RdMaxCr 3 +#define O_DMACR2__Data11WrMaxCr 21 +#define W_DMACR2__Data11WrMaxCr 3 +#define O_DMACR2__Data11RdMaxCr 18 +#define W_DMACR2__Data11RdMaxCr 3 +#define O_DMACR2__Data12WrMaxCr 15 +#define W_DMACR2__Data12WrMaxCr 3 +#define O_DMACR2__Data12RdMaxCr 12 +#define W_DMACR2__Data12RdMaxCr 3 +#define O_DMACR2__Data13WrMaxCr 9 +#define W_DMACR2__Data13WrMaxCr 3 +#define O_DMACR2__Data13RdMaxCr 6 +#define W_DMACR2__Data13RdMaxCr 3 +#define O_DMACR2__Data14WrMaxCr 3 +#define W_DMACR2__Data14WrMaxCr 3 +#define O_DMACR2__Data14RdMaxCr 0 +#define W_DMACR2__Data14RdMaxCr 3 +#define R_DMACR3 0x203 +#define O_DMACR3__Data15WrMaxCr 27 +#define W_DMACR3__Data15WrMaxCr 3 +#define O_DMACR3__Data15RdMaxCr 24 +#define W_DMACR3__Data15RdMaxCr 3 +#define O_DMACR3__SpClassWrMaxCr 21 +#define W_DMACR3__SpClassWrMaxCr 3 +#define O_DMACR3__SpClassRdMaxCr 18 +#define W_DMACR3__SpClassRdMaxCr 3 +#define O_DMACR3__JumFrInWrMaxCr 15 +#define W_DMACR3__JumFrInWrMaxCr 3 +#define O_DMACR3__JumFrInRdMaxCr 12 +#define W_DMACR3__JumFrInRdMaxCr 3 +#define O_DMACR3__RegFrInWrMaxCr 9 +#define W_DMACR3__RegFrInWrMaxCr 3 +#define O_DMACR3__RegFrInRdMaxCr 6 +#define W_DMACR3__RegFrInRdMaxCr 3 +#define O_DMACR3__FrOutWrMaxCr 3 +#define W_DMACR3__FrOutWrMaxCr 3 +#define O_DMACR3__FrOutRdMaxCr 0 +#define W_DMACR3__FrOutRdMaxCr 3 +#define R_REG_FRIN_SPILL_MEM_START_0 0x204 +#define O_REG_FRIN_SPILL_MEM_START_0__RegFrInSpillMemStart0 0 +#define W_REG_FRIN_SPILL_MEM_START_0__RegFrInSpillMemStart0 32 +#define R_REG_FRIN_SPILL_MEM_START_1 0x205 +#define O_REG_FRIN_SPILL_MEM_START_1__RegFrInSpillMemStart1 0 +#define W_REG_FRIN_SPILL_MEM_START_1__RegFrInSpillMemStart1 3 +#define R_REG_FRIN_SPILL_MEM_SIZE 0x206 +#define O_REG_FRIN_SPILL_MEM_SIZE__RegFrInSpillMemSize 0 +#define W_REG_FRIN_SPILL_MEM_SIZE__RegFrInSpillMemSize 32 +#define R_FROUT_SPILL_MEM_START_0 0x207 +#define O_FROUT_SPILL_MEM_START_0__FrOutSpillMemStart0 0 +#define W_FROUT_SPILL_MEM_START_0__FrOutSpillMemStart0 32 +#define R_FROUT_SPILL_MEM_START_1 0x208 +#define O_FROUT_SPILL_MEM_START_1__FrOutSpillMemStart1 0 +#define W_FROUT_SPILL_MEM_START_1__FrOutSpillMemStart1 3 +#define R_FROUT_SPILL_MEM_SIZE 0x209 +#define O_FROUT_SPILL_MEM_SIZE__FrOutSpillMemSize 0 +#define W_FROUT_SPILL_MEM_SIZE__FrOutSpillMemSize 32 +#define R_CLASS0_SPILL_MEM_START_0 0x20A +#define O_CLASS0_SPILL_MEM_START_0__Class0SpillMemStart0 0 +#define W_CLASS0_SPILL_MEM_START_0__Class0SpillMemStart0 32 +#define R_CLASS0_SPILL_MEM_START_1 0x20B +#define O_CLASS0_SPILL_MEM_START_1__Class0SpillMemStart1 0 +#define W_CLASS0_SPILL_MEM_START_1__Class0SpillMemStart1 3 +#define R_CLASS0_SPILL_MEM_SIZE 0x20C +#define O_CLASS0_SPILL_MEM_SIZE__Class0SpillMemSize 0 +#define W_CLASS0_SPILL_MEM_SIZE__Class0SpillMemSize 32 +#define R_JUMFRIN_SPILL_MEM_START_0 0x20D +#define O_JUMFRIN_SPILL_MEM_START_0__JumFrInSpillMemStar0 0 +#define W_JUMFRIN_SPILL_MEM_START_0__JumFrInSpillMemStar0 32 +#define R_JUMFRIN_SPILL_MEM_START_1 0x20E +#define O_JUMFRIN_SPILL_MEM_START_1__JumFrInSpillMemStart1 0 +#define W_JUMFRIN_SPILL_MEM_START_1__JumFrInSpillMemStart1 3 +#define R_JUMFRIN_SPILL_MEM_SIZE 0x20F +#define O_JUMFRIN_SPILL_MEM_SIZE__JumFrInSpillMemSize 0 +#define W_JUMFRIN_SPILL_MEM_SIZE__JumFrInSpillMemSize 32 +#define R_CLASS1_SPILL_MEM_START_0 0x210 +#define O_CLASS1_SPILL_MEM_START_0__Class1SpillMemStart0 0 +#define W_CLASS1_SPILL_MEM_START_0__Class1SpillMemStart0 32 +#define R_CLASS1_SPILL_MEM_START_1 0x211 +#define O_CLASS1_SPILL_MEM_START_1__Class1SpillMemStart1 0 +#define W_CLASS1_SPILL_MEM_START_1__Class1SpillMemStart1 3 +#define R_CLASS1_SPILL_MEM_SIZE 0x212 +#define O_CLASS1_SPILL_MEM_SIZE__Class1SpillMemSize 0 +#define W_CLASS1_SPILL_MEM_SIZE__Class1SpillMemSize 32 +#define R_CLASS2_SPILL_MEM_START_0 0x213 +#define O_CLASS2_SPILL_MEM_START_0__Class2SpillMemStart0 0 +#define W_CLASS2_SPILL_MEM_START_0__Class2SpillMemStart0 32 +#define R_CLASS2_SPILL_MEM_START_1 0x214 +#define O_CLASS2_SPILL_MEM_START_1__Class2SpillMemStart1 0 +#define W_CLASS2_SPILL_MEM_START_1__Class2SpillMemStart1 3 +#define R_CLASS2_SPILL_MEM_SIZE 0x215 +#define O_CLASS2_SPILL_MEM_SIZE__Class2SpillMemSize 0 +#define W_CLASS2_SPILL_MEM_SIZE__Class2SpillMemSize 32 +#define R_CLASS3_SPILL_MEM_START_0 0x216 +#define O_CLASS3_SPILL_MEM_START_0__Class3SpillMemStart0 0 +#define W_CLASS3_SPILL_MEM_START_0__Class3SpillMemStart0 32 +#define R_CLASS3_SPILL_MEM_START_1 0x217 +#define O_CLASS3_SPILL_MEM_START_1__Class3SpillMemStart1 0 +#define W_CLASS3_SPILL_MEM_START_1__Class3SpillMemStart1 3 +#define R_CLASS3_SPILL_MEM_SIZE 0x218 +#define O_CLASS3_SPILL_MEM_SIZE__Class3SpillMemSize 0 +#define W_CLASS3_SPILL_MEM_SIZE__Class3SpillMemSize 32 +#define R_REG_FRIN1_SPILL_MEM_START_0 0x219 +#define R_REG_FRIN1_SPILL_MEM_START_1 0x21a +#define R_REG_FRIN1_SPILL_MEM_SIZE 0x21b +#define R_SPIHNGY0 0x219 +#define O_SPIHNGY0__EG_HNGY_THRESH_0 24 +#define W_SPIHNGY0__EG_HNGY_THRESH_0 7 +#define O_SPIHNGY0__EG_HNGY_THRESH_1 16 +#define W_SPIHNGY0__EG_HNGY_THRESH_1 7 +#define O_SPIHNGY0__EG_HNGY_THRESH_2 8 +#define W_SPIHNGY0__EG_HNGY_THRESH_2 7 +#define O_SPIHNGY0__EG_HNGY_THRESH_3 0 +#define W_SPIHNGY0__EG_HNGY_THRESH_3 7 +#define R_SPIHNGY1 0x21A +#define O_SPIHNGY1__EG_HNGY_THRESH_4 24 +#define W_SPIHNGY1__EG_HNGY_THRESH_4 7 +#define O_SPIHNGY1__EG_HNGY_THRESH_5 16 +#define W_SPIHNGY1__EG_HNGY_THRESH_5 7 +#define O_SPIHNGY1__EG_HNGY_THRESH_6 8 +#define W_SPIHNGY1__EG_HNGY_THRESH_6 7 +#define O_SPIHNGY1__EG_HNGY_THRESH_7 0 +#define W_SPIHNGY1__EG_HNGY_THRESH_7 7 +#define R_SPIHNGY2 0x21B +#define O_SPIHNGY2__EG_HNGY_THRESH_8 24 +#define W_SPIHNGY2__EG_HNGY_THRESH_8 7 +#define O_SPIHNGY2__EG_HNGY_THRESH_9 16 +#define W_SPIHNGY2__EG_HNGY_THRESH_9 7 +#define O_SPIHNGY2__EG_HNGY_THRESH_10 8 +#define W_SPIHNGY2__EG_HNGY_THRESH_10 7 +#define O_SPIHNGY2__EG_HNGY_THRESH_11 0 +#define W_SPIHNGY2__EG_HNGY_THRESH_11 7 +#define R_SPIHNGY3 0x21C +#define O_SPIHNGY3__EG_HNGY_THRESH_12 24 +#define W_SPIHNGY3__EG_HNGY_THRESH_12 7 +#define O_SPIHNGY3__EG_HNGY_THRESH_13 16 +#define W_SPIHNGY3__EG_HNGY_THRESH_13 7 +#define O_SPIHNGY3__EG_HNGY_THRESH_14 8 +#define W_SPIHNGY3__EG_HNGY_THRESH_14 7 +#define O_SPIHNGY3__EG_HNGY_THRESH_15 0 +#define W_SPIHNGY3__EG_HNGY_THRESH_15 7 +#define R_SPISTRV0 0x21D +#define O_SPISTRV0__EG_STRV_THRESH_0 24 +#define W_SPISTRV0__EG_STRV_THRESH_0 7 +#define O_SPISTRV0__EG_STRV_THRESH_1 16 +#define W_SPISTRV0__EG_STRV_THRESH_1 7 +#define O_SPISTRV0__EG_STRV_THRESH_2 8 +#define W_SPISTRV0__EG_STRV_THRESH_2 7 +#define O_SPISTRV0__EG_STRV_THRESH_3 0 +#define W_SPISTRV0__EG_STRV_THRESH_3 7 +#define R_SPISTRV1 0x21E +#define O_SPISTRV1__EG_STRV_THRESH_4 24 +#define W_SPISTRV1__EG_STRV_THRESH_4 7 +#define O_SPISTRV1__EG_STRV_THRESH_5 16 +#define W_SPISTRV1__EG_STRV_THRESH_5 7 +#define O_SPISTRV1__EG_STRV_THRESH_6 8 +#define W_SPISTRV1__EG_STRV_THRESH_6 7 +#define O_SPISTRV1__EG_STRV_THRESH_7 0 +#define W_SPISTRV1__EG_STRV_THRESH_7 7 +#define R_SPISTRV2 0x21F +#define O_SPISTRV2__EG_STRV_THRESH_8 24 +#define W_SPISTRV2__EG_STRV_THRESH_8 7 +#define O_SPISTRV2__EG_STRV_THRESH_9 16 +#define W_SPISTRV2__EG_STRV_THRESH_9 7 +#define O_SPISTRV2__EG_STRV_THRESH_10 8 +#define W_SPISTRV2__EG_STRV_THRESH_10 7 +#define O_SPISTRV2__EG_STRV_THRESH_11 0 +#define W_SPISTRV2__EG_STRV_THRESH_11 7 +#define R_SPISTRV3 0x220 +#define O_SPISTRV3__EG_STRV_THRESH_12 24 +#define W_SPISTRV3__EG_STRV_THRESH_12 7 +#define O_SPISTRV3__EG_STRV_THRESH_13 16 +#define W_SPISTRV3__EG_STRV_THRESH_13 7 +#define O_SPISTRV3__EG_STRV_THRESH_14 8 +#define W_SPISTRV3__EG_STRV_THRESH_14 7 +#define O_SPISTRV3__EG_STRV_THRESH_15 0 +#define W_SPISTRV3__EG_STRV_THRESH_15 7 +#define R_TXDATAFIFO0 0x221 +#define O_TXDATAFIFO0__Tx0DataFifoStart 24 +#define W_TXDATAFIFO0__Tx0DataFifoStart 7 +#define O_TXDATAFIFO0__Tx0DataFifoSize 16 +#define W_TXDATAFIFO0__Tx0DataFifoSize 7 +#define O_TXDATAFIFO0__Tx1DataFifoStart 8 +#define W_TXDATAFIFO0__Tx1DataFifoStart 7 +#define O_TXDATAFIFO0__Tx1DataFifoSize 0 +#define W_TXDATAFIFO0__Tx1DataFifoSize 7 +#define R_TXDATAFIFO1 0x222 +#define O_TXDATAFIFO1__Tx2DataFifoStart 24 +#define W_TXDATAFIFO1__Tx2DataFifoStart 7 +#define O_TXDATAFIFO1__Tx2DataFifoSize 16 +#define W_TXDATAFIFO1__Tx2DataFifoSize 7 +#define O_TXDATAFIFO1__Tx3DataFifoStart 8 +#define W_TXDATAFIFO1__Tx3DataFifoStart 7 +#define O_TXDATAFIFO1__Tx3DataFifoSize 0 +#define W_TXDATAFIFO1__Tx3DataFifoSize 7 +#define R_TXDATAFIFO2 0x223 +#define O_TXDATAFIFO2__Tx4DataFifoStart 24 +#define W_TXDATAFIFO2__Tx4DataFifoStart 7 +#define O_TXDATAFIFO2__Tx4DataFifoSize 16 +#define W_TXDATAFIFO2__Tx4DataFifoSize 7 +#define O_TXDATAFIFO2__Tx5DataFifoStart 8 +#define W_TXDATAFIFO2__Tx5DataFifoStart 7 +#define O_TXDATAFIFO2__Tx5DataFifoSize 0 +#define W_TXDATAFIFO2__Tx5DataFifoSize 7 +#define R_TXDATAFIFO3 0x224 +#define O_TXDATAFIFO3__Tx6DataFifoStart 24 +#define W_TXDATAFIFO3__Tx6DataFifoStart 7 +#define O_TXDATAFIFO3__Tx6DataFifoSize 16 +#define W_TXDATAFIFO3__Tx6DataFifoSize 7 +#define O_TXDATAFIFO3__Tx7DataFifoStart 8 +#define W_TXDATAFIFO3__Tx7DataFifoStart 7 +#define O_TXDATAFIFO3__Tx7DataFifoSize 0 +#define W_TXDATAFIFO3__Tx7DataFifoSize 7 +#define R_TXDATAFIFO4 0x225 +#define O_TXDATAFIFO4__Tx8DataFifoStart 24 +#define W_TXDATAFIFO4__Tx8DataFifoStart 7 +#define O_TXDATAFIFO4__Tx8DataFifoSize 16 +#define W_TXDATAFIFO4__Tx8DataFifoSize 7 +#define O_TXDATAFIFO4__Tx9DataFifoStart 8 +#define W_TXDATAFIFO4__Tx9DataFifoStart 7 +#define O_TXDATAFIFO4__Tx9DataFifoSize 0 +#define W_TXDATAFIFO4__Tx9DataFifoSize 7 +#define R_TXDATAFIFO5 0x226 +#define O_TXDATAFIFO5__Tx10DataFifoStart 24 +#define W_TXDATAFIFO5__Tx10DataFifoStart 7 +#define O_TXDATAFIFO5__Tx10DataFifoSize 16 +#define W_TXDATAFIFO5__Tx10DataFifoSize 7 +#define O_TXDATAFIFO5__Tx11DataFifoStart 8 +#define W_TXDATAFIFO5__Tx11DataFifoStart 7 +#define O_TXDATAFIFO5__Tx11DataFifoSize 0 +#define W_TXDATAFIFO5__Tx11DataFifoSize 7 +#define R_TXDATAFIFO6 0x227 +#define O_TXDATAFIFO6__Tx12DataFifoStart 24 +#define W_TXDATAFIFO6__Tx12DataFifoStart 7 +#define O_TXDATAFIFO6__Tx12DataFifoSize 16 +#define W_TXDATAFIFO6__Tx12DataFifoSize 7 +#define O_TXDATAFIFO6__Tx13DataFifoStart 8 +#define W_TXDATAFIFO6__Tx13DataFifoStart 7 +#define O_TXDATAFIFO6__Tx13DataFifoSize 0 +#define W_TXDATAFIFO6__Tx13DataFifoSize 7 +#define R_TXDATAFIFO7 0x228 +#define O_TXDATAFIFO7__Tx14DataFifoStart 24 +#define W_TXDATAFIFO7__Tx14DataFifoStart 7 +#define O_TXDATAFIFO7__Tx14DataFifoSize 16 +#define W_TXDATAFIFO7__Tx14DataFifoSize 7 +#define O_TXDATAFIFO7__Tx15DataFifoStart 8 +#define W_TXDATAFIFO7__Tx15DataFifoStart 7 +#define O_TXDATAFIFO7__Tx15DataFifoSize 0 +#define W_TXDATAFIFO7__Tx15DataFifoSize 7 +#define R_RXDATAFIFO0 0x229 +#define O_RXDATAFIFO0__Rx0DataFifoStart 24 +#define W_RXDATAFIFO0__Rx0DataFifoStart 7 +#define O_RXDATAFIFO0__Rx0DataFifoSize 16 +#define W_RXDATAFIFO0__Rx0DataFifoSize 7 +#define O_RXDATAFIFO0__Rx1DataFifoStart 8 +#define W_RXDATAFIFO0__Rx1DataFifoStart 7 +#define O_RXDATAFIFO0__Rx1DataFifoSize 0 +#define W_RXDATAFIFO0__Rx1DataFifoSize 7 +#define R_RXDATAFIFO1 0x22A +#define O_RXDATAFIFO1__Rx2DataFifoStart 24 +#define W_RXDATAFIFO1__Rx2DataFifoStart 7 +#define O_RXDATAFIFO1__Rx2DataFifoSize 16 +#define W_RXDATAFIFO1__Rx2DataFifoSize 7 +#define O_RXDATAFIFO1__Rx3DataFifoStart 8 +#define W_RXDATAFIFO1__Rx3DataFifoStart 7 +#define O_RXDATAFIFO1__Rx3DataFifoSize 0 +#define W_RXDATAFIFO1__Rx3DataFifoSize 7 +#define R_RXDATAFIFO2 0x22B +#define O_RXDATAFIFO2__Rx4DataFifoStart 24 +#define W_RXDATAFIFO2__Rx4DataFifoStart 7 +#define O_RXDATAFIFO2__Rx4DataFifoSize 16 +#define W_RXDATAFIFO2__Rx4DataFifoSize 7 +#define O_RXDATAFIFO2__Rx5DataFifoStart 8 +#define W_RXDATAFIFO2__Rx5DataFifoStart 7 +#define O_RXDATAFIFO2__Rx5DataFifoSize 0 +#define W_RXDATAFIFO2__Rx5DataFifoSize 7 +#define R_RXDATAFIFO3 0x22C +#define O_RXDATAFIFO3__Rx6DataFifoStart 24 +#define W_RXDATAFIFO3__Rx6DataFifoStart 7 +#define O_RXDATAFIFO3__Rx6DataFifoSize 16 +#define W_RXDATAFIFO3__Rx6DataFifoSize 7 +#define O_RXDATAFIFO3__Rx7DataFifoStart 8 +#define W_RXDATAFIFO3__Rx7DataFifoStart 7 +#define O_RXDATAFIFO3__Rx7DataFifoSize 0 +#define W_RXDATAFIFO3__Rx7DataFifoSize 7 +#define R_RXDATAFIFO4 0x22D +#define O_RXDATAFIFO4__Rx8DataFifoStart 24 +#define W_RXDATAFIFO4__Rx8DataFifoStart 7 +#define O_RXDATAFIFO4__Rx8DataFifoSize 16 +#define W_RXDATAFIFO4__Rx8DataFifoSize 7 +#define O_RXDATAFIFO4__Rx9DataFifoStart 8 +#define W_RXDATAFIFO4__Rx9DataFifoStart 7 +#define O_RXDATAFIFO4__Rx9DataFifoSize 0 +#define W_RXDATAFIFO4__Rx9DataFifoSize 7 +#define R_RXDATAFIFO5 0x22E +#define O_RXDATAFIFO5__Rx10DataFifoStart 24 +#define W_RXDATAFIFO5__Rx10DataFifoStart 7 +#define O_RXDATAFIFO5__Rx10DataFifoSize 16 +#define W_RXDATAFIFO5__Rx10DataFifoSize 7 +#define O_RXDATAFIFO5__Rx11DataFifoStart 8 +#define W_RXDATAFIFO5__Rx11DataFifoStart 7 +#define O_RXDATAFIFO5__Rx11DataFifoSize 0 +#define W_RXDATAFIFO5__Rx11DataFifoSize 7 +#define R_RXDATAFIFO6 0x22F +#define O_RXDATAFIFO6__Rx12DataFifoStart 24 +#define W_RXDATAFIFO6__Rx12DataFifoStart 7 +#define O_RXDATAFIFO6__Rx12DataFifoSize 16 +#define W_RXDATAFIFO6__Rx12DataFifoSize 7 +#define O_RXDATAFIFO6__Rx13DataFifoStart 8 +#define W_RXDATAFIFO6__Rx13DataFifoStart 7 +#define O_RXDATAFIFO6__Rx13DataFifoSize 0 +#define W_RXDATAFIFO6__Rx13DataFifoSize 7 +#define R_RXDATAFIFO7 0x230 +#define O_RXDATAFIFO7__Rx14DataFifoStart 24 +#define W_RXDATAFIFO7__Rx14DataFifoStart 7 +#define O_RXDATAFIFO7__Rx14DataFifoSize 16 +#define W_RXDATAFIFO7__Rx14DataFifoSize 7 +#define O_RXDATAFIFO7__Rx15DataFifoStart 8 +#define W_RXDATAFIFO7__Rx15DataFifoStart 7 +#define O_RXDATAFIFO7__Rx15DataFifoSize 0 +#define W_RXDATAFIFO7__Rx15DataFifoSize 7 +#define R_XGMACPADCALIBRATION 0x231 +#define R_FREEQCARVE 0x233 +#define R_SPI4STATICDELAY0 0x240 +#define O_SPI4STATICDELAY0__DataLine7 28 +#define W_SPI4STATICDELAY0__DataLine7 4 +#define O_SPI4STATICDELAY0__DataLine6 24 +#define W_SPI4STATICDELAY0__DataLine6 4 +#define O_SPI4STATICDELAY0__DataLine5 20 +#define W_SPI4STATICDELAY0__DataLine5 4 +#define O_SPI4STATICDELAY0__DataLine4 16 +#define W_SPI4STATICDELAY0__DataLine4 4 +#define O_SPI4STATICDELAY0__DataLine3 12 +#define W_SPI4STATICDELAY0__DataLine3 4 +#define O_SPI4STATICDELAY0__DataLine2 8 +#define W_SPI4STATICDELAY0__DataLine2 4 +#define O_SPI4STATICDELAY0__DataLine1 4 +#define W_SPI4STATICDELAY0__DataLine1 4 +#define O_SPI4STATICDELAY0__DataLine0 0 +#define W_SPI4STATICDELAY0__DataLine0 4 +#define R_SPI4STATICDELAY1 0x241 +#define O_SPI4STATICDELAY1__DataLine15 28 +#define W_SPI4STATICDELAY1__DataLine15 4 +#define O_SPI4STATICDELAY1__DataLine14 24 +#define W_SPI4STATICDELAY1__DataLine14 4 +#define O_SPI4STATICDELAY1__DataLine13 20 +#define W_SPI4STATICDELAY1__DataLine13 4 +#define O_SPI4STATICDELAY1__DataLine12 16 +#define W_SPI4STATICDELAY1__DataLine12 4 +#define O_SPI4STATICDELAY1__DataLine11 12 +#define W_SPI4STATICDELAY1__DataLine11 4 +#define O_SPI4STATICDELAY1__DataLine10 8 +#define W_SPI4STATICDELAY1__DataLine10 4 +#define O_SPI4STATICDELAY1__DataLine9 4 +#define W_SPI4STATICDELAY1__DataLine9 4 +#define O_SPI4STATICDELAY1__DataLine8 0 +#define W_SPI4STATICDELAY1__DataLine8 4 +#define R_SPI4STATICDELAY2 0x242 +#define O_SPI4STATICDELAY0__TxStat1 8 +#define W_SPI4STATICDELAY0__TxStat1 4 +#define O_SPI4STATICDELAY0__TxStat0 4 +#define W_SPI4STATICDELAY0__TxStat0 4 +#define O_SPI4STATICDELAY0__RxControl 0 +#define W_SPI4STATICDELAY0__RxControl 4 +#define R_SPI4CONTROL 0x243 +#define O_SPI4CONTROL__StaticDelay 2 +#define O_SPI4CONTROL__LVDS_LVTTL 1 +#define O_SPI4CONTROL__SPI4Enable 0 +#define R_CLASSWATERMARKS 0x244 +#define O_CLASSWATERMARKS__Class0Watermark 24 +#define W_CLASSWATERMARKS__Class0Watermark 5 +#define O_CLASSWATERMARKS__Class1Watermark 16 +#define W_CLASSWATERMARKS__Class1Watermark 5 +#define O_CLASSWATERMARKS__Class3Watermark 0 +#define W_CLASSWATERMARKS__Class3Watermark 5 +#define R_RXWATERMARKS1 0x245 +#define O_RXWATERMARKS__Rx0DataWatermark 24 +#define W_RXWATERMARKS__Rx0DataWatermark 7 +#define O_RXWATERMARKS__Rx1DataWatermark 16 +#define W_RXWATERMARKS__Rx1DataWatermark 7 +#define O_RXWATERMARKS__Rx3DataWatermark 0 +#define W_RXWATERMARKS__Rx3DataWatermark 7 +#define R_RXWATERMARKS2 0x246 +#define O_RXWATERMARKS__Rx4DataWatermark 24 +#define W_RXWATERMARKS__Rx4DataWatermark 7 +#define O_RXWATERMARKS__Rx5DataWatermark 16 +#define W_RXWATERMARKS__Rx5DataWatermark 7 +#define O_RXWATERMARKS__Rx6DataWatermark 8 +#define W_RXWATERMARKS__Rx6DataWatermark 7 +#define O_RXWATERMARKS__Rx7DataWatermark 0 +#define W_RXWATERMARKS__Rx7DataWatermark 7 +#define R_RXWATERMARKS3 0x247 +#define O_RXWATERMARKS__Rx8DataWatermark 24 +#define W_RXWATERMARKS__Rx8DataWatermark 7 +#define O_RXWATERMARKS__Rx9DataWatermark 16 +#define W_RXWATERMARKS__Rx9DataWatermark 7 +#define O_RXWATERMARKS__Rx10DataWatermark 8 +#define W_RXWATERMARKS__Rx10DataWatermark 7 +#define O_RXWATERMARKS__Rx11DataWatermark 0 +#define W_RXWATERMARKS__Rx11DataWatermark 7 +#define R_RXWATERMARKS4 0x248 +#define O_RXWATERMARKS__Rx12DataWatermark 24 +#define W_RXWATERMARKS__Rx12DataWatermark 7 +#define O_RXWATERMARKS__Rx13DataWatermark 16 +#define W_RXWATERMARKS__Rx13DataWatermark 7 +#define O_RXWATERMARKS__Rx14DataWatermark 8 +#define W_RXWATERMARKS__Rx14DataWatermark 7 +#define O_RXWATERMARKS__Rx15DataWatermark 0 +#define W_RXWATERMARKS__Rx15DataWatermark 7 +#define R_FREEWATERMARKS 0x249 +#define O_FREEWATERMARKS__FreeOutWatermark 16 +#define W_FREEWATERMARKS__FreeOutWatermark 16 +#define O_FREEWATERMARKS__JumFrWatermark 8 +#define W_FREEWATERMARKS__JumFrWatermark 7 +#define O_FREEWATERMARKS__RegFrWatermark 0 +#define W_FREEWATERMARKS__RegFrWatermark 7 +#define R_EGRESSFIFOCARVINGSLOTS 0x24a + +#define CTRL_RES0 0 +#define CTRL_RES1 1 +#define CTRL_REG_FREE 2 +#define CTRL_JUMBO_FREE 3 +#define CTRL_CONT 4 +#define CTRL_EOP 5 +#define CTRL_START 6 +#define CTRL_SNGL 7 + +#define CTRL_B0_NOT_EOP 0 +#define CTRL_B0_EOP 1 + +#define R_ROUND_ROBIN_TABLE 0 +#define R_PDE_CLASS_0 0x300 +#define R_PDE_CLASS_1 0x302 +#define R_PDE_CLASS_2 0x304 +#define R_PDE_CLASS_3 0x306 + +#define R_MSG_TX_THRESHOLD 0x308 + +#define R_GMAC_JFR0_BUCKET_SIZE 0x320 +#define R_GMAC_RFR0_BUCKET_SIZE 0x321 +#define R_GMAC_TX0_BUCKET_SIZE 0x322 +#define R_GMAC_TX1_BUCKET_SIZE 0x323 +#define R_GMAC_TX2_BUCKET_SIZE 0x324 +#define R_GMAC_TX3_BUCKET_SIZE 0x325 +#define R_GMAC_JFR1_BUCKET_SIZE 0x326 +#define R_GMAC_RFR1_BUCKET_SIZE 0x327 + +#define R_XGS_TX0_BUCKET_SIZE 0x320 +#define R_XGS_TX1_BUCKET_SIZE 0x321 +#define R_XGS_TX2_BUCKET_SIZE 0x322 +#define R_XGS_TX3_BUCKET_SIZE 0x323 +#define R_XGS_TX4_BUCKET_SIZE 0x324 +#define R_XGS_TX5_BUCKET_SIZE 0x325 +#define R_XGS_TX6_BUCKET_SIZE 0x326 +#define R_XGS_TX7_BUCKET_SIZE 0x327 +#define R_XGS_TX8_BUCKET_SIZE 0x328 +#define R_XGS_TX9_BUCKET_SIZE 0x329 +#define R_XGS_TX10_BUCKET_SIZE 0x32A +#define R_XGS_TX11_BUCKET_SIZE 0x32B +#define R_XGS_TX12_BUCKET_SIZE 0x32C +#define R_XGS_TX13_BUCKET_SIZE 0x32D +#define R_XGS_TX14_BUCKET_SIZE 0x32E +#define R_XGS_TX15_BUCKET_SIZE 0x32F +#define R_XGS_JFR_BUCKET_SIZE 0x330 +#define R_XGS_RFR_BUCKET_SIZE 0x331 + +#define R_CC_CPU0_0 0x380 +#define R_CC_CPU1_0 0x388 +#define R_CC_CPU2_0 0x390 +#define R_CC_CPU3_0 0x398 +#define R_CC_CPU4_0 0x3a0 +#define R_CC_CPU5_0 0x3a8 +#define R_CC_CPU6_0 0x3b0 +#define R_CC_CPU7_0 0x3b8 + +#define XLR_GMAC_BLK_SZ (XLR_IO_GMAC_1_OFFSET - \ + XLR_IO_GMAC_0_OFFSET) + +/* Constants used for configuring the devices */ + +#define RGE_TX_THRESHOLD 1024 +#define RGE_TX_Q_SIZE 1024 + +#define MAC_B2B_IPG 88 + +/* frame sizes need to be cacheline aligned */ +#define MAX_FRAME_SIZE 1536 +#define MAX_FRAME_SIZE_JUMBO 9216 +#define RGE_TX_THRESHOLD_BYTES ETHER_MAX_LEN + +#define MAC_SKB_BACK_PTR_SIZE SMP_CACHE_BYTES +#define MAC_PREPAD 0 +#define BYTE_OFFSET 2 +#define XLR_RX_BUF_SIZE (MAX_FRAME_SIZE + BYTE_OFFSET + \ + MAC_PREPAD + MAC_SKB_BACK_PTR_SIZE + SMP_CACHE_BYTES) +#define MAC_CRC_LEN 4 +#define MAX_NUM_MSGRNG_STN_CC 128 +#define MAX_MSG_SND_ATTEMPTS 100 /* 13 stns x 4 entry msg/stn + + headroom */ + +#define MAC_FRIN_TO_BE_SENT_THRESHOLD 16 + +#define MAX_NUM_DESC_SPILL 1024 +#define MAX_FRIN_SPILL (MAX_NUM_DESC_SPILL << 2) +#define MAX_FROUT_SPILL (MAX_NUM_DESC_SPILL << 2) +#define MAX_CLASS_0_SPILL (MAX_NUM_DESC_SPILL << 2) +#define MAX_CLASS_1_SPILL (MAX_NUM_DESC_SPILL << 2) +#define MAX_CLASS_2_SPILL (MAX_NUM_DESC_SPILL << 2) +#define MAX_CLASS_3_SPILL (MAX_NUM_DESC_SPILL << 2) + +#define XLR_MAX_CORE 8 + +#define XLR_MAX_NLNA 3 +#define XLR_MAX_MACS 8 +#define XLR_MAX_TX_FRAGS 14 +#define MAX_P2D_DESC_PER_PORT 512 + +#define PHY_STATUS_RETRIES 25000 + + +/* Structs representing hardware data structures */ +struct size_1_desc { + uint64_t entry0; +}; + +struct size_2_desc { + uint64_t entry0; + uint64_t entry1; +}; + +struct size_3_desc { + uint64_t entry0; + uint64_t entry1; + uint64_t entry2; +}; + +struct size_4_desc { + uint64_t entry0; + uint64_t entry1; + uint64_t entry2; + uint64_t entry3; +}; + +struct fr_desc { + struct size_1_desc d1; +}; + +union rx_tx_desc { + struct size_2_desc d2; + /* struct size_3_desc d3; */ + /* struct size_4_desc d4; */ +}; + + +extern unsigned char xlr_base_mac_addr[]; + +/* Driver data structures and enums */ + +typedef enum { + xlr_mac_speed_10, xlr_mac_speed_100, + xlr_mac_speed_1000, xlr_mac_speed_rsvd +} xlr_mac_speed_t; + +typedef enum { + xlr_mac_duplex_auto, xlr_mac_duplex_half, + xlr_mac_duplex_full +} xlr_mac_duplex_t; + +typedef enum { + xlr_mac_link_down, + xlr_mac_link_up, +} xlr_mac_link_t; + +typedef enum { + xlr_mac_fc_auto, xlr_mac_fc_disabled, xlr_mac_fc_frame, + xlr_mac_fc_collision, xlr_mac_fc_carrier +} xlr_mac_fc_t; + +enum { + SGMII_SPEED_10 = 0x00000000, + SGMII_SPEED_100 = 0x02000000, + SGMII_SPEED_1000 = 0x04000000, +}; + +struct nlge_softc; + +/* + * A data-structure to hold a set of related ports. The "sense" in which they + * are related is defined by the user of this data-structure. + * + * One example: a set of ports that are controlled thru a single MDIO line. + */ +struct nlge_port_set { + struct nlge_softc **port_vec; + uint32_t vec_sz; +}; + +/* + * nlna_softc has Network Accelerator (NA) attributes that are necessary to + * configure the h/w registers of this block. All the commmon configuration + * for a set of GMAC ports controlled by an NA is done from here. + */ +struct nlna_softc { + device_t nlna_dev; + + uint32_t num_ports; + int na_type; + int mac_type; + xlr_reg_t *base; + + struct callout tx_thr; + struct fr_desc *frin_spill; + struct fr_desc *frout_spill; + union rx_tx_desc *class_0_spill; + union rx_tx_desc *class_1_spill; + union rx_tx_desc *class_2_spill; + union rx_tx_desc *class_3_spill; + uint32_t rfrbucket; + uint32_t station_id; + + struct nlge_softc *child_sc[XLR_MAX_MACS]; + + /* + * Set of ports controlled/configured by the MII line + * of this network accelerator. + */ + struct nlge_port_set mdio_set; + struct nlge_softc *mdio_sc[XLR_MAX_MACS]; +}; + +struct nlge_softc { + struct ifnet *nlge_if; /* should be first member - cf. + mii.c:miibus_attach() */ + struct mii_data nlge_mii; + struct nlge_port_set *mdio_pset; + device_t nlge_dev; + device_t mii_bus; + xlr_reg_t *base; + xlr_reg_t *mii_base; + xlr_reg_t *pcs_addr; + xlr_reg_t *serdes_addr; + int port_type; + int if_flags; + xlr_mac_speed_t speed; + xlr_mac_duplex_t duplex; + xlr_mac_link_t link; + xlr_mac_fc_t flow_ctrl; + uint32_t id; + uint32_t instance; + uint32_t phy_addr; + uint32_t tx_bucket_id; + uint8_t dev_addr[ETHER_ADDR_LEN]; + struct mtx sc_lock; +}; + + +struct nlge_tx_desc { + uint64_t frag[XLR_MAX_TX_FRAGS + 2]; +}; + +#define MAX_TX_RING_SIZE (XLR_MAX_MACS * MAX_P2D_DESC_PER_PORT *\ + sizeof(struct p2d_tx_desc)) + +#define NLGE_WRITE(base, off, val) xlr_write_reg(base, off, val) +#define NLGE_READ(base, off) xlr_read_reg(base, off) +#define NLGE_UPDATE(base, off, val, mask) \ + do { \ + uint32_t rd_val, wrt_val; \ + rd_val = NLGE_READ(base, off); \ + wrt_val = (rd_val & ~mask) | (val & mask); \ + NLGE_WRITE(base, off, wrt_val); \ + } while (0) + +#define NLGE_LOCK_INIT(_sc, _name) \ + mtx_init(&(_sc)->sc_lock, _name, MTX_NETWORK_LOCK, MTX_DEF) +#define NLGE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_lock) +#define NLGE_LOCK(_sc) mtx_lock(&(_sc)->sc_lock) +#define NLGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock) +#define NLGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED) + diff --git a/sys/mips/rmi/dev/sec/desc.h b/sys/mips/rmi/dev/sec/desc.h index 5757e13a765..1238d001060 100644 --- a/sys/mips/rmi/dev/sec/desc.h +++ b/sys/mips/rmi/dev/sec/desc.h @@ -26,6 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ * RMI_BSD */ #ifndef _DESC_H_ #define _DESC_H_ @@ -2320,7 +2321,7 @@ typedef struct OperationDescriptor_s { uint32_t flags; uint32_t cpu; uint32_t seq_num; - uint64_t reserved; + uint64_t vaddr; } OperationDescriptor_t, *OperationDescriptor_pt; diff --git a/sys/mips/rmi/dev/sec/rmilib.c b/sys/mips/rmi/dev/sec/rmilib.c index 6068e5d2852..014bfc87280 100644 --- a/sys/mips/rmi/dev/sec/rmilib.c +++ b/sys/mips/rmi/dev/sec/rmilib.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -49,20 +48,19 @@ __FBSDID("$FreeBSD$"); #include - -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -// static int msgrng_stnid_pk0 = MSGRNG_STNID_PK0; +/* static int msgrng_stnid_pk0 = MSGRNG_STNID_PK0; */ -/*#define RMI_SEC_DEBUG */ +/* #define RMI_SEC_DEBUG */ #define SMP_CACHE_BYTES XLR_CACHELINE_SIZE #define NUM_CHUNKS(size, bits) ( ((size)>>(bits)) + (((size)&((1<<(bits))-1))?1:0) ) @@ -72,86 +70,44 @@ symkey_desc_pt g_desc; struct xlr_sec_command *g_cmd; #ifdef XLR_SEC_CMD_DEBUG -static void - decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector); - +static void decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector); #endif -void print_buf(char *desc, void *data, int len); +static int xlr_sec_cipher_hash_command(xlr_sec_io_pt op, symkey_desc_pt desc, + uint8_t); +static xlr_sec_error_t xlr_sec_setup_descriptor(xlr_sec_io_pt op, + unsigned int flags, symkey_desc_pt desc, uint32_t * cfg_vector); -static int - xlr_sec_cipher_hash_command(xlr_sec_io_pt op, symkey_desc_pt desc, uint8_t); - -static xlr_sec_error_t -xlr_sec_setup_descriptor(xlr_sec_io_pt op, - unsigned int flags, - symkey_desc_pt desc, - uint32_t * cfg_vector); - -static -xlr_sec_error_t -xlr_sec_setup_packet(xlr_sec_io_pt op, - symkey_desc_pt desc, - unsigned int flags, - uint64_t * data, - PacketDescriptor_pt pkt_desc, - ControlDescriptor_pt ctl_desc, - uint32_t vector, - PacketDescriptor_pt next_pkt_desc, +static xlr_sec_error_t xlr_sec_setup_packet(xlr_sec_io_pt op, + symkey_desc_pt desc, unsigned int flags, uint64_t * data, + PacketDescriptor_pt pkt_desc, ControlDescriptor_pt ctl_desc, + uint32_t vector, PacketDescriptor_pt next_pkt_desc, uint8_t multi_frag_flag); - -static int - xlr_sec_submit_message(symkey_desc_pt desc, uint32_t cfg_vector); - -static -xlr_sec_error_t -xlr_sec_setup_cipher(xlr_sec_io_pt op, - ControlDescriptor_pt ctl_desc, - uint32_t * vector); - -static -xlr_sec_error_t -xlr_sec_setup_digest(xlr_sec_io_pt op, - ControlDescriptor_pt ctl_desc, - uint32_t * vector); - -static -xlr_sec_error_t -xlr_sec_setup_cksum(xlr_sec_io_pt op, +static int xlr_sec_submit_message(symkey_desc_pt desc, uint32_t cfg_vector); +static xlr_sec_error_t xlr_sec_setup_cipher(xlr_sec_io_pt op, + ControlDescriptor_pt ctl_desc, uint32_t * vector); +static xlr_sec_error_t xlr_sec_setup_digest(xlr_sec_io_pt op, + ControlDescriptor_pt ctl_desc, uint32_t * vector); +static xlr_sec_error_t xlr_sec_setup_cksum(xlr_sec_io_pt op, ControlDescriptor_pt ctl_desc); +static xlr_sec_error_t xlr_sec_control_setup(xlr_sec_io_pt op, + unsigned int flags, uint64_t * control, ControlDescriptor_pt ctl_desc, + xlr_sec_drv_user_t * user, uint32_t vector); +static void xlr_sec_free_desc(symkey_desc_pt desc); -static -xlr_sec_error_t -xlr_sec_control_setup(xlr_sec_io_pt op, - unsigned int flags, - uint64_t * control, - ControlDescriptor_pt ctl_desc, - xlr_sec_drv_user_t * user, - uint32_t vector); - - -xlr_sec_error_t -xlr_sec_submit_op(symkey_desc_pt desc); - -static void xlr_sec_free_desc(symkey_desc_pt desc); - -void -xlr_sec_msgring_handler(int bucket, int size, int code, int stid, +void print_buf(char *desc, void *data, int len); +xlr_sec_error_t xlr_sec_submit_op(symkey_desc_pt desc); +void xlr_sec_msgring_handler(int bucket, int size, int code, int stid, struct msgrng_msg *msg, void *data); - void xlr_sec_init(struct xlr_sec_softc *sc) { unsigned int i; xlr_reg_t *mmio; - mmio = sc->mmio = xlr_io_mmio(XLR_IO_SECURITY_OFFSET); - xlr_write_reg(mmio, SEC_DMA_CREDIT, SEC_DMA_CREDIT_CONFIG); - - xlr_write_reg(mmio, SEC_CONFIG2, SEC_CFG2_ROUND_ROBIN_ON); for (i = 0; i < 8; i++) @@ -168,7 +124,6 @@ xlr_sec_init(struct xlr_sec_softc *sc) xls_cc_table_sec.counters[i >> 3][i & 0x07] : cc_table_sec.counters[i >> 3][i & 0x07]); - /* * Register a bucket handler with the phoenix messaging subsystem * For now, register handler for bucket 0->5 in msg stn 0 @@ -179,30 +134,23 @@ xlr_sec_init(struct xlr_sec_softc *sc) return; } - - int xlr_sec_setup(struct xlr_sec_session *ses, struct xlr_sec_command *cmd, - symkey_desc_pt desc -) + symkey_desc_pt desc) { xlr_sec_io_pt op; int size, ret_val; int iv_len; - desc->ses = ses; op = &cmd->op; if (op == NULL) return (-ENOMEM); - - desc->ctl_desc.instruction = 0; memset(&desc->ctl_desc.cipherHashInfo, 0, sizeof(CipherHashInfo_t)); desc->control = 0; - desc->pkt_desc[0].srcLengthIVOffUseIVNext = 0; desc->pkt_desc[0].dstDataSettings = 0; desc->pkt_desc[0].authDstNonceLow = 0; @@ -211,12 +159,10 @@ xlr_sec_setup(struct xlr_sec_session *ses, desc->pkt_desc[1].dstDataSettings = 0; desc->pkt_desc[1].authDstNonceLow = 0; desc->pkt_desc[1].ckSumDstNonceHiCFBMaskLLWMask = 0; - desc->data = 0; desc->ctl_result = 0; desc->data_result = 0; - if (op->flags & XLR_SEC_FLAGS_HIGH_PRIORITY) if (!xlr_is_xls()) desc->op_ctl.stn_id++; @@ -225,7 +171,6 @@ xlr_sec_setup(struct xlr_sec_session *ses, desc->user.user_dest = (uint8_t *) (unsigned long)op->dest_buf; desc->user.user_auth = (uint8_t *) (unsigned long)op->auth_dest; - if ((op->cipher_type == XLR_SEC_CIPHER_TYPE_ARC4) && (!op->rc4_state && (op->rc4_loadstate || op->rc4_savestate))) { printf(" ** Load/Save State and no State **"); @@ -234,7 +179,6 @@ xlr_sec_setup(struct xlr_sec_session *ses, } desc->user.user_state = (uint8_t *) (unsigned long)op->rc4_state; - switch (op->cipher_type) { case XLR_SEC_CIPHER_TYPE_NONE: iv_len = 0; @@ -260,10 +204,6 @@ xlr_sec_setup(struct xlr_sec_session *ses, xlr_sec_free_desc(desc); return (-EINVAL); } - - - - size = op->source_buf_size + iv_len; /* @@ -276,7 +216,8 @@ xlr_sec_setup(struct xlr_sec_session *ses, if (op->cipher_type == XLR_SEC_CIPHER_TYPE_NONE) { if (op->source_buf_size != 0) { - memcpy(desc->user.aligned_src, (uint8_t *) (unsigned long)op->source_buf, + memcpy(desc->user.aligned_src, + (uint8_t *)(uintptr_t)op->source_buf, op->source_buf_size); } } else { @@ -306,12 +247,9 @@ xlr_sec_setup(struct xlr_sec_session *ses, } } - - /* Set source to new kernel space */ op->source_buf = (uint64_t) (unsigned long)desc->user.aligned_src; - /* * Build new dest buffer, for Cipher output only */ @@ -324,7 +262,6 @@ xlr_sec_setup(struct xlr_sec_session *ses, } else { /* DEBUG -dpk */ XLR_SEC_CMD_DIAG("dest_buf_size = %d \n", op->dest_buf_size); - size = op->dest_buf_size + iv_len; /* @@ -335,11 +272,9 @@ xlr_sec_setup(struct xlr_sec_session *ses, op->cipher_mode == XLR_SEC_CIPHER_MODE_CTR) size += XLR_SEC_AES_BLOCK_SIZE - 1; op->dest_buf = (uint64_t) (unsigned long)desc->user.aligned_dest; - } ret_val = xlr_sec_cipher_hash_command(op, desc, ses->multi_frag_flag); - return (ret_val); } @@ -396,7 +331,6 @@ xlr_sec_cipher_hash_command(xlr_sec_io_pt op, symkey_desc_pt desc, return err; } - static xlr_sec_error_t xlr_sec_setup_descriptor(xlr_sec_io_pt op, unsigned int flags, @@ -407,7 +341,6 @@ xlr_sec_setup_descriptor(xlr_sec_io_pt op, XLR_SEC_CMD_DIAG("xlr_sec_setup_descriptor: ENTER\n"); - if ((err = xlr_sec_setup_cipher(op, &desc->ctl_desc, cfg_vector)) != XLR_SEC_ERR_NONE) { XLR_SEC_CMD_DIAG("xlr_sec_setup_descriptor: xlr_sec_setup_cipher done err %d\n", (int)err); @@ -483,7 +416,7 @@ xlr_sec_setup_packet(xlr_sec_io_pt op, len = op->source_buf_size + byte_offset - global_offset; if (multi_frag_flag) { - next_seg_addr = (uint64_t) vtophys((void *)(unsigned long)(desc->next_src_buf)); + next_seg_addr = (uint64_t)vtophys((void *)(uintptr_t)desc->next_src_buf); next_seg_addr = (next_seg_addr & ~(SMP_CACHE_BYTES - 1)); next_len = desc->next_src_len; } @@ -505,14 +438,12 @@ xlr_sec_setup_packet(xlr_sec_io_pt op, */ cipher_offset_dwords = (op->iv_offset + byte_offset) >> 3; - if (op->cipher_mode == XLR_SEC_CIPHER_MODE_F8 || op->cipher_mode == XLR_SEC_CIPHER_MODE_CTR) { if (multi_frag_flag) { int nlhmac = ((op->source_buf_size + global_offset + 7 - op->cipher_offset) >> 3) & 1; pkt_desc->srcLengthIVOffUseIVNext = - FIELD_VALUE(PKT_DSC_HASHBYTES, len & 7) | FIELD_VALUE(PKT_DSC_IVOFF, cipher_offset_dwords) | FIELD_VALUE(PKT_DSC_PKTLEN, nlhmac + ((len + 7) >> 3)) | @@ -539,7 +470,6 @@ xlr_sec_setup_packet(xlr_sec_io_pt op, } else { if (multi_frag_flag) { pkt_desc->srcLengthIVOffUseIVNext = - FIELD_VALUE(PKT_DSC_HASHBYTES, len & 7) | FIELD_VALUE(PKT_DSC_IVOFF, cipher_offset_dwords) | FIELD_VALUE(PKT_DSC_PKTLEN, (len + 7) >> 3) | @@ -890,7 +820,6 @@ xlr_sec_setup_packet(xlr_sec_io_pt op, CLEAR_SET_FIELD(next_pkt_desc->ckSumDstNonceHiCFBMaskLLWMask, PKT_DSC_CKSUM_DST_ADDR, (uint64_t) vtophys((void *)(unsigned long)desc->next_cksum_dest)); - } } /* @@ -902,17 +831,13 @@ xlr_sec_setup_packet(xlr_sec_io_pt op, XLR_SEC_CMD_DIAG(" xlr_sec_setup_packet(): pkt_desc=%p phys_pkt_desc=%llx \n", pkt_desc, (unsigned long long)vtophys(pkt_desc)); - - CLEAR_SET_FIELD(*data, MSG_CMD_DATA_ADDR, ((uint64_t) vtophys(pkt_desc))); CLEAR_SET_FIELD(*data, MSG_CMD_DATA_CTL, SEC_EOP); CLEAR_SET_FIELD(*data, MSG_CMD_DATA_LEN, MSG_CMD_DATA_LEN_LOAD); - XLR_SEC_CMD_DIAG("xlr_sec_setup_packet: DONE\n"); #ifdef RMI_SEC_DEBUG - { printf("data desc\n"); printf("srcLengthIVOffUseIVNext = 0x%llx\n", pkt_desc->srcLengthIVOffUseIVNext); @@ -1036,9 +961,7 @@ xlr_sec_submit_message(symkey_desc_pt desc, uint32_t cfg_vector) int ret_val = 0; XLR_SEC_CMD_DIAG("xlr_sec_submit_message: ENTER\n"); - err = XLR_SEC_ERR_NONE; - XLR_SEC_CMD_DIAG_SYM_DESC(desc, cfg_vector); do { @@ -1206,7 +1129,6 @@ xlr_sec_setup_cipher(xlr_sec_io_pt op, return XLR_SEC_ERR_NONE; } - static xlr_sec_error_t xlr_sec_setup_digest(xlr_sec_io_pt op, @@ -1304,7 +1226,6 @@ xlr_sec_setup_digest(xlr_sec_io_pt op, *vector |= digest_vector; XLR_SEC_CMD_DIAG("xlr_sec_setup_digest: EXIT vector = %04x\n", *vector); - return XLR_SEC_ERR_NONE; } @@ -1350,7 +1271,6 @@ xlr_sec_control_setup(xlr_sec_io_pt op, XLR_SEC_CMD_DIAG(" ENTER vector = %04x\n", vector); #endif - switch (vector) { case XLR_SEC_VECTOR_MAC: XLR_SEC_CMD_DIAG(" XLR_SEC_VECTOR_MAC \n"); @@ -1970,7 +1890,6 @@ xlr_sec_control_setup(xlr_sec_io_pt op, return XLR_SEC_ERR_NONE; } - xlr_sec_error_t xlr_sec_submit_op(symkey_desc_pt desc) { @@ -2013,31 +1932,18 @@ xlr_sec_submit_op(symkey_desc_pt desc) XLR_SEC_CMD_DIAG("[%s]: IN_IRQ=%d msg0=0x%llx msg1=0x%llx \n", __FUNCTION__, desc->op_ctl.flags, send_msg.msg0, send_msg.msg1); - - retries = 100; - while (retries--) { - msgrng_flags_save(msgrng_flags); - - code = message_send_retry(SEC_MSGRING_WORDSIZE, - MSGRNG_CODE_SEC, - desc->op_ctl.stn_id, - &send_msg); - - - msgrng_flags_restore(msgrng_flags); - + msgrng_flags = msgrng_access_enable(); + code = message_send(SEC_MSGRING_WORDSIZE, MSGRNG_CODE_SEC, + desc->op_ctl.stn_id, &send_msg); + msgrng_restore(msgrng_flags); if (code == 0) break; } - - return (XLR_SEC_ERR_NONE); } - - symkey_desc_pt xlr_sec_allocate_desc(void *session_ptr) { @@ -2090,7 +1996,6 @@ xlr_sec_allocate_desc(void *session_ptr) new->user.kern_auth = new->user.user_auth = NULL; new->user.aligned_auth = new->user.user_auth = NULL; - /* find cacheline alignment */ aligned = new; addr = (uint64_t) vtophys(new); @@ -2101,6 +2006,7 @@ xlr_sec_allocate_desc(void *session_ptr) /* setup common control info */ aligned->op_ctl.phys_self = addr; aligned->op_ctl.stn_id = MSGRNG_STNID_SEC0; + aligned->op_ctl.vaddr = (uintptr_t)aligned; return (aligned); } @@ -2114,8 +2020,6 @@ xlr_sec_free_desc(symkey_desc_pt desc) return; } contigfree(desc, sizeof(symkey_desc_t), M_DEVBUF); - - return; } @@ -2816,7 +2720,7 @@ decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector) break; } DPRINT("PACKET DESCRIPTOR: \n"); - word = desc->pkt_desc.srcLengthIVOffUseIVNext; + word = 0; //desc->pkt_desc.srcLengthIVOffUseIVNext; DPRINT("\tSrcLengthIVOffsetIVNext: %llx\n", word); DPRINT("\t\tLoad HMAC = %lld \n", GET_FIELD(word, PKT_DSC_LOADHMACKEY)); @@ -2841,7 +2745,7 @@ decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector) DPRINT("\t\tGlobal Src Offset = %lld \n", GET_FIELD(word, PKT_DSC_SEGOFFSET)); - word = desc->pkt_desc.dstDataSettings; + word = 0; //desc->pkt_desc.dstDataSettings; DPRINT("\tdstDataSettings: %llx \n", word); DPRINT("\t\tArc4 Byte Count = %lld \n", GET_FIELD(word, PKT_DSC_ARC4BYTECOUNT)); @@ -2859,7 +2763,7 @@ decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector) PKT_DSC_CPHR_DST_DWOFFSET)); DPRINT("\t\tCipher Dest Offset= %lld \n", GET_FIELD(word, PKT_DSC_CPHR_DST_OFFSET)); - word = desc->pkt_desc.authDstNonceLow; + word = 0; //desc->pkt_desc.authDstNonceLow; DPRINT("\tauthDstNonceLow: %llx \n", word); DPRINT("\t\tNonce Low 24 = %lld \n", GET_FIELD(word, PKT_DSC_NONCE_LOW)); @@ -2867,7 +2771,7 @@ decode_symkey_desc(symkey_desc_pt desc, uint32_t cfg_vector) PKT_DSC_AUTH_DST_ADDR)); DPRINT("\t\tCipher Offset High= %lld \n", GET_FIELD(word, PKT_DSC_CIPH_OFF_HI)); - word = desc->pkt_desc.ckSumDstNonceHiCFBMaskLLWMask; + word = 0; //desc->pkt_desc.ckSumDstNonceHiCFBMaskLLWMask; DPRINT("\tckSumDstNonceHiCFBMaskLLWMask: %llx \n", word); DPRINT("\t\tHash Byte off = %lld \n", GET_FIELD(word, PKT_DSC_HASH_BYTE_OFF)); DPRINT("\t\tPacket Len bytes = %lld \n", GET_FIELD(word, PKT_DSC_PKTLEN_BYTES)); @@ -2897,7 +2801,7 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, symkey_desc_pt desc = NULL; struct xlr_sec_session *ses = NULL; struct xlr_sec_command *cmd = NULL; - + uint32_t flags; if (code != MSGRNG_CODE_SEC) { panic("xlr_sec_msgring_handler: bad code = %d," @@ -2916,7 +2820,6 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, sec_eng = GET_FIELD(msg->msg0, MSG_CTL_OP_TYPE); sec_pipe = GET_FIELD(msg->msg1, MSG_CTL_OP_TYPE); - error = msg->msg0 >> 40 & 0x1ff; if (error) printf("ctrl error = 0x%llx\n", error); @@ -2938,12 +2841,11 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, * they are used for the engine and pipe Id. */ addr = GET_FIELD(msg->msg1, MSG_RSLT_DATA_DSC_ADDR); - addr = addr & ~((1 << 5) - 1); if (!addr) { panic("[%s:STNID_SEC]: NULL symkey addr!\n", __FUNCTION__); - } + /* * The adddress points to the data descriptor. The operation * descriptor is defined with the 32-byte cacheline size in @@ -2951,7 +2853,10 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, * reference the symkey descriptor. (ref: xlr_sec_desc.h) */ addr = addr - sizeof(OperationDescriptor_t); - desc = (symkey_desc_pt) MIPS_PHYS_TO_KSEG0(addr); + flags = xlr_enable_kx(); + desc = (symkey_desc_pt)(uintptr_t)xlr_paddr_ld(addr + + offsetof(OperationDescriptor_t, vaddr)); + xlr_restore_kx(flags); if (!desc) { printf("\nerror : not getting desc back correctly \n"); @@ -3099,10 +3004,8 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, } #endif - /* Copy cipher-data to User-space */ if (op->cipher_type != XLR_SEC_CIPHER_TYPE_NONE) { - size = op->dest_buf_size; /* DEBUG -dpk */ @@ -3119,14 +3022,12 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, crypto_copyback(cmd->crp->crp_flags, cmd->crp->crp_buf, 0, cmd->op.dest_buf_size, (caddr_t)(long)desc->user.aligned_dest + op->cipher_offset); crypto_done(cmd->crp); - } - } + /* Copy digest to User-space */ if (op->digest_type != XLR_SEC_DIGEST_TYPE_NONE) { - int offset = 0; switch (op->digest_type) { @@ -3163,7 +3064,6 @@ xlr_sec_msgring_handler(int bucket, int size, int code, int stid, } if (op->cipher_type == XLR_SEC_CIPHER_TYPE_ARC4 && op->rc4_savestate) { - size = XLR_SEC_MAX_RC4_STATE_SIZE; XLR_SEC_CMD_DIAG("state: to_addr=%p from_addr=%p size=%d \n", diff --git a/sys/mips/rmi/dev/sec/rmilib.h b/sys/mips/rmi/dev/sec/rmilib.h index 1f65c885c10..00106f9b944 100644 --- a/sys/mips/rmi/dev/sec/rmilib.h +++ b/sys/mips/rmi/dev/sec/rmilib.h @@ -25,7 +25,8 @@ * 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$ * RMI_BSD */ @@ -33,12 +34,10 @@ #define _RMILIB_H_ #include -__FBSDID("$FreeBSD$"); - #include -#include +#include -/*#define XLR_SEC_CMD_DEBUG*/ +/* #define XLR_SEC_CMD_DEBUG */ #ifdef XLR_SEC_CMD_DEBUG #define DPRINT printf diff --git a/sys/mips/rmi/dev/sec/rmisec.c b/sys/mips/rmi/dev/sec/rmisec.c index acced4ac130..5e00307c8e6 100644 --- a/sys/mips/rmi/dev/sec/rmisec.c +++ b/sys/mips/rmi/dev/sec/rmisec.c @@ -43,29 +43,27 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include +#include +#include +#include +#include + +#include "cryptodev_if.h" #include #include -#include -#include -#include -#include - -#include -#include - #include -/*#define RMI_SEC_DEBUG */ - +/* #define RMI_SEC_DEBUG */ void xlr_sec_print_data(struct cryptop *crp); -static int xlr_sec_newsession(void *arg, uint32_t * sidp, struct cryptoini *cri); -static int xlr_sec_freesession(void *arg, uint64_t tid); -static int xlr_sec_process(void *arg, struct cryptop *crp, int hint); - +static int xlr_sec_newsession(device_t dev, uint32_t * sidp, struct cryptoini *cri); +static int xlr_sec_freesession(device_t dev, uint64_t tid); +static int xlr_sec_process(device_t dev, struct cryptop *crp, int hint); static int xlr_sec_probe(device_t); static int xlr_sec_attach(device_t); @@ -82,6 +80,11 @@ static device_method_t xlr_sec_methods[] = { DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), + /* crypto device methods */ + DEVMETHOD(cryptodev_newsession, xlr_sec_newsession), + DEVMETHOD(cryptodev_freesession,xlr_sec_freesession), + DEVMETHOD(cryptodev_process, xlr_sec_process), + {0, 0} }; @@ -95,81 +98,63 @@ static devclass_t xlr_sec_devclass; DRIVER_MODULE(rmisec, iodi, xlr_sec_driver, xlr_sec_devclass, 0, 0); MODULE_DEPEND(rmisec, crypto, 1, 1, 1); - - static int xlr_sec_probe(device_t dev) { + + device_set_desc(dev, "XLR Security Accelerator"); return (BUS_PROBE_DEFAULT); - } - /* * Attach an interface that successfully probed. */ static int xlr_sec_attach(device_t dev) { - struct xlr_sec_softc *sc = device_get_softc(dev); - bzero(sc, sizeof(*sc)); sc->sc_dev = dev; - - - mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "rmi crypto driver", MTX_DEF); - - sc->sc_cid = crypto_get_driverid(0); + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "rmi crypto driver", + MTX_DEF); + sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE); if (sc->sc_cid < 0) { printf("xlr_sec - error : could not get the driver id\n"); goto error_exit; } - if (crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_DES_CBC\n"); - if (crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_3DES_CBC\n"); - if (crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, - xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_AES_CBC\n"); - if (crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0) != 0) printf("register failed for CRYPTO_ARC4\n"); - - if (crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0) != 0) printf("register failed for CRYPTO_MD5\n"); - if (crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0) != 0) printf("register failed for CRYPTO_SHA1\n"); - if (crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0) != 0) printf("register failed for CRYPTO_MD5_HMAC\n"); - if (crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, - xlr_sec_newsession, xlr_sec_freesession, xlr_sec_process, sc) != 0) + if (crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0) != 0) printf("register failed for CRYPTO_SHA1_HMAC\n"); - xlr_sec_init(sc); + device_printf(dev, "Initialization complete!\n"); return (0); - error_exit: return (ENXIO); } - /* * Detach an interface that successfully probed. */ @@ -194,39 +179,28 @@ xlr_sec_detach(device_t dev) return (0); } - - - /* * Allocate a new 'session' and return an encoded session id. 'sidp' * contains our registration id, and should contain an encoded session * id on successful allocation. */ static int -xlr_sec_newsession(void *arg, u_int32_t * sidp, struct cryptoini *cri) +xlr_sec_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) { struct cryptoini *c; - struct xlr_sec_softc *sc = arg; + struct xlr_sec_softc *sc = device_get_softc(dev); int mac = 0, cry = 0, sesn; struct xlr_sec_session *ses = NULL; - if (sidp == NULL || cri == NULL || sc == NULL) return (EINVAL); - if (sc->sc_sessions == NULL) { ses = sc->sc_sessions = (struct xlr_sec_session *)malloc( sizeof(struct xlr_sec_session), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); - - ses->desc_ptr = (void *)xlr_sec_allocate_desc((void *)ses); - if (ses->desc_ptr == NULL) - return (ENOMEM); - sesn = 0; - ses->sessionid = sesn; sc->sc_nsessions = 1; } else { for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { @@ -242,23 +216,22 @@ xlr_sec_newsession(void *arg, u_int32_t * sidp, struct cryptoini *cri) sizeof(struct xlr_sec_session), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); - bcopy(sc->sc_sessions, ses, sesn * sizeof(struct xlr_sec_session)); - bzero(sc->sc_sessions, sesn * sizeof(struct xlr_sec_session)); + bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); + bzero(sc->sc_sessions, sesn * sizeof(*ses)); free(sc->sc_sessions, M_DEVBUF); sc->sc_sessions = ses; ses = &sc->sc_sessions[sesn]; - ses->sessionid = sesn; - ses->desc_ptr = (void *)xlr_sec_allocate_desc((void *)ses); - if (ses->desc_ptr == NULL) - return (ENOMEM); sc->sc_nsessions++; } } + bzero(ses, sizeof(*ses)); + ses->sessionid = sesn; + ses->desc_ptr = xlr_sec_allocate_desc(ses); + if (ses->desc_ptr == NULL) + return (ENOMEM); ses->hs_used = 1; - for (c = cri; c != NULL; c = c->cri_next) { - switch (c->cri_alg) { case CRYPTO_MD5: case CRYPTO_SHA1: @@ -313,9 +286,9 @@ xlr_sec_newsession(void *arg, u_int32_t * sidp, struct cryptoini *cri) * XXX to blow away any keys already stored there. */ static int -xlr_sec_freesession(void *arg, u_int64_t tid) +xlr_sec_freesession(device_t dev, u_int64_t tid) { - struct xlr_sec_softc *sc = arg; + struct xlr_sec_softc *sc = device_get_softc(dev); int session; u_int32_t sid = CRYPTO_SESID2LID(tid); @@ -327,7 +300,6 @@ xlr_sec_freesession(void *arg, u_int64_t tid) return (EINVAL); sc->sc_sessions[session].hs_used = 0; - return (0); } @@ -375,11 +347,10 @@ xlr_sec_print_data(struct cryptop *crp) #endif - static int -xlr_sec_process(void *arg, struct cryptop *crp, int hint) +xlr_sec_process(device_t dev, struct cryptop *crp, int hint) { - struct xlr_sec_softc *sc = arg; + struct xlr_sec_softc *sc = device_get_softc(dev); struct xlr_sec_command *cmd = NULL; int session, err; struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; @@ -466,7 +437,6 @@ xlr_sec_process(void *arg, struct cryptop *crp, int hint) cmd->op.num_packets = 1; cmd->op.num_fragments = 1; - if (cmd->op.source_buf_size > SEC_MAX_FRAG_LEN) { ses->multi_frag_flag = 1; } else { @@ -499,7 +469,6 @@ xlr_sec_process(void *arg, struct cryptop *crp, int hint) cmd->op.pkt_iv = XLR_SEC_PKT_IV_OLD; cmd->op.pkt_lastword = XLR_SEC_LASTWORD_128; - default: printf("currently not handled\n"); } @@ -524,8 +493,10 @@ xlr_sec_process(void *arg, struct cryptop *crp, int hint) memcpy(&cmd->op.crypt_key[0], enccrd->crd_key, XLR_SEC_DES_KEY_LENGTH); } else { cmd->op.cipher_type = XLR_SEC_CIPHER_TYPE_3DES; - //if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { - memcpy(&cmd->op.crypt_key[0], enccrd->crd_key, XLR_SEC_3DES_KEY_LENGTH); + //if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) + { + memcpy(&cmd->op.crypt_key[0], enccrd->crd_key, + XLR_SEC_3DES_KEY_LENGTH); } } @@ -550,16 +521,19 @@ xlr_sec_process(void *arg, struct cryptop *crp, int hint) cmd->op.pkt_lastword = XLR_SEC_LASTWORD_128; //if ((!(enccrd->crd_flags & CRD_F_IV_PRESENT)) && - if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT)) { - memcpy(&cmd->op.initial_vector[0], enccrd->crd_iv, XLR_SEC_DES_IV_LENGTH); - } + if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT)) { + memcpy(&cmd->op.initial_vector[0], enccrd->crd_iv, + XLR_SEC_DES_IV_LENGTH); + } break; case CRYPTO_AES_CBC: if (enccrd->crd_alg == CRYPTO_AES_CBC) { cmd->op.cipher_type = XLR_SEC_CIPHER_TYPE_AES128; - //if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) { - memcpy(&cmd->op.crypt_key[0], enccrd->crd_key, XLR_SEC_AES128_KEY_LENGTH); + //if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) + { + memcpy(&cmd->op.crypt_key[0], enccrd->crd_key, + XLR_SEC_AES128_KEY_LENGTH); } } cmd->op.cipher_mode = XLR_SEC_CIPHER_MODE_CBC; @@ -583,11 +557,11 @@ xlr_sec_process(void *arg, struct cryptop *crp, int hint) cmd->op.pkt_lastword = XLR_SEC_LASTWORD_128; //if (!(enccrd->crd_flags & CRD_F_IV_PRESENT)) { - if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT)) { - memcpy(&cmd->op.initial_vector[0], enccrd->crd_iv, XLR_SEC_AES_BLOCK_SIZE); - } - // + if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT)) { + memcpy(&cmd->op.initial_vector[0], enccrd->crd_iv, + XLR_SEC_AES_BLOCK_SIZE); } + //} break; } } diff --git a/sys/mips/rmi/dev/sec/stats.h b/sys/mips/rmi/dev/sec/stats.h deleted file mode 100644 index 276f7e9b999..00000000000 --- a/sys/mips/rmi/dev/sec/stats.h +++ /dev/null @@ -1,469 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - * - * RMI_BSD */ - -#ifndef _STATS_H_ -#define _STATS_H_ - -typedef struct hmac_stats -{ - unsigned long md5_count; - unsigned long long md5_bytes; - unsigned long sha1_count; - unsigned long long sha1_bytes; - unsigned long sha256_count; - unsigned long long sha256_bytes; - unsigned long sha384_count; - unsigned long long sha384_bytes; - unsigned long sha512_count; - unsigned long long sha512_bytes; - unsigned long gcm_count; - unsigned long long gcm_bytes; - unsigned long kasumi_f9_count; - unsigned long long kasumi_f9_bytes; - unsigned long reverts; - unsigned long long reverts_bytes; -} hmac_stats_t, *hmac_stats_pt; - -typedef struct cipher_stats -{ - unsigned long des_encrypts; - unsigned long long des_encrypt_bytes; - unsigned long des_decrypts; - unsigned long long des_decrypt_bytes; - unsigned long des3_encrypts; - unsigned long long des3_encrypt_bytes; - unsigned long des3_decrypts; - unsigned long long des3_decrypt_bytes; - unsigned long aes_encrypts; - unsigned long long aes_encrypt_bytes; - unsigned long aes_decrypts; - unsigned long long aes_decrypt_bytes; - unsigned long arc4_encrypts; - unsigned long long arc4_encrypt_bytes; - unsigned long arc4_decrypts; - unsigned long long arc4_decrypt_bytes; - unsigned long kasumi_f8_encrypts; - unsigned long long kasumi_f8_encrypt_bytes; - unsigned long kasumi_f8_decrypts; - unsigned long long kasumi_f8_decrypt_bytes; - unsigned long reverts; - unsigned long long reverts_bytes; -} cipher_stats_t, *cipher_stats_pt; - - -typedef struct modexp_stats -{ - unsigned long modexp_512s; - unsigned long modexp_1024s; -} modexp_stats_t, *modexp_stats_pt; - -typedef struct ecc_stats -{ - unsigned long ecc_mul; - unsigned long ecc_add; - unsigned long ecc_dbl; - unsigned long ecc_vfy; - unsigned long ecc_bin_mul; - unsigned long ecc_field_bin_inv; - unsigned long ecc_field_bin_mul; - unsigned long ecc_field_bin_add; - unsigned long ecc_field_add; - unsigned long ecc_field_sub; - unsigned long ecc_field_mul; - unsigned long ecc_field_inv; - unsigned long ecc_field_div; - unsigned long ecc_field_red; -} ecc_stats_t, *ecc_stats_pt; - - -typedef struct opt_stats -{ - unsigned long combined; - unsigned long unaligned_auth_dest; - unsigned long sym_failed; - unsigned long modexp_failed; - unsigned long ecc_failed; -} opt_stats_t, *opt_stats_pt; - -typedef struct rmisec_stats -{ - uint32_t sent; - uint32_t received; - uint32_t stats_mask; - uint32_t control_mask; - rwlock_t rmisec_control_lock; - rwlock_t rmisec_stats_lock; - char clear_start[0]; - uint64_t wait_time; - uint32_t max_wait_time; - uint32_t maxsnd_wait_time; - uint32_t wait_count; - hmac_stats_t hmac; - cipher_stats_t cipher; - modexp_stats_t modexp; - ecc_stats_t ecc; - opt_stats_t opt; -} rmisec_stats_t, *rmisec_stats_pt; - - -/* stats routines */ - -static void inline phxdrv_record_sent(rmisec_stats_pt stats) -{ - write_lock(&stats->rmisec_stats_lock); - stats->sent++; - write_unlock(&stats->rmisec_stats_lock); -} - -static void inline phxdrv_record_received(rmisec_stats_pt stats) -{ - write_lock(&stats->rmisec_stats_lock); - stats->received++; - write_unlock(&stats->rmisec_stats_lock); -} - - -static void inline phxdrv_record_des(rmisec_stats_pt stats, int enc, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_DES) { - write_lock(&stats->rmisec_stats_lock); - if (enc) { - stats->cipher.des_encrypts++; - stats->cipher.des_encrypt_bytes += nbytes; - } - else { - stats->cipher.des_decrypts++; - stats->cipher.des_decrypt_bytes += nbytes; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_3des(rmisec_stats_pt stats, int enc, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_3DES) { - write_lock(&stats->rmisec_stats_lock); - if (enc) { - stats->cipher.des3_encrypts++; - stats->cipher.des3_encrypt_bytes += nbytes; - } - else { - stats->cipher.des3_decrypts++; - stats->cipher.des3_decrypt_bytes += nbytes; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_aes(rmisec_stats_pt stats, int enc, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_AES) { - write_lock(&stats->rmisec_stats_lock); - if (enc) { - stats->cipher.aes_encrypts++; - stats->cipher.aes_encrypt_bytes += nbytes; - } - else { - stats->cipher.aes_decrypts++; - stats->cipher.aes_decrypt_bytes += nbytes; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_arc4(rmisec_stats_pt stats, int enc, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_ARC4) { - write_lock(&stats->rmisec_stats_lock); - if (enc) { - stats->cipher.arc4_encrypts++; - stats->cipher.arc4_encrypt_bytes += nbytes; - } - else { - stats->cipher.arc4_decrypts++; - stats->cipher.arc4_decrypt_bytes += nbytes; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_kasumi_f8(rmisec_stats_pt stats, int enc, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_KASUMI_F8) { - write_lock(&stats->rmisec_stats_lock); - if (enc) { - stats->cipher.kasumi_f8_encrypts++; - stats->cipher.kasumi_f8_encrypt_bytes += nbytes; - } - else { - stats->cipher.kasumi_f8_decrypts++; - stats->cipher.kasumi_f8_decrypt_bytes += nbytes; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_modexp(rmisec_stats_pt stats, - int blksize) -{ - if (stats->stats_mask & PHXDRV_PROFILE_MODEXP) { - write_lock(&stats->rmisec_stats_lock); - if (blksize == 512) { - stats->modexp.modexp_512s++; - } - if (blksize == 1024) { - stats->modexp.modexp_1024s++; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_ecc(rmisec_stats_pt stats, PHX_ECC_OP op) -{ - if (stats->stats_mask & PHXDRV_PROFILE_ECC) { - write_lock(&stats->rmisec_stats_lock); - switch (op) { - case PHX_ECC_NOP: - break; - case PHX_ECC_MUL: - stats->ecc.ecc_mul++; - break; - case PHX_ECC_BIN_MUL: - stats->ecc.ecc_bin_mul++; - break; - case PHX_ECC_ADD: - stats->ecc.ecc_add++; - break; - case PHX_ECC_DBL: - stats->ecc.ecc_dbl++; - break; - case PHX_ECC_VFY: - stats->ecc.ecc_vfy++; - break; - case PHX_ECC_FIELD_BIN_INV: - stats->ecc.ecc_field_bin_inv++; - break; - case PHX_ECC_FIELD_BIN_MUL: - stats->ecc.ecc_field_bin_mul++; - break; - case PHX_ECC_FIELD_BIN_ADD: - stats->ecc.ecc_field_bin_add++; - break; - case PHX_ECC_FIELD_ADD: - stats->ecc.ecc_field_add++; - break; - case PHX_ECC_FIELD_SUB: - stats->ecc.ecc_field_sub++; - break; - case PHX_ECC_FIELD_MUL: - stats->ecc.ecc_field_mul++; - break; - case PHX_ECC_FIELD_INV: - stats->ecc.ecc_field_inv++; - break; - case PHX_ECC_FIELD_DIV: - stats->ecc.ecc_field_div++; - break; - case PHX_ECC_FIELD_RED: - stats->ecc.ecc_field_red++; - break; - case PHX_ECC_FIELD: - case PHX_ECC_BIN: - break; - } - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_cipher_revert(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_CPHR_REVERTS) { - write_lock(&stats->rmisec_stats_lock); - stats->cipher.reverts++; - stats->cipher.reverts_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_hmac_revert(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_HMAC_REVERTS) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.reverts++; - stats->hmac.reverts_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_md5(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_MD5) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.md5_count++; - stats->hmac.md5_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_sha1(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_SHA1) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.sha1_count++; - stats->hmac.sha1_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_sha256(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_SHA256) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.sha256_count++; - stats->hmac.sha256_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_sha384(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_SHA384) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.sha384_count++; - stats->hmac.sha384_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_sha512(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_SHA512) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.sha512_count++; - stats->hmac.sha512_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_gcm(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_GCM) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.gcm_count++; - stats->hmac.gcm_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_kasumi_f9(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_KASUMI_F9) { - write_lock(&stats->rmisec_stats_lock); - stats->hmac.kasumi_f9_count++; - stats->hmac.kasumi_f9_bytes += nbytes; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_unaligned_auth_dest(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_UNALIGNED_AUTH_DEST) { - write_lock(&stats->rmisec_stats_lock); - stats->opt.unaligned_auth_dest++; - write_unlock(&stats->rmisec_stats_lock); - } -} - - -static void inline phxdrv_record_combined(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_COMBINED) { - write_lock(&stats->rmisec_stats_lock); - stats->opt.combined++; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_sym_failed(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_COMBINED) { - write_lock(&stats->rmisec_stats_lock); - stats->opt.sym_failed++; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_modexp_failed(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_COMBINED) { - write_lock(&stats->rmisec_stats_lock); - stats->opt.modexp_failed++; - write_unlock(&stats->rmisec_stats_lock); - } -} - -static void inline phxdrv_record_ecc_failed(rmisec_stats_pt stats, - int nbytes) -{ - if (stats->stats_mask & PHXDRV_PROFILE_COMBINED) { - write_lock(&stats->rmisec_stats_lock); - stats->opt.ecc_failed++; - write_unlock(&stats->rmisec_stats_lock); - } -} - -#endif diff --git a/sys/mips/rmi/debug.h b/sys/mips/rmi/dev/xlr/debug.h similarity index 99% rename from sys/mips/rmi/debug.h rename to sys/mips/rmi/dev/xlr/debug.h index b5ec144cc2c..53f1cb21dc0 100644 --- a/sys/mips/rmi/debug.h +++ b/sys/mips/rmi/dev/xlr/debug.h @@ -26,7 +26,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef _RMI_DEBUG_H_ #define _RMI_DEBUG_H_ diff --git a/sys/mips/rmi/dev/xlr/rge.c b/sys/mips/rmi/dev/xlr/rge.c index 979543bd9b7..a529377571c 100644 --- a/sys/mips/rmi/dev/xlr/rge.c +++ b/sys/mips/rmi/dev/xlr/rge.c @@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -63,7 +64,6 @@ __FBSDID("$FreeBSD$"); #include #include - #include #include @@ -87,26 +87,23 @@ __FBSDID("$FreeBSD$"); #include #include /* */ #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include -/* #include "opt_rge.h" */ +#include +#include +#include +#include #include "miibus_if.h" @@ -187,35 +184,8 @@ int xlr_rge_tx_ok_done[MAXCPU]; int xlr_rge_rx_done[MAXCPU]; int xlr_rge_repl_done[MAXCPU]; -static __inline__ unsigned int -ldadd_wu(unsigned int value, unsigned long *addr) -{ - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "move $8, %2\n" - "move $9, %3\n" - /* "ldaddwu $8, $9\n" */ - ".word 0x71280011\n" - "move %0, $8\n" - ".set pop\n" - : "=&r"(value), "+m"(*addr) - : "0"(value), "r"((unsigned long)addr) - : "$8", "$9"); - - return value; -} - -static __inline__ uint32_t -xlr_enable_kx(void) -{ - uint32_t sr = mips_rd_status(); - - mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); - return sr; -} - /* #define mac_stats_add(x, val) ({(x) += (val);}) */ -#define mac_stats_add(x, val) ldadd_wu(val, &x) +#define mac_stats_add(x, val) xlr_ldaddwu(val, &x) #define XLR_MAX_CORE 8 #define RGE_LOCK_INIT(_sc, _name) \ @@ -614,25 +584,16 @@ static void free_buf(vm_paddr_t paddr) { struct mbuf *m; - uint32_t mag; -#ifdef __mips_n64 - uint64_t *vaddr; - - vaddr = (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(paddr); - m = (struct mbuf *)vaddr[0]; - mag = (uint32_t)vaddr[1]; -#else + uint64_t mag; uint32_t sr; sr = xlr_enable_kx(); - m = (struct mbuf *)(intptr_t)xlr_paddr_lw(paddr - XLR_CACHELINE_SIZE + sizeof(uint32_t)); - mag = xlr_paddr_lw(paddr - XLR_CACHELINE_SIZE + 3 * sizeof(uint32_t)); - mips_wr_status(sr); -#endif - + m = (struct mbuf *)(intptr_t)xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE); + mag = xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE + sizeof(uint64_t)); + xlr_restore_kx(sr); if (mag != 0xf00bad) { - printf("Something is wrong kseg:%lx found mag:%x not 0xf00bad\n", - (u_long)paddr, mag); + printf("Something is wrong kseg:%lx found mag:%lx not 0xf00bad\n", + (u_long)paddr, (u_long)mag); return; } if (m != NULL) @@ -714,21 +675,30 @@ static __inline__ int xlr_mac_send_fr(struct driver_data *priv, vm_paddr_t addr, int len) { - int stid = priv->rfrbucket; struct msgrng_msg msg; - int vcpu = xlr_cpu_id(); + int stid = priv->rfrbucket; + int code, ret; + uint32_t msgrng_flags; +#ifdef INVARIANTS + int i = 0; +#endif mac_make_desc_rfr(&msg, addr); /* Send the packet to MAC */ dbg_msg("mac_%d: Sending free packet %lx to stid %d\n", priv->instance, (u_long)addr, stid); - if (priv->type == XLR_XGMAC) { - while (message_send(1, MSGRNG_CODE_XGMAC, stid, &msg)); - } else { - while (message_send(1, MSGRNG_CODE_MAC, stid, &msg)); - xlr_rge_repl_done[vcpu]++; - } + if (priv->type == XLR_XGMAC) + code = MSGRNG_CODE_XGMAC; /* WHY? */ + else + code = MSGRNG_CODE_MAC; + + do { + msgrng_flags = msgrng_access_enable(); + ret = message_send(1, code, stid, &msg); + msgrng_restore(msgrng_flags); + KASSERT(i++ < 100000, ("Too many credit fails\n")); + } while (ret != 0); return 0; } @@ -1001,7 +971,7 @@ rmi_xlr_config_pde(struct driver_data *priv) if (cpumask & (1 << i)) { cpu = i; bucket = ((cpu >> 2) << 3); - bucket_map |= (1ULL << bucket); + bucket_map |= (3ULL << bucket); } } printf("rmi_xlr_config_pde: bucket_map=%jx\n", (uintmax_t)bucket_map); @@ -1442,37 +1412,16 @@ rmi_xlr_mac_set_duplex(struct driver_data *s, #define MAC_TX_PASS 0 #define MAC_TX_RETRY 1 -static __inline__ void -message_send_block(unsigned int size, unsigned int code, - unsigned int stid, struct msgrng_msg *msg) -{ - unsigned int dest = 0; - unsigned long long status = 0; - - msgrng_load_tx_msg0(msg->msg0); - msgrng_load_tx_msg1(msg->msg1); - msgrng_load_tx_msg2(msg->msg2); - msgrng_load_tx_msg3(msg->msg3); - - dest = ((size - 1) << 16) | (code << 8) | (stid); - - do { - msgrng_send(dest); - status = msgrng_read_status(); - } while (status & 0x6); - -} - int xlr_dev_queue_xmit_hack = 0; static int mac_xmit(struct mbuf *m, struct rge_softc *sc, struct driver_data *priv, int len, struct p2d_tx_desc *tx_desc) { - struct msgrng_msg msg; + struct msgrng_msg msg = {0,0,0,0}; int stid = priv->txbucket; uint32_t tx_cycles = 0; - unsigned long mflags = 0; + uint32_t mflags; int vcpu = xlr_cpu_id(); int rv; @@ -1482,17 +1431,17 @@ mac_xmit(struct mbuf *m, struct rge_softc *sc, return MAC_TX_FAIL; else { - msgrng_access_enable(mflags); - if ((rv = message_send_retry(1, MSGRNG_CODE_MAC, stid, &msg)) != 0) { + mflags = msgrng_access_enable(); + if ((rv = message_send(1, MSGRNG_CODE_MAC, stid, &msg)) != 0) { msg_snd_failed++; - msgrng_access_disable(mflags); + msgrng_restore(mflags); release_tx_desc(&msg, 0); xlr_rge_msg_snd_failed[vcpu]++; dbg_msg("Failed packet to cpu %d, rv = %d, stid %d, msg0=%jx\n", vcpu, rv, stid, (uintmax_t)msg.msg0); return MAC_TX_FAIL; } - msgrng_access_disable(mflags); + msgrng_restore(mflags); port_inc_counter(priv->instance, PORT_TX); } @@ -1562,7 +1511,6 @@ mac_frin_replenish(void *args /* ignored */ ) for (i = 0; i < XLR_MAX_MACS; i++) { /* int offset = 0; */ - unsigned long msgrng_flags; void *m; uint32_t cycles; struct rge_softc *sc; @@ -1595,14 +1543,11 @@ mac_frin_replenish(void *args /* ignored */ ) } } xlr_inc_counter(REPLENISH_FRIN); - msgrng_access_enable(msgrng_flags); if (xlr_mac_send_fr(priv, vtophys(m), MAX_FRAME_SIZE)) { free_buf(vtophys(m)); printf("[%s]: rx free message_send failed!\n", __FUNCTION__); - msgrng_access_disable(msgrng_flags); break; } - msgrng_access_disable(msgrng_flags); xlr_set_counter(REPLENISH_CYCLES, (read_c0_count() - cycles)); atomic_subtract_int((&priv->frin_to_be_sent[cpu]), 1); @@ -2041,15 +1986,8 @@ static void rge_rx(struct rge_softc *sc, vm_paddr_t paddr, int len) { struct mbuf *m; - uint32_t mag; struct ifnet *ifp = sc->rge_ifp; -#ifdef __mips_n64 - uint64_t *vaddr; - - vaddr =(uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(paddr - XLR_CACHELINE_SIZE); - m = (struct mbuf *)vaddr[0]; - mag = (uint32_t)vaddr[1]; -#else + uint64_t mag; uint32_t sr; /* * On 32 bit machines we use XKPHYS to get the values stores with @@ -2057,10 +1995,9 @@ rge_rx(struct rge_softc *sc, vm_paddr_t paddr, int len) * KX is enabled to prevent this setting leaking to other code. */ sr = xlr_enable_kx(); - m = (struct mbuf *)(intptr_t)xlr_paddr_lw(paddr - XLR_CACHELINE_SIZE + sizeof(uint32_t)); - mag = xlr_paddr_lw(paddr - XLR_CACHELINE_SIZE + 3 * sizeof(uint32_t)); - mips_wr_status(sr); -#endif + m = (struct mbuf *)(intptr_t)xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE); + mag = xlr_paddr_ld(paddr - XLR_CACHELINE_SIZE + sizeof(uint64_t)); + xlr_restore_kx(sr); if (mag != 0xf00bad) { /* somebody else packet Error - FIXME in intialization */ printf("cpu %d: *ERROR* Not my packet paddr %p\n", @@ -2430,7 +2367,6 @@ static int rmi_xlr_mac_fill_rxfr(struct rge_softc *sc) { struct driver_data *priv = &(sc->priv); - unsigned long msgrng_flags; int i; int ret = 0; void *ptr; @@ -2448,9 +2384,7 @@ rmi_xlr_mac_fill_rxfr(struct rge_softc *sc) break; } /* Send the free Rx desc to the MAC */ - msgrng_access_enable(msgrng_flags); xlr_mac_send_fr(priv, vtophys(ptr), MAX_FRAME_SIZE); - msgrng_access_disable(msgrng_flags); } return ret; @@ -2605,17 +2539,20 @@ mac_common_init(void) init_tx_ring(); if (xlr_board_info.is_xls) { - if (register_msgring_handler(TX_STN_GMAC0, - rmi_xlr_mac_msgring_handler, NULL)) { + if (register_msgring_handler(MSGRNG_STNID_GMAC, + MSGRNG_STNID_GMAC + 1, rmi_xlr_mac_msgring_handler, + NULL)) { panic("Couldn't register msgring handler\n"); } - if (register_msgring_handler(TX_STN_GMAC1, - rmi_xlr_mac_msgring_handler, NULL)) { + if (register_msgring_handler(MSGRNG_STNID_GMAC1, + MSGRNG_STNID_GMAC1 + 1, rmi_xlr_mac_msgring_handler, + NULL)) { panic("Couldn't register msgring handler\n"); } } else { - if (register_msgring_handler(TX_STN_GMAC, - rmi_xlr_mac_msgring_handler, NULL)) { + if (register_msgring_handler(MSGRNG_STNID_GMAC, + MSGRNG_STNID_GMAC + 1, rmi_xlr_mac_msgring_handler, + NULL)) { panic("Couldn't register msgring handler\n"); } } diff --git a/sys/mips/rmi/dev/xlr/rge.h b/sys/mips/rmi/dev/xlr/rge.h index 98b5847c6d8..fa98a0d6076 100644 --- a/sys/mips/rmi/dev/xlr/rge.h +++ b/sys/mips/rmi/dev/xlr/rge.h @@ -26,6 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $FreeBSD$ * RMI_BSD */ #ifndef _RMI_RGE_H_ #define _RMI_RGE_H_ @@ -972,12 +973,12 @@ enum { }; struct rge_softc_stats { - unsigned long rx_frames; - unsigned long tx_frames; - unsigned long rx_packets; - unsigned long rx_bytes; - unsigned long tx_packets; - unsigned long tx_bytes; + unsigned int rx_frames; + unsigned int tx_frames; + unsigned int rx_packets; + unsigned int rx_bytes; + unsigned int tx_packets; + unsigned int tx_bytes; }; struct driver_data { diff --git a/sys/mips/rmi/files.xlr b/sys/mips/rmi/files.xlr index 2444cbd2cb0..e96fc43789f 100644 --- a/sys/mips/rmi/files.xlr +++ b/sys/mips/rmi/files.xlr @@ -7,21 +7,21 @@ mips/rmi/iodi.c standard mips/rmi/msgring.c standard mips/rmi/msgring_xls.c standard mips/rmi/board.c standard -mips/rmi/on_chip.c standard +mips/rmi/fmn.c standard mips/rmi/intr_machdep.c standard mips/rmi/mpwait.S optional smp mips/rmi/xlr_i2c.c optional iic mips/rmi/uart_bus_xlr_iodi.c optional uart mips/rmi/uart_cpu_mips_xlr.c optional uart -mips/rmi/perfmon_kern.c optional xlr_perfmon -mips/rmi/perfmon_percpu.c optional xlr_perfmon mips/rmi/xlr_pci.c optional pci +mips/rmi/xlr_pcmcia.c optional ata mips/rmi/xls_ehci.c optional usb ehci mips/rmi/bus_space_rmi.c standard mips/rmi/bus_space_rmi_pci.c standard mips/rmi/dev/sec/rmisec.c optional rmisec mips/rmi/dev/sec/rmilib.c optional rmisec mips/rmi/dev/xlr/rge.c optional rge +mips/rmi/dev/nlge/if_nlge.c optional nlge dev/iicbus/xlr_rtc.c optional xlr_rtc dev/iicbus/xlr_temperature.c optional xlr_temperature dev/iicbus/xlr_eeprom.c optional xlr_eeprom diff --git a/sys/mips/rmi/fmn.c b/sys/mips/rmi/fmn.c new file mode 100644 index 00000000000..011d7a1ff95 --- /dev/null +++ b/sys/mips/rmi/fmn.c @@ -0,0 +1,497 @@ +/*- + * Copyright (c) 2003-2009 RMI Corporation + * 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 RMI Corporation, 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 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. + * + * RMI_BSD */ +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \ +do { \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \ + msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \ +} while(0) + + +/* + * Keep track of our message ring handler threads, each core has a + * different message station. Ideally we will need to start a few + * message handling threads every core, and wake them up depending on + * load + */ +struct msgring_thread { + struct { + struct thread *thread; /* msgring handler threads */ + int needed; /* thread needs to wake up */ + } threads[XLR_NTHREADS]; + int running; /* number of threads running */ + int nthreads; /* number of threads started */ + struct mtx lock; /* for changing running/active */ +}; +static struct msgring_thread msgring_threads[XLR_MAX_CORES]; +static struct proc *msgring_proc; /* all threads are under a proc */ + +/* + * The maximum number of software message handler threads to be started + * per core. Default is 3 per core + */ +static int msgring_maxthreads = 3; +TUNABLE_INT("hw.fmn.maxthreads", &msgring_maxthreads); + +/* + * The device drivers can register a handler for the the messages sent + * from a station (corresponding to the device). + */ +struct tx_stn_handler { + msgring_handler action; + void *arg; +}; +static struct tx_stn_handler msgmap[MSGRNG_NSTATIONS]; +static struct mtx msgmap_lock; + +/* + * Initialize the messaging subsystem. + * + * Message Stations are shared among all threads in a cpu core, this + * has to be called once from every core which is online. + */ +void +xlr_msgring_cpu_init(void) +{ + struct stn_cc *cc_config; + struct bucket_size *bucket_sizes; + uint32_t flags; + int id; + + KASSERT(xlr_thr_id() == 0, + ("xlr_msgring_cpu_init from non-zero thread")); + id = xlr_core_id(); + bucket_sizes = xlr_board_info.bucket_sizes; + cc_config = xlr_board_info.credit_configs[id]; + + flags = msgrng_access_enable(); + + /* + * FMN messages are received in 8 buckets per core, set up + * the bucket sizes for each bucket + */ + msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]); + msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]); + msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]); + msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]); + msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]); + msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]); + msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]); + msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]); + + /* + * For sending FMN messages, we need credits on the destination + * bucket. Program the credits this core has on the 128 possible + * destination buckets. + * We cannot use a loop here, because the the first argument has + * to be a constant integer value. + */ + MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters); + MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters); + msgrng_restore(flags); +} + +/* + * Boot time init, called only once + */ +void +xlr_msgring_config(void) +{ + mtx_init(&msgmap_lock, "msgring", NULL, MTX_SPIN); + + /* check value */ + if (msgring_maxthreads < 0 || msgring_maxthreads > XLR_NTHREADS) + msgring_maxthreads = XLR_NTHREADS; +} + +/* + * Drain out max_messages for the buckets set in the bucket mask. + * Use max_messages = 0 to drain out all messages. + */ +uint32_t +xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages) +{ + int bucket = 0; + int size = 0, code = 0, rx_stid = 0; + struct msgrng_msg msg; + struct tx_stn_handler *he; + unsigned int status = 0; + unsigned long mflags; + uint32_t n_msgs; + uint32_t msgbuckets; + + n_msgs = 0; + mflags = msgrng_access_enable(); + for (;;) { + msgbuckets = (~msgrng_read_status() >> 24) & bucket_mask; + + /* all buckets empty, break */ + if (msgbuckets == 0) + break; + + for (bucket = 0; bucket < 8; bucket++) { + if ((msgbuckets & (1 << bucket)) == 0) /* empty */ + continue; + + status = message_receive(bucket, &size, &code, + &rx_stid, &msg); + if (status != 0) + continue; + n_msgs++; + he = &msgmap[rx_stid]; + if (he->action == NULL) { + printf("[%s]: No Handler for message from " + "stn_id=%d, bucket=%d, size=%d, msg0=%jx\n", + __func__, rx_stid, bucket, size, + (uintmax_t)msg.msg0); + } else { + msgrng_restore(mflags); + (*he->action)(bucket, size, code, rx_stid, + &msg, he->arg); + mflags = msgrng_access_enable(); + } + if (max_messages > 0 && n_msgs >= max_messages) + goto done; + } + } + +done: + msgrng_restore(mflags); + return (n_msgs); +} + +/* + * XLR COP2 supports watermark interrupts based on the number of + * messages pending in all the buckets in the core. We increase + * the watermark until all the possible handler threads in the core + * are woken up. + */ +static void +msgrng_setconfig(int running, int nthr) +{ + uint32_t config, mflags; + int watermark = 1; /* non zero needed */ + int wm_intr_value; + + KASSERT(nthr >= 0 && nthr <= msgring_maxthreads, + ("Bad value of nthr %d", nthr)); + KASSERT(running <= nthr, ("Bad value of running %d", running)); + + if (running == nthr) { + wm_intr_value = 0; + } else { + switch (running) { + case 0: break; /* keep default */ + case 1: + watermark = 32; break; + case 2: + watermark = 48; break; + case 3: + watermark = 56; break; + } + wm_intr_value = 0x2; /* set watermark enable interrupt */ + } + mflags = msgrng_access_enable(); + config = (watermark << 24) | (IRQ_MSGRING << 16) | (1 << 8) | + wm_intr_value; + /* clear pending interrupts, they will get re-raised if still valid */ + write_c0_eirr64(1ULL << IRQ_MSGRING); + msgrng_write_config(config); + msgrng_restore(mflags); +} + +/* Debug counters */ +static int msgring_nintr[XLR_MAX_CORES]; +static int msgring_badintr[XLR_MAX_CORES]; +static int msgring_wakeup_sleep[XLR_MAX_CORES * XLR_NTHREADS]; +static int msgring_wakeup_nosleep[XLR_MAX_CORES * XLR_NTHREADS]; +static int msgring_nmsgs[XLR_MAX_CORES * XLR_NTHREADS]; + +static int +msgring_process_fast_intr(void *arg) +{ + struct msgring_thread *mthd; + struct thread *td; + uint32_t mflags; + int core, nt; + + core = xlr_core_id(); + mthd = &msgring_threads[core]; + msgring_nintr[core]++; + mtx_lock_spin(&mthd->lock); + nt = mthd->running; + if(nt >= mthd->nthreads) { + msgring_badintr[core]++; + mtx_unlock_spin(&mthd->lock); + return (FILTER_HANDLED); + } + + td = mthd->threads[nt].thread; + mflags = msgrng_access_enable(); + + /* default value with interrupts disabled */ + msgrng_write_config((1 << 24) | (IRQ_MSGRING << 16) | (1 << 8)); + /* clear pending interrupts */ + write_c0_eirr64(1ULL << IRQ_MSGRING); + msgrng_restore(mflags); + mtx_unlock_spin(&mthd->lock); + + /* wake up the target thread */ + mthd->threads[nt].needed = 1; + thread_lock(td); + if (TD_AWAITING_INTR(td)) { + msgring_wakeup_sleep[core*4+nt]++; + TD_CLR_IWAIT(td); + sched_add(td, SRQ_INTR); + } else + msgring_wakeup_nosleep[core*4+nt]++; + thread_unlock(td); + return (FILTER_HANDLED); +} + +static void +msgring_process(void *arg) +{ + struct msgring_thread *mthd; + struct thread *td; + int hwtid, tid, core; + int nmsgs; + + hwtid = (intptr_t)arg; + core = hwtid / 4; + tid = hwtid % 4; + mthd = &msgring_threads[core]; + td = mthd->threads[tid].thread; + KASSERT(curthread == td, + ("Incorrect thread core %d, thread %d", core, hwtid)); + + /* First bind this thread to the right CPU */ + thread_lock(td); + sched_bind(td, xlr_hwtid_to_cpuid[hwtid]); + thread_unlock(td); + + mtx_lock_spin(&mthd->lock); + ++mthd->nthreads; /* Active thread count */ + mtx_unlock_spin(&mthd->lock); + + /* start processing messages */ + for(;;) { + mtx_lock_spin(&mthd->lock); + ++mthd->running; + msgrng_setconfig(mthd->running, mthd->nthreads); + mtx_unlock_spin(&mthd->lock); + + atomic_store_rel_int(&mthd->threads[tid].needed, 0); + nmsgs = xlr_msgring_handler(0xff, 0); + msgring_nmsgs[hwtid] += nmsgs; + + mtx_lock_spin(&mthd->lock); + --mthd->running; + msgrng_setconfig(mthd->running, mthd->nthreads); + mtx_unlock_spin(&mthd->lock); + + /* sleep */ + thread_lock(td); + if (mthd->threads[tid].needed) { + thread_unlock(td); + continue; + } + sched_class(td, PRI_ITHD); + TD_SET_IWAIT(td); + mi_switch(SW_VOL, NULL); + thread_unlock(td); + } +} + +static void +create_msgring_thread(int hwtid) +{ + struct msgring_thread *mthd; + struct thread *td; + int tid, core; + int error; + + core = hwtid / 4; + tid = hwtid % 4; + mthd = &msgring_threads[core]; + if (tid == 0) { + mtx_init(&mthd->lock, "msgrngcore", NULL, MTX_SPIN); + mthd->running = mthd->nthreads = 0; + } + error = kproc_kthread_add(msgring_process, (void *)(uintptr_t)hwtid, + &msgring_proc, &td, RFSTOPPED, 2, "msgrngproc", + "msgthr%d", hwtid); + if (error) + panic("kproc_kthread_add() failed with %d", error); + mthd->threads[tid].thread = td; + + thread_lock(td); + sched_class(td, PRI_ITHD); + sched_add(td, SRQ_INTR); + thread_unlock(td); + CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name); +} + +int +register_msgring_handler(int startb, int endb, msgring_handler action, + void *arg) +{ + void *cookie; + int i; + static int msgring_int_enabled = 0; + + KASSERT(startb >= 0 && startb <= endb && endb < MSGRNG_NSTATIONS, + ("Invalid value for for bucket range %d,%d", startb, endb)); + + mtx_lock_spin(&msgmap_lock); + for (i = startb; i <= endb; i++) { + KASSERT(msgmap[i].action == NULL, + ("Bucket %d already used [action %p]", i, msgmap[i].action)); + msgmap[i].action = action; + msgmap[i].arg = arg; + } + mtx_unlock_spin(&msgmap_lock); + + if (xlr_test_and_set(&msgring_int_enabled)) { + create_msgring_thread(0); + if (msgring_maxthreads > xlr_threads_per_core) + msgring_maxthreads = xlr_threads_per_core; + cpu_establish_hardintr("msgring", msgring_process_fast_intr, + NULL, NULL, IRQ_MSGRING, + INTR_TYPE_NET | INTR_FAST, &cookie); + } + return (0); +} + +/* + * Start message ring processing threads on other CPUs, after SMP start + */ +static void +start_msgring_threads(void *arg) +{ + int hwt, tid; + + for (hwt = 1; hwt < XLR_MAX_CORES * XLR_NTHREADS; hwt++) { + if ((xlr_hw_thread_mask & (1 << hwt)) == 0) + continue; + tid = hwt % XLR_NTHREADS; + if (tid >= msgring_maxthreads) + continue; + create_msgring_thread(hwt); + } +} + +SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, + start_msgring_threads, NULL); + +/* + * DEBUG support, XXX: static buffer, not locked + */ +static int +sys_print_debug(SYSCTL_HANDLER_ARGS) +{ + int error, nb, i, fs; + static char xprintb[4096], *buf; + + buf = xprintb; + fs = sizeof(xprintb); + nb = snprintf(buf, fs, + "\nID INTR ER WU-SLP WU-ERR MSGS\n"); + buf += nb; + fs -= nb; + for (i = 0; i < 32; i++) { + if ((xlr_hw_thread_mask & (1 << i)) == 0) + continue; + nb = snprintf(buf, fs, + "%2d: %8d %4d %8d %8d %8d\n", i, + msgring_nintr[i/4], msgring_badintr[i/4], + msgring_wakeup_sleep[i], msgring_wakeup_nosleep[i], + msgring_nmsgs[i]); + buf += nb; + fs -= nb; + } + error = SYSCTL_OUT(req, xprintb, buf - xprintb); + return (error); +} + +SYSCTL_PROC(_debug, OID_AUTO, msgring, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, + sys_print_debug, "A", "msgring debug info"); diff --git a/sys/mips/rmi/interrupt.h b/sys/mips/rmi/interrupt.h index edb475a3270..76bbe5afa2e 100644 --- a/sys/mips/rmi/interrupt.h +++ b/sys/mips/rmi/interrupt.h @@ -25,8 +25,10 @@ * 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. - *__FBSDID("$FreeBSD$") - * RMI_BSD */ + * + * RMI_BSD + * $FreeBSD$ + */ #ifndef _RMI_INTERRUPT_H_ #define _RMI_INTERRUPT_H_ @@ -40,10 +42,9 @@ * XLR needs custom pre and post handlers for PCI/PCI-e interrupts * XXX: maybe follow i386 intsrc model */ -void xlr_cpu_establish_hardintr(const char *, driver_filter_t *, - driver_intr_t *, void *, int, int, void **, void (*)(void *), - void (*)(void *), void (*)(void *), int (*)(void *, u_char)); -void xlr_mask_hard_irq(void *); -void xlr_unmask_hard_irq(void *); +void xlr_establish_intr(const char *name, driver_filter_t filt, + driver_intr_t handler, void *arg, int irq, int flags, + void **cookiep, void (*busack)(int)); +void xlr_enable_irq(int irq); #endif /* _RMI_INTERRUPT_H_ */ diff --git a/sys/mips/rmi/intr_machdep.c b/sys/mips/rmi/intr_machdep.c index ef86aac7284..c606548c19e 100644 --- a/sys/mips/rmi/intr_machdep.c +++ b/sys/mips/rmi/intr_machdep.c @@ -44,39 +44,83 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include + +#include #include -#include #include -/*#include */ +struct xlr_intrsrc { + void (*busack)(int); /* Additional ack */ + struct intr_event *ie; /* event corresponding to intr */ + int irq; +}; + +static struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR]; static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; -static struct intr_event *mips_intr_events[XLR_MAX_INTR]; static int intrcnt_index; void -xlr_mask_hard_irq(void *source) +xlr_enable_irq(int irq) { - uintptr_t irq = (uintptr_t) source; + uint64_t eimr; - write_c0_eimr64(read_c0_eimr64() & ~(1ULL << irq)); + eimr = read_c0_eimr64(); + write_c0_eimr64(eimr | (1ULL << irq)); } void -xlr_unmask_hard_irq(void *source) +cpu_establish_softintr(const char *name, driver_filter_t * filt, + void (*handler) (void *), void *arg, int irq, int flags, + void **cookiep) { - uintptr_t irq = (uintptr_t) source; - write_c0_eimr64(read_c0_eimr64() | (1ULL << irq)); + panic("Soft interrupts unsupported!\n"); } void -xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt, - void (*handler) (void *), void *arg, int irq, int flags, void **cookiep, - void (*pre_ithread)(void *), void (*post_ithread)(void *), - void (*post_filter)(void *), int (*assign_cpu)(void *, u_char)) +cpu_establish_hardintr(const char *name, driver_filter_t * filt, + void (*handler) (void *), void *arg, int irq, int flags, + void **cookiep) +{ + + xlr_establish_intr(name, filt, handler, arg, irq, flags, + cookiep, NULL); +} + +static void +xlr_post_filter(void *source) +{ + struct xlr_intrsrc *src = source; + + if (src->busack) + src->busack(src->irq); + pic_ack(PIC_IRQ_TO_INTR(src->irq)); +} + +static void +xlr_pre_ithread(void *source) +{ + struct xlr_intrsrc *src = source; + + if (src->busack) + src->busack(src->irq); +} + +static void +xlr_post_ithread(void *source) +{ + struct xlr_intrsrc *src = source; + + pic_ack(PIC_IRQ_TO_INTR(src->irq)); +} + +void +xlr_establish_intr(const char *name, driver_filter_t filt, + driver_intr_t handler, void *arg, int irq, int flags, + void **cookiep, void (*busack)(int)) { struct intr_event *ie; /* descriptor for the IRQ */ + struct xlr_intrsrc *src = NULL; int errcode; if (irq < 0 || irq > XLR_MAX_INTR) @@ -86,43 +130,34 @@ xlr_cpu_establish_hardintr(const char *name, driver_filter_t * filt, * FIXME locking - not needed now, because we do this only on * startup from CPU0 */ - ie = mips_intr_events[irq]; - /* mih->cntp = &intrcnt[irq]; */ + src = &xlr_interrupts[irq]; + ie = src->ie; if (ie == NULL) { - errcode = intr_event_create(&ie, (void *)(uintptr_t) irq, 0, - irq, pre_ithread, post_ithread, post_filter, assign_cpu, - "hard intr%d:", irq); - + /* + * PIC based interrupts need ack in PIC, and some SoC + * components need additional acks (e.g. PCI) + */ + if (PIC_IRQ_IS_PICINTR(irq)) + errcode = intr_event_create(&ie, src, 0, irq, + xlr_pre_ithread, xlr_post_ithread, xlr_post_filter, + NULL, "hard intr%d:", irq); + else { + if (filt == NULL) + panic("Not supported - non filter percpu intr"); + errcode = intr_event_create(&ie, src, 0, irq, + NULL, NULL, NULL, NULL, "hard intr%d:", irq); + } if (errcode) { printf("Could not create event for intr %d\n", irq); return; } - mips_intr_events[irq] = ie; + src->irq = irq; + src->busack = busack; + src->ie = ie; } - intr_event_add_handler(ie, name, filt, handler, arg, intr_priority(flags), flags, cookiep); - xlr_unmask_hard_irq((void *)(uintptr_t) irq); -} - -void -cpu_establish_hardintr(const char *name, driver_filter_t * filt, - void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) -{ - xlr_cpu_establish_hardintr(name, filt, handler, arg, irq, - flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq, - NULL, NULL); -} - -void -cpu_establish_softintr(const char *name, driver_filter_t * filt, - void (*handler) (void *), void *arg, int irq, int flags, - void **cookiep) -{ - /* we don't separate them into soft/hard like other mips */ - xlr_cpu_establish_hardintr(name, filt, handler, arg, irq, - flags, cookiep, xlr_mask_hard_irq, xlr_unmask_hard_irq, - NULL, NULL); + xlr_enable_irq(irq); } void @@ -148,7 +183,7 @@ cpu_intr(struct trapframe *tf) * compare which ACKs the interrupt. */ if (eirr & (1 << IRQ_TIMER)) { - intr_event_handle(mips_intr_events[IRQ_TIMER], tf); + intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf); critical_exit(); return; } @@ -158,7 +193,7 @@ cpu_intr(struct trapframe *tf) if ((eirr & (1ULL << i)) == 0) continue; - ie = mips_intr_events[i]; + ie = xlr_interrupts[i].ie; /* Don't account special IRQs */ switch (i) { case IRQ_IPI: @@ -167,16 +202,12 @@ cpu_intr(struct trapframe *tf) default: mips_intrcnt_inc(mips_intr_counters[i]); } + + /* Ack the IRQ on the CPU */ write_c0_eirr64(1ULL << i); - pic_ack(i, 0); - if (!ie || TAILQ_EMPTY(&ie->ie_handlers)) { - printf("stray interrupt %d\n", i); - continue; - } if (intr_event_handle(ie, tf) != 0) { printf("stray interrupt %d\n", i); } - pic_delayed_ack(i, 0); } critical_exit(); } diff --git a/sys/mips/rmi/iodi.c b/sys/mips/rmi/iodi.c index 3f58218fa76..60b7915d1bc 100644 --- a/sys/mips/rmi/iodi.c +++ b/sys/mips/rmi/iodi.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -48,28 +49,17 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include -#include -#include -#include -#include - - #include #include #include /* for DELAY */ -#include #include + +#include +#include #include #include #include -#include -#include -#include -#include -#include +#include #include #include @@ -89,56 +79,49 @@ iodi_setup_intr(device_t, device_t, struct resource *, int, struct iodi_softc *iodi_softc; /* There can be only one. */ +/* + * We will manage the Flash/PCMCIA devices in IODI for now. + * The NOR flash, Compact flash etc. which can be connected on + * various chip selects on the peripheral IO, should have a + * separate bus later. + */ +static void +bridge_pcmcia_ack(int irq) +{ + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET); + + xlr_write_reg(mmio, 0x60, 0xffffffff); +} + static int iodi_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t * filt, driver_intr_t * intr, void *arg, - void **cookiep) + struct resource *ires, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) { - int level; - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - xlr_reg_t reg; + const char *name = device_get_name(child); - /* FIXME is this the right place to fiddle with PIC? */ - if (strcmp(device_get_name(child), "uart") == 0) { + if (strcmp(name, "uart") == 0) { /* FIXME uart 1? */ - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - level = PIC_IRQ_IS_EDGE_TRIGGERED(PIC_IRT_UART_0_INDEX); - xlr_write_reg(mmio, PIC_IRT_0_UART_0, 0x01); - xlr_write_reg(mmio, PIC_IRT_1_UART_0, ((1 << 31) | (level << 30) | (1 << 6) | (PIC_UART_0_IRQ))); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - cpu_establish_hardintr("uart", filt, - (driver_intr_t *) intr, (void *)arg, PIC_UART_0_IRQ, flags, cookiep); - - } else if (strcmp(device_get_name(child), "rge") == 0) { + cpu_establish_hardintr("uart", filt, intr, arg, + PIC_UART_0_IRQ, flags, cookiep); + pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 1); + } else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) { int irq; /* This is a hack to pass in the irq */ irq = (intptr_t)ires->__r_i; - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - reg = xlr_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE); - xlr_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE, reg | (1 << 6) | (1 << 30) | (1 << 31)); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - cpu_establish_hardintr("rge", filt, (driver_intr_t *) intr, (void *)arg, irq, flags, cookiep); - - } else if (strcmp(device_get_name(child), "ehci") == 0) { - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - reg = xlr_read_reg(mmio, PIC_IRT_1_BASE + PIC_USB_IRQ - PIC_IRQ_BASE); - xlr_write_reg(mmio, PIC_IRT_1_BASE + PIC_USB_IRQ - PIC_IRQ_BASE, reg | (1 << 6) | (1 << 30) | (1 << 31)); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - cpu_establish_hardintr("ehci", filt, (driver_intr_t *) intr, (void *)arg, PIC_USB_IRQ, flags, cookiep); + cpu_establish_hardintr("rge", filt, intr, arg, irq, flags, + cookiep); + pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 1); + } else if (strcmp(name, "ehci") == 0) { + cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags, + cookiep); + pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 1); + } else if (strcmp(name, "ata") == 0) { + xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags, + cookiep, bridge_pcmcia_ack); + pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 1); } - /* - * This causes a panic and looks recursive to me (RRS). - * BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, - * intr, arg, cookiep); - */ - return (0); } @@ -147,6 +130,7 @@ iodi_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK); + const char *name = device_get_name(child); int unit; #ifdef DEBUG @@ -168,7 +152,7 @@ iodi_alloc_resource(device_t bus, device_t child, int type, int *rid, } #endif - if (strcmp(device_get_name(child), "uart") == 0) { + if (strcmp(name, "uart") == 0) { if ((unit = device_get_unit(child)) == 0) { /* uart 0 */ res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET); } else if (unit == 1) { @@ -177,12 +161,15 @@ iodi_alloc_resource(device_t bus, device_t child, int type, int *rid, printf("%s: Unknown uart unit\n", __FUNCTION__); res->r_bustag = uart_bus_space_mem; - } else if (strcmp(device_get_name(child), "ehci") == 0) { + } else if (strcmp(name, "ehci") == 0) { res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000); res->r_bustag = rmi_pci_bus_space; - } else if (strcmp(device_get_name(child), "cfi") == 0) { + } else if (strcmp(name, "cfi") == 0) { res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000); res->r_bustag = 0; + } else if (strcmp(name, "ata") == 0) { + res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000); + res->r_bustag = rmi_pci_bus_space; /* byte swapping (not really PCI) */ } /* res->r_start = *rid; */ return (res); @@ -198,6 +185,7 @@ iodi_activate_resource(device_t bus, device_t child, int type, int rid, /* prototypes */ static int iodi_probe(device_t); static int iodi_attach(device_t); +static int iodi_detach(device_t); static void iodi_identify(driver_t *, device_t); int @@ -217,6 +205,7 @@ int iodi_attach(device_t dev) { device_t tmpd; + int i; /* * Attach each devices @@ -224,6 +213,7 @@ iodi_attach(device_t dev) device_add_child(dev, "uart", 0); device_add_child(dev, "xlr_i2c", 0); device_add_child(dev, "pcib", 0); + device_add_child(dev, "rmisec", -1); if (xlr_board_info.usb) device_add_child(dev, "ehci", 0); @@ -231,6 +221,9 @@ iodi_attach(device_t dev) if (xlr_board_info.cfi) device_add_child(dev, "cfi", 0); + if (xlr_board_info.ata) + device_add_child(dev, "ata", 0); + if (xlr_board_info.gmac_block[0].enabled) { tmpd = device_add_child(dev, "rge", 0); device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]); @@ -269,20 +262,51 @@ iodi_attach(device_t dev) tmpd = device_add_child(dev, "rge", 5); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); #endif - } else - device_printf(dev, "Unknown type of gmac 1\n"); + } else + device_printf(dev, "Unknown type of gmac 1\n"); + } + + /* This is to add the new GMAC driver. The above adds the old driver, + which has been retained for now as the new driver is stabilized. + The new driver is enabled with "option nlge". Make sure that only + one of rge or nlge is enabled in the conf file. */ + for (i = 0; i < 3; i++) { + if (xlr_board_info.gmac_block[i].enabled == 0) + continue; + tmpd = device_add_child(dev, "nlna", i); + device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]); } bus_generic_probe(dev); bus_generic_attach(dev); return 0; } +int +iodi_detach(device_t dev) +{ + device_t nlna_dev; + int error, i, ret; + + error = 0; + ret = 0; + for (i = 0; i < 3; i++) { + nlna_dev = device_find_child(dev, "nlna", i); + if (nlna_dev != NULL) + error = bus_generic_detach(nlna_dev); + if (error) + ret = error; + } + return ret; +} + static device_method_t iodi_methods[] = { DEVMETHOD(device_probe, iodi_probe), DEVMETHOD(device_attach, iodi_attach), + DEVMETHOD(device_detach, iodi_detach), DEVMETHOD(device_identify, iodi_identify), DEVMETHOD(bus_alloc_resource, iodi_alloc_resource), DEVMETHOD(bus_activate_resource, iodi_activate_resource), + DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_setup_intr, iodi_setup_intr), {0, 0}, }; diff --git a/sys/mips/rmi/iomap.h b/sys/mips/rmi/iomap.h index afc52bf712f..72756d25483 100644 --- a/sys/mips/rmi/iomap.h +++ b/sys/mips/rmi/iomap.h @@ -26,7 +26,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef _RMI_IOMAP_H_ #define _RMI_IOMAP_H_ diff --git a/sys/mips/rmi/msgring.h b/sys/mips/rmi/msgring.h index 43be63899f8..6110f5f5b25 100644 --- a/sys/mips/rmi/msgring.h +++ b/sys/mips/rmi/msgring.h @@ -26,333 +26,233 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef _RMI_MSGRING_H_ #define _RMI_MSGRING_H_ -#include +#include +#include +#include -#define MSGRNG_TX_BUF_REG 0 -#define MSGRNG_RX_BUF_REG 1 +#include +#include +#include -#define MSGRNG_MSG_STATUS_REG 2 -#define MSGRNG_MSG_CONFIG_REG 3 +#define MSGRNG_TX_BUF_REG 0 +#define MSGRNG_RX_BUF_REG 1 +#define MSGRNG_MSG_STATUS_REG 2 +#define MSGRNG_MSG_CONFIG_REG 3 +#define MSGRNG_MSG_BUCKSIZE_REG 4 -#define MSGRNG_MSG_BUCKSIZE_REG 4 - -#define MSGRNG_CC_0_REG 16 -#define MSGRNG_CC_1_REG 17 -#define MSGRNG_CC_2_REG 18 -#define MSGRNG_CC_3_REG 19 -#define MSGRNG_CC_4_REG 20 -#define MSGRNG_CC_5_REG 21 -#define MSGRNG_CC_6_REG 22 -#define MSGRNG_CC_7_REG 23 -#define MSGRNG_CC_8_REG 24 -#define MSGRNG_CC_9_REG 25 -#define MSGRNG_CC_10_REG 26 -#define MSGRNG_CC_11_REG 27 -#define MSGRNG_CC_12_REG 28 -#define MSGRNG_CC_13_REG 29 -#define MSGRNG_CC_14_REG 30 -#define MSGRNG_CC_15_REG 31 - -#define msgrng_read_status() read_c2_register32(MSGRNG_MSG_STATUS_REG, 0) - -#define msgrng_read_config() read_c2_register32(MSGRNG_MSG_CONFIG_REG, 0) -#define msgrng_write_config(value) write_c2_register32(MSGRNG_MSG_CONFIG_REG, 0, value) - -#define msgrng_read_bucksize(bucket) read_c2_register32(MSGRNG_MSG_BUCKSIZE_REG, bucket) -#define msgrng_write_bucksize(bucket, value) write_c2_register32(MSGRNG_MSG_BUCKSIZE_REG, bucket, value) - -#define msgrng_read_cc(reg, pri) read_c2_register32(reg, pri) -#define msgrng_write_cc(reg, value, pri) write_c2_register32(reg, pri, value) - -#define msgrng_load_rx_msg0() read_c2_register64(MSGRNG_RX_BUF_REG, 0) -#define msgrng_load_rx_msg1() read_c2_register64(MSGRNG_RX_BUF_REG, 1) -#define msgrng_load_rx_msg2() read_c2_register64(MSGRNG_RX_BUF_REG, 2) -#define msgrng_load_rx_msg3() read_c2_register64(MSGRNG_RX_BUF_REG, 3) - -#define msgrng_load_tx_msg0(value) write_c2_register64(MSGRNG_TX_BUF_REG, 0, value) -#define msgrng_load_tx_msg1(value) write_c2_register64(MSGRNG_TX_BUF_REG, 1, value) -#define msgrng_load_tx_msg2(value) write_c2_register64(MSGRNG_TX_BUF_REG, 2, value) -#define msgrng_load_tx_msg3(value) write_c2_register64(MSGRNG_TX_BUF_REG, 3, value) +#define MSGRNG_CC_0_REG 16 +#define MSGRNG_CC_1_REG 17 +#define MSGRNG_CC_2_REG 18 +#define MSGRNG_CC_3_REG 19 +#define MSGRNG_CC_4_REG 20 +#define MSGRNG_CC_5_REG 21 +#define MSGRNG_CC_6_REG 22 +#define MSGRNG_CC_7_REG 23 +#define MSGRNG_CC_8_REG 24 +#define MSGRNG_CC_9_REG 25 +#define MSGRNG_CC_10_REG 26 +#define MSGRNG_CC_11_REG 27 +#define MSGRNG_CC_12_REG 28 +#define MSGRNG_CC_13_REG 29 +#define MSGRNG_CC_14_REG 30 +#define MSGRNG_CC_15_REG 31 /* Station IDs */ -#define MSGRNG_STNID_CPU0 0x00 -#define MSGRNG_STNID_CPU1 0x08 -#define MSGRNG_STNID_CPU2 0x10 -#define MSGRNG_STNID_CPU3 0x18 -#define MSGRNG_STNID_CPU4 0x20 -#define MSGRNG_STNID_CPU5 0x28 -#define MSGRNG_STNID_CPU6 0x30 -#define MSGRNG_STNID_CPU7 0x38 -#define MSGRNG_STNID_XGS0_TX 64 -#define MSGRNG_STNID_XMAC0_00_TX 64 -#define MSGRNG_STNID_XMAC0_01_TX 65 -#define MSGRNG_STNID_XMAC0_02_TX 66 -#define MSGRNG_STNID_XMAC0_03_TX 67 -#define MSGRNG_STNID_XMAC0_04_TX 68 -#define MSGRNG_STNID_XMAC0_05_TX 69 -#define MSGRNG_STNID_XMAC0_06_TX 70 -#define MSGRNG_STNID_XMAC0_07_TX 71 -#define MSGRNG_STNID_XMAC0_08_TX 72 -#define MSGRNG_STNID_XMAC0_09_TX 73 -#define MSGRNG_STNID_XMAC0_10_TX 74 -#define MSGRNG_STNID_XMAC0_11_TX 75 -#define MSGRNG_STNID_XMAC0_12_TX 76 -#define MSGRNG_STNID_XMAC0_13_TX 77 -#define MSGRNG_STNID_XMAC0_14_TX 78 -#define MSGRNG_STNID_XMAC0_15_TX 79 +#define MSGRNG_STNID_CPU0 0x00 +#define MSGRNG_STNID_CPU1 0x08 +#define MSGRNG_STNID_CPU2 0x10 +#define MSGRNG_STNID_CPU3 0x18 +#define MSGRNG_STNID_CPU4 0x20 +#define MSGRNG_STNID_CPU5 0x28 +#define MSGRNG_STNID_CPU6 0x30 +#define MSGRNG_STNID_CPU7 0x38 +#define MSGRNG_STNID_XGS0_TX 64 +#define MSGRNG_STNID_XMAC0_00_TX 64 +#define MSGRNG_STNID_XMAC0_01_TX 65 +#define MSGRNG_STNID_XMAC0_02_TX 66 +#define MSGRNG_STNID_XMAC0_03_TX 67 +#define MSGRNG_STNID_XMAC0_04_TX 68 +#define MSGRNG_STNID_XMAC0_05_TX 69 +#define MSGRNG_STNID_XMAC0_06_TX 70 +#define MSGRNG_STNID_XMAC0_07_TX 71 +#define MSGRNG_STNID_XMAC0_08_TX 72 +#define MSGRNG_STNID_XMAC0_09_TX 73 +#define MSGRNG_STNID_XMAC0_10_TX 74 +#define MSGRNG_STNID_XMAC0_11_TX 75 +#define MSGRNG_STNID_XMAC0_12_TX 76 +#define MSGRNG_STNID_XMAC0_13_TX 77 +#define MSGRNG_STNID_XMAC0_14_TX 78 +#define MSGRNG_STNID_XMAC0_15_TX 79 -#define MSGRNG_STNID_XGS1_TX 80 -#define MSGRNG_STNID_XMAC1_00_TX 80 -#define MSGRNG_STNID_XMAC1_01_TX 81 -#define MSGRNG_STNID_XMAC1_02_TX 82 -#define MSGRNG_STNID_XMAC1_03_TX 83 -#define MSGRNG_STNID_XMAC1_04_TX 84 -#define MSGRNG_STNID_XMAC1_05_TX 85 -#define MSGRNG_STNID_XMAC1_06_TX 86 -#define MSGRNG_STNID_XMAC1_07_TX 87 -#define MSGRNG_STNID_XMAC1_08_TX 88 -#define MSGRNG_STNID_XMAC1_09_TX 89 -#define MSGRNG_STNID_XMAC1_10_TX 90 -#define MSGRNG_STNID_XMAC1_11_TX 91 -#define MSGRNG_STNID_XMAC1_12_TX 92 -#define MSGRNG_STNID_XMAC1_13_TX 93 -#define MSGRNG_STNID_XMAC1_14_TX 94 -#define MSGRNG_STNID_XMAC1_15_TX 95 +#define MSGRNG_STNID_XGS1_TX 80 +#define MSGRNG_STNID_XMAC1_00_TX 80 +#define MSGRNG_STNID_XMAC1_01_TX 81 +#define MSGRNG_STNID_XMAC1_02_TX 82 +#define MSGRNG_STNID_XMAC1_03_TX 83 +#define MSGRNG_STNID_XMAC1_04_TX 84 +#define MSGRNG_STNID_XMAC1_05_TX 85 +#define MSGRNG_STNID_XMAC1_06_TX 86 +#define MSGRNG_STNID_XMAC1_07_TX 87 +#define MSGRNG_STNID_XMAC1_08_TX 88 +#define MSGRNG_STNID_XMAC1_09_TX 89 +#define MSGRNG_STNID_XMAC1_10_TX 90 +#define MSGRNG_STNID_XMAC1_11_TX 91 +#define MSGRNG_STNID_XMAC1_12_TX 92 +#define MSGRNG_STNID_XMAC1_13_TX 93 +#define MSGRNG_STNID_XMAC1_14_TX 94 +#define MSGRNG_STNID_XMAC1_15_TX 95 -#define MSGRNG_STNID_GMAC 96 -#define MSGRNG_STNID_GMACJFR_0 96 -#define MSGRNG_STNID_GMACRFR_0 97 -#define MSGRNG_STNID_GMACTX0 98 -#define MSGRNG_STNID_GMACTX1 99 -#define MSGRNG_STNID_GMACTX2 100 -#define MSGRNG_STNID_GMACTX3 101 -#define MSGRNG_STNID_GMACJFR_1 102 -#define MSGRNG_STNID_GMACRFR_1 103 +#define MSGRNG_STNID_GMAC 96 +#define MSGRNG_STNID_GMACJFR_0 96 +#define MSGRNG_STNID_GMACRFR_0 97 +#define MSGRNG_STNID_GMACTX0 98 +#define MSGRNG_STNID_GMACTX1 99 +#define MSGRNG_STNID_GMACTX2 100 +#define MSGRNG_STNID_GMACTX3 101 +#define MSGRNG_STNID_GMACJFR_1 102 +#define MSGRNG_STNID_GMACRFR_1 103 -#define MSGRNG_STNID_DMA 104 -#define MSGRNG_STNID_DMA_0 104 -#define MSGRNG_STNID_DMA_1 105 -#define MSGRNG_STNID_DMA_2 106 -#define MSGRNG_STNID_DMA_3 107 +#define MSGRNG_STNID_DMA 104 +#define MSGRNG_STNID_DMA_0 104 +#define MSGRNG_STNID_DMA_1 105 +#define MSGRNG_STNID_DMA_2 106 +#define MSGRNG_STNID_DMA_3 107 -#define MSGRNG_STNID_XGS0FR 112 -#define MSGRNG_STNID_XMAC0JFR 112 -#define MSGRNG_STNID_XMAC0RFR 113 +#define MSGRNG_STNID_XGS0FR 112 +#define MSGRNG_STNID_XMAC0JFR 112 +#define MSGRNG_STNID_XMAC0RFR 113 -#define MSGRNG_STNID_XGS1FR 114 -#define MSGRNG_STNID_XMAC1JFR 114 -#define MSGRNG_STNID_XMAC1RFR 115 -#define MSGRNG_STNID_SEC 120 -#define MSGRNG_STNID_SEC0 120 -#define MSGRNG_STNID_SEC1 121 -#define MSGRNG_STNID_SEC2 122 -#define MSGRNG_STNID_SEC3 123 -#define MSGRNG_STNID_PK0 124 -#define MSGRNG_STNID_SEC_RSA 124 -#define MSGRNG_STNID_SEC_RSVD0 125 -#define MSGRNG_STNID_SEC_RSVD1 126 -#define MSGRNG_STNID_SEC_RSVD2 127 +#define MSGRNG_STNID_XGS1FR 114 +#define MSGRNG_STNID_XMAC1JFR 114 +#define MSGRNG_STNID_XMAC1RFR 115 +#define MSGRNG_STNID_SEC 120 +#define MSGRNG_STNID_SEC0 120 +#define MSGRNG_STNID_SEC1 121 +#define MSGRNG_STNID_SEC2 122 +#define MSGRNG_STNID_SEC3 123 +#define MSGRNG_STNID_PK0 124 +#define MSGRNG_STNID_SEC_RSA 124 +#define MSGRNG_STNID_SEC_RSVD0 125 +#define MSGRNG_STNID_SEC_RSVD1 126 +#define MSGRNG_STNID_SEC_RSVD2 127 -#define MSGRNG_STNID_GMAC1 80 -#define MSGRNG_STNID_GMAC1_FR_0 81 -#define MSGRNG_STNID_GMAC1_TX0 82 -#define MSGRNG_STNID_GMAC1_TX1 83 -#define MSGRNG_STNID_GMAC1_TX2 84 -#define MSGRNG_STNID_GMAC1_TX3 85 -#define MSGRNG_STNID_GMAC1_FR_1 87 -#define MSGRNG_STNID_GMAC0 96 -#define MSGRNG_STNID_GMAC0_FR_0 97 -#define MSGRNG_STNID_GMAC0_TX0 98 -#define MSGRNG_STNID_GMAC0_TX1 99 -#define MSGRNG_STNID_GMAC0_TX2 100 -#define MSGRNG_STNID_GMAC0_TX3 101 -#define MSGRNG_STNID_GMAC0_FR_1 103 -#define MSGRNG_STNID_CMP_0 108 -#define MSGRNG_STNID_CMP_1 109 -#define MSGRNG_STNID_CMP_2 110 -#define MSGRNG_STNID_CMP_3 111 -#define MSGRNG_STNID_PCIE_0 116 -#define MSGRNG_STNID_PCIE_1 117 -#define MSGRNG_STNID_PCIE_2 118 -#define MSGRNG_STNID_PCIE_3 119 -#define MSGRNG_STNID_XLS_PK0 121 +#define MSGRNG_STNID_GMAC1 80 +#define MSGRNG_STNID_GMAC1_FR_0 81 +#define MSGRNG_STNID_GMAC1_TX0 82 +#define MSGRNG_STNID_GMAC1_TX1 83 +#define MSGRNG_STNID_GMAC1_TX2 84 +#define MSGRNG_STNID_GMAC1_TX3 85 +#define MSGRNG_STNID_GMAC1_FR_1 87 +#define MSGRNG_STNID_GMAC0 96 +#define MSGRNG_STNID_GMAC0_FR_0 97 +#define MSGRNG_STNID_GMAC0_TX0 98 +#define MSGRNG_STNID_GMAC0_TX1 99 +#define MSGRNG_STNID_GMAC0_TX2 100 +#define MSGRNG_STNID_GMAC0_TX3 101 +#define MSGRNG_STNID_GMAC0_FR_1 103 +#define MSGRNG_STNID_CMP_0 108 +#define MSGRNG_STNID_CMP_1 109 +#define MSGRNG_STNID_CMP_2 110 +#define MSGRNG_STNID_CMP_3 111 +#define MSGRNG_STNID_PCIE_0 116 +#define MSGRNG_STNID_PCIE_1 117 +#define MSGRNG_STNID_PCIE_2 118 +#define MSGRNG_STNID_PCIE_3 119 +#define MSGRNG_STNID_XLS_PK0 121 -#define MSGRNG_CODE_MAC 0 -#define MSGRNG_CODE_XGMAC 2 -#define MSGRNG_CODE_SEC 0 -#define MSGRNG_CODE_BOOT_WAKEUP 200 -#define MSGRNG_CODE_SPI4 3 +#define MSGRNG_CODE_MAC 0 +#define MSGRNG_CODE_XGMAC 2 +#define MSGRNG_CODE_SEC 0 +#define MSGRNG_CODE_BOOT_WAKEUP 200 +#define MSGRNG_CODE_SPI4 3 -static inline int -msgrng_xgmac_stid_rfr(int id) -{ - return !id ? MSGRNG_STNID_XMAC0RFR : MSGRNG_STNID_XMAC1RFR; -} +#define msgrng_read_status() read_c2_register32(MSGRNG_MSG_STATUS_REG, 0) +#define msgrng_read_config() read_c2_register32(MSGRNG_MSG_CONFIG_REG, 0) +#define msgrng_write_config(v) write_c2_register32(MSGRNG_MSG_CONFIG_REG, 0, v) +#define msgrng_read_bucksize(b) read_c2_register32(MSGRNG_MSG_BUCKSIZE_REG, b) +#define msgrng_write_bucksize(b, v) write_c2_register32(MSGRNG_MSG_BUCKSIZE_REG, b, v) +#define msgrng_read_cc(r, s) read_c2_register32(r, s) +#define msgrng_write_cc(r, v, s) write_c2_register32(r, s, v) -static inline int -msgrng_xgmac_stid_jfr(int id) -{ - return !id ? MSGRNG_STNID_XMAC0JFR : MSGRNG_STNID_XMAC1JFR; -} +#define msgrng_load_rx_msg0() read_c2_register64(MSGRNG_RX_BUF_REG, 0) +#define msgrng_load_rx_msg1() read_c2_register64(MSGRNG_RX_BUF_REG, 1) +#define msgrng_load_rx_msg2() read_c2_register64(MSGRNG_RX_BUF_REG, 2) +#define msgrng_load_rx_msg3() read_c2_register64(MSGRNG_RX_BUF_REG, 3) -static inline int -msgrng_xgmac_stid_tx(int id) -{ - return !id ? MSGRNG_STNID_XMAC0_00_TX : MSGRNG_STNID_XMAC1_00_TX; -} +#define msgrng_load_tx_msg0(v) write_c2_register64(MSGRNG_TX_BUF_REG, 0, v) +#define msgrng_load_tx_msg1(v) write_c2_register64(MSGRNG_TX_BUF_REG, 1, v) +#define msgrng_load_tx_msg2(v) write_c2_register64(MSGRNG_TX_BUF_REG, 2, v) +#define msgrng_load_tx_msg3(v) write_c2_register64(MSGRNG_TX_BUF_REG, 3, v) -static inline int -msgrng_gmac_stid_rfr(int id) -{ - return (MSGRNG_STNID_GMACRFR_0); -} - -static inline int -msgrng_gmac_stid_rfr_split_mode(int id) -{ - return ((id >> 1) ? MSGRNG_STNID_GMACRFR_1 : MSGRNG_STNID_GMACRFR_0); -} - -static inline int -msgrng_gmac_stid_jfr(int id) -{ - return MSGRNG_STNID_GMACJFR_0; -} - -static inline int -msgrng_gmac_stid_jfr_split_mode(int id) -{ - return ((id >> 1) ? MSGRNG_STNID_GMACJFR_1 : MSGRNG_STNID_GMACJFR_0); -} - -static inline int -msgrng_gmac_stid_tx(int id) -{ - return (MSGRNG_STNID_GMACTX0 + id); -} - -static inline void +static __inline void msgrng_send(unsigned int stid) { __asm__ volatile ( - ".set push\n" - ".set noreorder\n" - "sync\n" - // "msgsnd %0\n" - "move $8, %0\n" - "c2 0x80001\n" - ".set pop\n" - :: "r" (stid):"$8" + ".set push\n" + ".set noreorder\n" + "move $8, %0\n" + "c2 0x80001\n" /* msgsnd $8 */ + ".set pop\n" + :: "r" (stid): "$8" ); } -static inline void +static __inline void msgrng_receive(unsigned int pri) { __asm__ volatile ( - ".set push\n" - ".set noreorder\n" - // "msgld %0\n" - "move $8, %0\n" - "c2 0x80002\n" - ".set pop\n" - :: "r" (pri):"$8" + ".set push\n" + ".set noreorder\n" + "move $8, %0\n" + "c2 0x80002\n" /* msgld $8 */ + ".set pop\n" + :: "r" (pri): "$8" ); } -static inline void + +static __inline void msgrng_wait(unsigned int mask) { __asm__ volatile ( - ".set push\n" - ".set noreorder\n" - // "msgwait %0\n" - "move $8, %0\n" - "c2 0x80003\n" - ".set pop\n" - :: "r" (mask):"$8" + ".set push\n" + ".set noreorder\n" + "move $8, %0\n" + "c2 0x80003\n" /* msgwait $8 */ + ".set pop\n" + :: "r" (mask): "$8" ); } -#define msgrng_enable(flags) \ -do { \ - __asm__ volatile ( \ - ".set push\n\t" \ - ".set reorder\n\t" \ - ".set noat\n\t" \ - "mfc0 %0, $12\n\t" \ - "li $8, 0x40000001\n\t" \ - "or $1, %0, $8\n\t" \ - "xori $1, 1\n\t" \ - ".set noreorder\n\t" \ - "mtc0 $1, $12\n\t" \ - ".set\tpop\n\t" \ - : "=r" (flags) \ - : \ - : "$8" \ - ); \ -} while (0) +static __inline uint32_t +msgrng_access_enable(void) +{ + uint32_t sr = mips_rd_status(); -#define msgrng_disable(flags) __asm__ volatile ( \ - "mtc0 %0, $12" : : "r" (flags)) + mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_COP_2_BIT); + return (sr); +} -#define msgrng_flags_save(flags) msgrng_enable(flags) -#define msgrng_flags_restore(flags) msgrng_disable(flags) +static __inline void +msgrng_restore(uint32_t sr) +{ + + mips_wr_status(sr); +} struct msgrng_msg { - __uint64_t msg0; - __uint64_t msg1; - __uint64_t msg2; - __uint64_t msg3; + uint64_t msg0; + uint64_t msg1; + uint64_t msg2; + uint64_t msg3; }; -static inline void -message_send_block_fast(int size, unsigned int code, unsigned int stid, - unsigned long long msg0, unsigned long long msg1, - unsigned long long msg2, unsigned long long msg3) -{ - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - ".set mips64\n" - "dmtc2 %1, $0, 0\n" - "dmtc2 %2, $0, 1\n" - "dmtc2 %3, $0, 2\n" - "dmtc2 %4, $0, 3\n" - "move $8, %0\n" - "1: c2 0x80001\n" - "mfc2 $8, $2\n" - "andi $8, $8, 0x6\n" - "bnez $8, 1b\n" - "move $8, %0\n" - ".set pop\n" - : - : "r"(((size - 1) << 16) | (code << 8) | stid), "r"(msg0), "r"(msg1), "r"(msg2), "r"(msg3) - : "$8" - ); -} - -#define message_receive_fast(bucket, size, code, stid, msg0, msg1, msg2, msg3) \ - ( { unsigned int _status=0, _tmp=0; \ - msgrng_receive(bucket); \ - while ( (_status=msgrng_read_status()) & 0x08) ; \ - _tmp = _status & 0x30; \ - if (__builtin_expect((!_tmp), 1)) { \ - (size)=((_status & 0xc0)>>6)+1; \ - (code)=(_status & 0xff00)>>8; \ - (stid)=(_status & 0x7f0000)>>16; \ - (msg0)=msgrng_load_rx_msg0(); \ - (msg1)=msgrng_load_rx_msg1(); \ - (msg2)=msgrng_load_rx_msg2(); \ - (msg3)=msgrng_load_rx_msg3(); \ - _tmp=0; \ - } \ - _tmp; \ - } ) - -static __inline__ int +static __inline int message_send(unsigned int size, unsigned int code, unsigned int stid, struct msgrng_msg *msg) { @@ -360,84 +260,75 @@ message_send(unsigned int size, unsigned int code, unsigned long long status = 0; int i = 0; + /* + * Make sure that all the writes pending at the cpu are flushed. + * Any writes pending on CPU will not be see by devices. L1/L2 + * caches are coherent with IO, so no cache flush needed. + */ + __asm __volatile ("sync"); + + /* Load TX message buffers */ msgrng_load_tx_msg0(msg->msg0); msgrng_load_tx_msg1(msg->msg1); msgrng_load_tx_msg2(msg->msg2); msgrng_load_tx_msg3(msg->msg3); + dest = ((size - 1) << 16) | (code << 8) | stid; - dest = ((size - 1) << 16) | (code << 8) | (stid); - - //dbg_msg("Sending msg<%Lx,%Lx,%Lx,%Lx> to dest = %x\n", - //msg->msg0, msg->msg1, msg->msg2, msg->msg3, dest); - - msgrng_send(dest); - - for (i = 0; i < 16; i++) { + /* + * Retry a few times on credit fail, this should be a + * transient condition, unless there is a configuration + * failure, or the receiver is stuck. + */ + for (i = 0; i < 8; i++) { + msgrng_send(dest); status = msgrng_read_status(); - //dbg_msg("status = %Lx\n", status); + KASSERT((status & 0x2) == 0, ("Send pending fail!")); + if ((status & 0x4) == 0) + return (0); + } - if (status & 0x6) { - continue; - } else - break; - } - if (i == 16) { - if (dest == 0x61) - //dbg_msg("Processor %x: Unable to send msg to %llx\n", processor_id(), dest); - return status & 0x6; - } - return msgrng_read_status() & 0x06; + /* If there is a credit failure, return error */ + return (status & 0x06); } -static __inline__ int -message_send_retry(unsigned int size, unsigned int code, - unsigned int stid, struct msgrng_msg *msg) -{ - int res = 0; - int retry = 0; - - for (;;) { - res = message_send(size, code, stid, msg); - /* retry a pending fail */ - if (res & 0x02) - continue; - /* credit fail */ - if (res & 0x04) - retry++; - else - break; - if (retry == 4) - return res & 0x06; - } - - return 0; -} - -static __inline__ int -message_receive(int pri, int *size, int *code, int *src_id, +static __inline int +message_receive(int bucket, int *size, int *code, int *stid, struct msgrng_msg *msg) { - int res = message_receive_fast(pri, *size, *code, *src_id, msg->msg0, msg->msg1, msg->msg2, msg->msg3); + uint32_t status = 0, tmp = 0; + + msgrng_receive(bucket); -#ifdef MSGRING_DUMP_MESSAGES - if (!res) { - dbg_msg("Received msg <%llx, %llx, %llx, %llx> <%d,%d,%d>\n", - msg->msg0, msg->msg1, msg->msg2, msg->msg3, - *size, *code, *src_id); - } -#endif + /* wait for load pending to clear */ + do { + status = msgrng_read_status(); + } while ((status & 0x08) != 0); - return res; + /* receive error bits */ + tmp = status & 0x30; + if (tmp != 0) + return (tmp); + + *size = ((status & 0xc0) >> 6) + 1; + *code = (status & 0xff00) >> 8; + *stid = (status & 0x7f0000) >> 16; + msg->msg0 = msgrng_load_rx_msg0(); + msg->msg1 = msgrng_load_rx_msg1(); + msg->msg2 = msgrng_load_rx_msg2(); + msg->msg3 = msgrng_load_rx_msg3(); + return (0); } -#define MSGRNG_STN_RX_QSIZE 256 +#define MSGRNG_STN_RX_QSIZE 256 +#define MSGRNG_NSTATIONS 128 +#define MSGRNG_CORE_NBUCKETS 8 struct stn_cc { unsigned short counters[16][8]; }; struct bucket_size { - unsigned short bucket[128]; + unsigned short bucket[MSGRNG_NSTATIONS]; }; extern struct bucket_size bucket_sizes; @@ -469,61 +360,11 @@ extern struct stn_cc xls_cc_table_pcie; extern struct stn_cc xls_cc_table_dma; extern struct stn_cc xls_cc_table_sec; - -#define msgrng_access_save(lock, mflags) do { \ - if (rmi_spin_mutex_safe) mtx_lock_spin(lock); \ - msgrng_flags_save(mflags); \ - }while(0) - -#define msgrng_access_restore(lock, mflags) do { \ - msgrng_flags_restore(mflags); \ - if (rmi_spin_mutex_safe) mtx_unlock_spin(lock); \ - }while(0) - -#define msgrng_access_enable(mflags) do { \ - critical_enter(); \ - msgrng_flags_save(mflags); \ -} while(0) - -#define msgrng_access_disable(mflags) do { \ - msgrng_flags_restore(mflags); \ - critical_exit(); \ -} while(0) - -/* - * NOTE: this is not stationid/8, ie the station numbers below are just - * for internal use - */ -enum { - TX_STN_CPU_0, - TX_STN_CPU_1, - TX_STN_CPU_2, - TX_STN_CPU_3, - TX_STN_CPU_4, - TX_STN_CPU_5, - TX_STN_CPU_6, - TX_STN_CPU_7, - TX_STN_GMAC, - TX_STN_DMA, - TX_STN_XGS_0, - TX_STN_XGS_1, - TX_STN_SAE, - TX_STN_GMAC0, - TX_STN_GMAC1, - TX_STN_CDE, - TX_STN_PCIE, - TX_STN_INVALID, - MAX_TX_STNS -}; - -extern int -register_msgring_handler(int major, - void (*action) (int, int, int, int, struct msgrng_msg *, void *), - void *dev_id); - extern void xlr_msgring_cpu_init(void); - - extern void xlr_msgring_config(void); - -#define cpu_to_msgring_bucket(cpu) ((((cpu) >> 2)<<3)|((cpu) & 0x03)) +typedef void (*msgring_handler)(int, int, int, int, struct msgrng_msg *, void *); +int register_msgring_handler(int startb, int endb, msgring_handler action, + void *arg); +uint32_t xlr_msgring_handler(uint8_t bucket_mask, uint32_t max_messages); +void xlr_msgring_cpu_init(void); +void xlr_msgring_config(void); #endif diff --git a/sys/mips/rmi/on_chip.c b/sys/mips/rmi/on_chip.c deleted file mode 100644 index ec53394f310..00000000000 --- a/sys/mips/rmi/on_chip.c +++ /dev/null @@ -1,446 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - * - * RMI_BSD */ -#include -__FBSDID("$FreeBSD$"); -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -void -disable_msgring_int(void *arg); -void -enable_msgring_int(void *arg); - -/* definitions */ -struct tx_stn_handler { - void (*action) (int, int, int, int, struct msgrng_msg *, void *); - void *dev_id; -}; - -struct msgring_ithread { - struct thread *i_thread; - u_int i_pending; - u_int i_flags; - int i_cpu; - int i_core; -}; - -struct msgring_ithread *msgring_ithreads[MAXCPU]; - -/* globals */ -static struct tx_stn_handler tx_stn_handlers[MAX_TX_STNS]; - -#define MSGRNG_CC_INIT_CPU_DEST(dest, counter) \ -do { \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][0], 0 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][1], 1 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][2], 2 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][3], 3 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][4], 4 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][5], 5 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][6], 6 ); \ - msgrng_write_cc(MSGRNG_CC_##dest##_REG, counter[dest][7], 7 ); \ -} while(0) - - -/* make this a read/write spinlock */ -static struct mtx msgrng_lock; -static int msgring_int_enabled; -struct mtx xlr_pic_lock; - -static int msgring_pop_num_buckets; -static uint32_t msgring_pop_bucket_mask; -static int msgring_int_type; -static int msgring_watermark_count; -static uint32_t msgring_thread_mask; - -uint32_t msgrng_msg_cycles = 0; - -void xlr_msgring_handler(struct trapframe *); - -void -xlr_msgring_cpu_init(void) -{ - struct stn_cc *cc_config; - struct bucket_size *bucket_sizes; - int id; - unsigned long flags; - - KASSERT(xlr_thr_id() == 0, - ("xlr_msgring_cpu_init from non-zero thread\n")); - - id = xlr_core_id(); - - bucket_sizes = xlr_board_info.bucket_sizes; - cc_config = xlr_board_info.credit_configs[id]; - - msgrng_flags_save(flags); - - /* - * Message Stations are shared among all threads in a cpu core - * Assume, thread 0 on all cores are always active when more than 1 - * thread is active in a core - */ - msgrng_write_bucksize(0, bucket_sizes->bucket[id * 8 + 0]); - msgrng_write_bucksize(1, bucket_sizes->bucket[id * 8 + 1]); - msgrng_write_bucksize(2, bucket_sizes->bucket[id * 8 + 2]); - msgrng_write_bucksize(3, bucket_sizes->bucket[id * 8 + 3]); - msgrng_write_bucksize(4, bucket_sizes->bucket[id * 8 + 4]); - msgrng_write_bucksize(5, bucket_sizes->bucket[id * 8 + 5]); - msgrng_write_bucksize(6, bucket_sizes->bucket[id * 8 + 6]); - msgrng_write_bucksize(7, bucket_sizes->bucket[id * 8 + 7]); - - MSGRNG_CC_INIT_CPU_DEST(0, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(1, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(2, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(3, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(4, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(5, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(6, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(7, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(8, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(9, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(10, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(11, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(12, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(13, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(14, cc_config->counters); - MSGRNG_CC_INIT_CPU_DEST(15, cc_config->counters); - - msgrng_flags_restore(flags); -} - -void -xlr_msgring_config(void) -{ - msgring_int_type = 0x02; - msgring_pop_num_buckets = 8; - msgring_pop_bucket_mask = 0xff; - - msgring_watermark_count = 1; - msgring_thread_mask = 0x01; -} - -void -xlr_msgring_handler(struct trapframe *tf) -{ - unsigned long mflags; - int bucket = 0; - int size = 0, code = 0, rx_stid = 0, tx_stid = 0; - struct msgrng_msg msg; - unsigned int bucket_empty_bm = 0; - unsigned int status = 0; - - /* TODO: not necessary to disable preemption */ - msgrng_flags_save(mflags); - - /* First Drain all the high priority messages */ - for (;;) { - bucket_empty_bm = (msgrng_read_status() >> 24) & msgring_pop_bucket_mask; - - /* all buckets empty, break */ - if (bucket_empty_bm == msgring_pop_bucket_mask) - break; - - for (bucket = 0; bucket < msgring_pop_num_buckets; bucket++) { - if ((bucket_empty_bm & (1 << bucket)) /* empty */ ) - continue; - - status = message_receive(bucket, &size, &code, &rx_stid, &msg); - if (status) - continue; - - tx_stid = xlr_board_info.msgmap[rx_stid]; - - if (!tx_stn_handlers[tx_stid].action) { - printf("[%s]: No Handler for message from stn_id=%d, bucket=%d, " - "size=%d, msg0=%jx, dropping message\n", - __FUNCTION__, tx_stid, bucket, size, (uintmax_t)msg.msg0); - } else { - //printf("[%s]: rx_stid = %d\n", __FUNCTION__, rx_stid); - msgrng_flags_restore(mflags); - (*tx_stn_handlers[tx_stid].action) (bucket, size, code, rx_stid, - &msg, tx_stn_handlers[tx_stid].dev_id); - msgrng_flags_save(mflags); - } - } - } - - xlr_set_counter(MSGRNG_EXIT_STATUS, msgrng_read_status()); - - msgrng_flags_restore(mflags); -} - -void -enable_msgring_int(void *arg) -{ - unsigned long mflags = 0; - - msgrng_access_save(&msgrng_lock, mflags); - /* enable the message ring interrupts */ - msgrng_write_config((msgring_watermark_count << 24) | (IRQ_MSGRING << 16) - | (msgring_thread_mask << 8) | msgring_int_type); - msgrng_access_restore(&msgrng_lock, mflags); -} - -void -disable_msgring_int(void *arg) -{ - unsigned long mflags = 0; - uint32_t config; - - msgrng_access_save(&msgrng_lock, mflags); - config = msgrng_read_config(); - config &= ~0x3; - msgrng_write_config(config); - msgrng_access_restore(&msgrng_lock, mflags); -} - -static int -msgring_process_fast_intr(void *arg) -{ - int core = xlr_core_id(); - volatile struct msgring_ithread *it; - struct thread *td; - - /* wakeup an appropriate intr_thread for processing this interrupt */ - it = (volatile struct msgring_ithread *)msgring_ithreads[core]; - KASSERT(it != NULL, ("No interrupt thread on cpu %d", core)); - td = it->i_thread; - - /* - * Interrupt thread will enable the interrupts after processing all - * messages - */ - disable_msgring_int(NULL); - atomic_store_rel_int(&it->i_pending, 1); - thread_lock(td); - if (TD_AWAITING_INTR(td)) { - TD_CLR_IWAIT(td); - sched_add(td, SRQ_INTR); - } - thread_unlock(td); - return FILTER_HANDLED; -} - -static void -msgring_process(void *arg) -{ - volatile struct msgring_ithread *ithd; - struct thread *td; - struct proc *p; - - td = curthread; - p = td->td_proc; - ithd = (volatile struct msgring_ithread *)arg; - KASSERT(ithd->i_thread == td, - ("%s:msg_ithread and proc linkage out of sync", __func__)); - - /* First bind this thread to the right CPU */ - thread_lock(td); - - sched_bind(td, ithd->i_cpu); - thread_unlock(td); - - atomic_store_rel_ptr((volatile uintptr_t *)&msgring_ithreads[ithd->i_core], - (uintptr_t)arg); - enable_msgring_int(NULL); - - while (1) { - while (ithd->i_pending) { - /* - * This might need a full read and write barrier to - * make sure that this write posts before any of the - * memory or device accesses in the handlers. - */ - xlr_msgring_handler(NULL); - atomic_store_rel_int(&ithd->i_pending, 0); - enable_msgring_int(NULL); - } - if (!ithd->i_pending) { - thread_lock(td); - if (ithd->i_pending) { - thread_unlock(td); - continue; - } - sched_class(td, PRI_ITHD); - TD_SET_IWAIT(td); - mi_switch(SW_VOL, NULL); - thread_unlock(td); - } - } - -} - -static void -create_msgring_thread(int core, int cpu) -{ - struct msgring_ithread *ithd; - struct thread *td; - struct proc *p; - int error; - - /* Create kernel thread for message ring interrupt processing */ - /* Currently create one task for thread 0 of each core */ - ithd = malloc(sizeof(struct msgring_ithread), - M_DEVBUF, M_WAITOK | M_ZERO); - error = kproc_create(msgring_process, (void *)ithd, &p, - RFSTOPPED | RFHIGHPID, 2, "msg_intr%d", cpu); - - if (error) - panic("kproc_create() failed with %d", error); - td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ - - ithd->i_thread = td; - ithd->i_pending = 0; - ithd->i_cpu = cpu; - ithd->i_core = core; - - thread_lock(td); - sched_class(td, PRI_ITHD); - sched_add(td, SRQ_INTR); - thread_unlock(td); - CTR2(KTR_INTR, "%s: created %s", __func__, td->td_name); -} - -int -register_msgring_handler(int major, - void (*action) (int, int, int, int, struct msgrng_msg *, void *), - void *dev_id) -{ - void *cookie; /* FIXME - use? */ - - if (major >= MAX_TX_STNS) - return 1; - - //dbg_msg("major=%d, action=%p, dev_id=%p\n", major, action, dev_id); - - if (rmi_spin_mutex_safe) - mtx_lock_spin(&msgrng_lock); - tx_stn_handlers[major].action = action; - tx_stn_handlers[major].dev_id = dev_id; - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&msgrng_lock); - - if (xlr_test_and_set(&msgring_int_enabled)) { - create_msgring_thread(0, 0); - cpu_establish_hardintr("msgring", (driver_filter_t *) msgring_process_fast_intr, - NULL, NULL, IRQ_MSGRING, - INTR_TYPE_NET | INTR_FAST, &cookie); - } - return 0; -} - -static void -pic_init(void) -{ - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - int i = 0; - int level; - - dbg_msg("Initializing PIC...\n"); - for (i = 0; i < PIC_NUM_IRTS; i++) { - - level = PIC_IRQ_IS_EDGE_TRIGGERED(i); - - /* Bind all PIC irqs to cpu 0 */ - xlr_write_reg(mmio, PIC_IRT_0_BASE + i, 0x01); - - /* - * Use local scheduling and high polarity for all IRTs - * Invalidate all IRTs, by default - */ - xlr_write_reg(mmio, PIC_IRT_1_BASE + i, (level << 30) | (1 << 6) | - (PIC_IRQ_BASE + i)); - } - dbg_msg("PIC init now done\n"); -} - -void -on_chip_init(void) -{ - /* Set xlr_io_base to the run time value */ - mtx_init(&msgrng_lock, "msgring", NULL, MTX_SPIN | MTX_RECURSE); - mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN); - - xlr_board_info_setup(); - - msgring_int_enabled = 0; - - xlr_msgring_config(); - pic_init(); - - xlr_msgring_cpu_init(); -} - -static void -start_msgring_threads(void *arg) -{ - int core, cpu; - - for (core = 1; core < XLR_MAX_CORES; core++) { - if ((xlr_hw_thread_mask >> (4 * core)) & 0xf) { - /* start one thread for an enabled core */ - cpu = xlr_hwtid_to_cpuid[4 * core]; - create_msgring_thread(core, cpu); - } - } -} - -SYSINIT(start_msgring_threads, SI_SUB_SMP, SI_ORDER_MIDDLE, start_msgring_threads, NULL); diff --git a/sys/mips/rmi/pic.h b/sys/mips/rmi/pic.h index 05d2741266c..543369c561c 100644 --- a/sys/mips/rmi/pic.h +++ b/sys/mips/rmi/pic.h @@ -25,272 +25,248 @@ * 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. - * __FBSDID("$FreeBSD$"); * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef _RMI_PIC_H_ -#define _RMI_PIC_H_ +#define _RMI_PIC_H_ + #include - - - - -extern int rmi_spin_mutex_safe; - #include #include #include -#define PIC_IRT_WD_INDEX 0 -#define PIC_IRT_TIMER_0_INDEX 1 -#define PIC_IRT_TIMER_1_INDEX 2 -#define PIC_IRT_TIMER_2_INDEX 3 -#define PIC_IRT_TIMER_3_INDEX 4 -#define PIC_IRT_TIMER_4_INDEX 5 -#define PIC_IRT_TIMER_5_INDEX 6 -#define PIC_IRT_TIMER_6_INDEX 7 -#define PIC_IRT_TIMER_7_INDEX 8 -#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX -#define PIC_IRT_UART_0_INDEX 9 -#define PIC_IRT_UART_1_INDEX 10 -#define PIC_IRT_I2C_0_INDEX 11 -#define PIC_IRT_I2C_1_INDEX 12 -#define PIC_IRT_PCMCIA_INDEX 13 -#define PIC_IRT_GPIO_INDEX 14 -#define PIC_IRT_HYPER_INDEX 15 -#define PIC_IRT_PCIX_INDEX 16 -#define PIC_IRT_GMAC0_INDEX 17 -#define PIC_IRT_GMAC1_INDEX 18 -#define PIC_IRT_GMAC2_INDEX 19 -#define PIC_IRT_GMAC3_INDEX 20 -#define PIC_IRT_XGS0_INDEX 21 -#define PIC_IRT_XGS1_INDEX 22 -#define PIC_IRT_HYPER_FATAL_INDEX 23 -#define PIC_IRT_PCIX_FATAL_INDEX 24 -#define PIC_IRT_BRIDGE_AERR_INDEX 25 -#define PIC_IRT_BRIDGE_BERR_INDEX 26 -#define PIC_IRT_BRIDGE_TB_INDEX 27 -#define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28 +#define PIC_IRT_WD_INDEX 0 +#define PIC_IRT_TIMER_INDEX(i) (1 + (i)) +#define PIC_IRT_UART_0_INDEX 9 +#define PIC_IRT_UART_1_INDEX 10 +#define PIC_IRT_I2C_0_INDEX 11 +#define PIC_IRT_I2C_1_INDEX 12 +#define PIC_IRT_PCMCIA_INDEX 13 +#define PIC_IRT_GPIO_INDEX 14 +#define PIC_IRT_HYPER_INDEX 15 +#define PIC_IRT_PCIX_INDEX 16 +#define PIC_IRT_GMAC0_INDEX 17 +#define PIC_IRT_GMAC1_INDEX 18 +#define PIC_IRT_GMAC2_INDEX 19 +#define PIC_IRT_GMAC3_INDEX 20 +#define PIC_IRT_XGS0_INDEX 21 +#define PIC_IRT_XGS1_INDEX 22 +#define PIC_IRT_HYPER_FATAL_INDEX 23 +#define PIC_IRT_PCIX_FATAL_INDEX 24 +#define PIC_IRT_BRIDGE_AERR_INDEX 25 +#define PIC_IRT_BRIDGE_BERR_INDEX 26 +#define PIC_IRT_BRIDGE_TB_INDEX 27 +#define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28 /* numbering for XLS */ -#define PIC_IRT_BRIDGE_ERR_INDEX 25 -#define PIC_IRT_PCIE_LINK0_INDEX 26 -#define PIC_IRT_PCIE_LINK1_INDEX 27 -#define PIC_IRT_PCIE_LINK2_INDEX 23 -#define PIC_IRT_PCIE_LINK3_INDEX 24 -#define PIC_IRT_PCIE_INT_INDEX 28 -#define PIC_IRT_PCIE_FATAL_INDEX 29 -#define PIC_IRT_GPIO_B_INDEX 30 -#define PIC_IRT_USB_INDEX 31 +#define PIC_IRT_BRIDGE_ERR_INDEX 25 +#define PIC_IRT_PCIE_LINK0_INDEX 26 +#define PIC_IRT_PCIE_LINK1_INDEX 27 +#define PIC_IRT_PCIE_LINK2_INDEX 23 +#define PIC_IRT_PCIE_LINK3_INDEX 24 +#define PIC_IRT_PCIE_B0_LINK2_INDEX 28 +#define PIC_IRT_PCIE_B0_LINK3_INDEX 29 +#define PIC_IRT_PCIE_INT_INDEX 28 +#define PIC_IRT_PCIE_FATAL_INDEX 29 +#define PIC_IRT_GPIO_B_INDEX 30 +#define PIC_IRT_USB_INDEX 31 +#define PIC_NUM_IRTS 32 -#define PIC_NUM_IRTS 32 +#define PIC_CLOCK_TIMER 7 -#define PIC_SYS_TIMER_MAXVAL_0_BASE 0x100 -#define PIC_SYS_TIMER_MAXVAL_1_BASE 0x110 +#define PIC_CTRL 0x00 +#define PIC_IPI 0x04 +#define PIC_INT_ACK 0x06 -#define PIC_SYS_TIMER_0_BASE 0x120 -#define PIC_SYS_TIMER_1_BASE 0x130 +#define WD_MAX_VAL_0 0x08 +#define WD_MAX_VAL_1 0x09 +#define WD_MASK_0 0x0a +#define WD_MASK_1 0x0b +#define WD_HEARBEAT_0 0x0c +#define WD_HEARBEAT_1 0x0d -#define PIC_CLOCK_TIMER 7 +#define PIC_IRT_0_BASE 0x40 +#define PIC_IRT_1_BASE 0x80 +#define PIC_TIMER_MAXVAL_0_BASE 0x100 +#define PIC_TIMER_MAXVAL_1_BASE 0x110 +#define PIC_TIMER_COUNT_0_BASE 0x120 +#define PIC_TIMER_COUNT_1_BASE 0x130 -#define PIC_CTRL 0x00 -#define PIC_IPI 0x04 -#define PIC_INT_ACK 0x06 +#define PIC_IRT_0(picintr) (PIC_IRT_0_BASE + (picintr)) +#define PIC_IRT_1(picintr) (PIC_IRT_1_BASE + (picintr)) -#define WD_MAX_VAL_0 0x08 -#define WD_MAX_VAL_1 0x09 -#define WD_MASK_0 0x0a -#define WD_MASK_1 0x0b -#define WD_HEARBEAT_0 0x0c -#define WD_HEARBEAT_1 0x0d +#define PIC_TIMER_MAXVAL_0(i) (PIC_TIMER_MAXVAL_0_BASE + (i)) +#define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i)) +#define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i)) +#define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i)) +#define PIC_TIMER_HZ 66000000U -#define PIC_IRT_0_BASE 0x40 -#define PIC_IRT_1_BASE 0x80 +/* + * We use a simple mapping form PIC interrupts to CPU IRQs. + * The PIC interrupts 0-31 are mapped to CPU irq's 8-39. + * this leaves the lower 0-7 for the cpu interrupts (like + * count/compare, msgrng) and 40-63 for IPIs + */ +#define PIC_IRQ_BASE 8 +#define PIC_INTR_TO_IRQ(i) (PIC_IRQ_BASE + (i)) +#define PIC_IRQ_TO_INTR(i) ((i) - PIC_IRQ_BASE) -#define PIC_IRT_0_WD (PIC_IRT_0_BASE + PIC_IRT_WD_INDEX) -#define PIC_IRT_1_WD (PIC_IRT_1_BASE + PIC_IRT_WD_INDEX) -#define PIC_IRT_0_TIMER_0 (PIC_IRT_0_BASE + PIC_IRT_TIMER_0_INDEX) -#define PIC_IRT_1_TIMER_0 (PIC_IRT_1_BASE + PIC_IRT_TIMER_0_INDEX) -#define PIC_IRT_0_TIMER_1 (PIC_IRT_0_BASE + PIC_IRT_TIMER_1_INDEX) -#define PIC_IRT_1_TIMER_1 (PIC_IRT_1_BASE + PIC_IRT_TIMER_1_INDEX) -#define PIC_IRT_0_TIMER_2 (PIC_IRT_0_BASE + PIC_IRT_TIMER_2_INDEX) -#define PIC_IRT_1_TIMER_2 (PIC_IRT_1_BASE + PIC_IRT_TIMER_2_INDEX) -#define PIC_IRT_0_TIMER_3 (PIC_IRT_0_BASE + PIC_IRT_TIMER_3_INDEX) -#define PIC_IRT_1_TIMER_3 (PIC_IRT_1_BASE + PIC_IRT_TIMER_3_INDEX) -#define PIC_IRT_0_TIMER_4 (PIC_IRT_0_BASE + PIC_IRT_TIMER_4_INDEX) -#define PIC_IRT_1_TIMER_4 (PIC_IRT_1_BASE + PIC_IRT_TIMER_4_INDEX) -#define PIC_IRT_0_TIMER_5 (PIC_IRT_0_BASE + PIC_IRT_TIMER_5_INDEX) -#define PIC_IRT_1_TIMER_5 (PIC_IRT_1_BASE + PIC_IRT_TIMER_5_INDEX) -#define PIC_IRT_0_TIMER_6 (PIC_IRT_0_BASE + PIC_IRT_TIMER_6_INDEX) -#define PIC_IRT_1_TIMER_6 (PIC_IRT_1_BASE + PIC_IRT_TIMER_6_INDEX) -#define PIC_IRT_0_TIMER_7 (PIC_IRT_0_BASE + PIC_IRT_TIMER_7_INDEX) -#define PIC_IRT_1_TIMER_7 (PIC_IRT_1_BASE + PIC_IRT_TIMER_7_INDEX) -#define PIC_IRT_0_CLOCK (PIC_IRT_0_TIMER_7) -#define PIC_IRT_1_CLOCK (PIC_IRT_1_TIMER_7) -#define PIC_IRT_0_UART_0 (PIC_IRT_0_BASE + PIC_IRT_UART_0_INDEX) -#define PIC_IRT_1_UART_0 (PIC_IRT_1_BASE + PIC_IRT_UART_0_INDEX) -#define PIC_IRT_0_UART_1 (PIC_IRT_0_BASE + PIC_IRT_UART_1_INDEX) -#define PIC_IRT_1_UART_1 (PIC_IRT_1_BASE + PIC_IRT_UART_1_INDEX) -#define PIC_IRT_0_I2C_0 (PIC_IRT_0_BASE + PIC_IRT_I2C_0_INDEX) -#define PIC_IRT_1_I2C_0 (PIC_IRT_1_BASE + PIC_IRT_I2C_0_INDEX) -#define PIC_IRT_0_I2C_1 (PIC_IRT_0_BASE + PIC_IRT_I2C_1_INDEX) -#define PIC_IRT_1_I2C_1 (PIC_IRT_1_BASE + PIC_IRT_I2C_1_INDEX) -#define PIC_IRT_0_HYPER (PIC_IRT_0_BASE + PIC_IRT_HYPER_INDEX) -#define PIC_IRT_1_HYPER (PIC_IRT_1_BASE + PIC_IRT_HYPER_INDEX) -#define PIC_IRT_0_PCIX (PIC_IRT_0_BASE + PIC_IRT_PCIX_INDEX) -#define PIC_IRT_1_PCIX (PIC_IRT_1_BASE + PIC_IRT_PCIX_INDEX) +#define PIC_WD_IRQ (PIC_IRQ_BASE + PIC_IRT_WD_INDEX) +#define PIC_TIMER_IRQ(i) (PIC_IRQ_BASE + PIC_IRT_TIMER_INDEX(i)) +#define PIC_CLOCK_IRQ PIC_TIMER_IRQ(PIC_CLOCK_TIMER) -#define PIC_TIMER_0_MAXVAL_0 (PIC_SYS_TIMER_MAXVAL_0_BASE + 0) -#define PIC_TIMER_0_MAXVAL_1 (PIC_SYS_TIMER_MAXVAL_1_BASE + 0) -#define PIC_TIMER_0_COUNTER_0 (PIC_SYS_TIMER_0_BASE + 0) -#define PIC_TIMER_0_COUNTER_1 (PIC_SYS_TIMER_1_BASE + 0) -#define PIC_TIMER_6_MAXVAL_0 (PIC_SYS_TIMER_MAXVAL_0_BASE + 6) -#define PIC_TIMER_6_MAXVAL_1 (PIC_SYS_TIMER_MAXVAL_1_BASE + 6) -#define PIC_TIMER_6_COUNTER_0 (PIC_SYS_TIMER_0_BASE + 6) -#define PIC_TIMER_6_COUNTER_1 (PIC_SYS_TIMER_1_BASE + 6) -#define PIC_TIMER_7_MAXVAL_0 (PIC_SYS_TIMER_MAXVAL_0_BASE + 7) -#define PIC_TIMER_7_MAXVAL_1 (PIC_SYS_TIMER_MAXVAL_1_BASE + 7) -#define PIC_TIMER_7_COUNTER_0 (PIC_SYS_TIMER_0_BASE + 7) -#define PIC_TIMER_7_COUNTER_1 (PIC_SYS_TIMER_1_BASE + 7) - -#define PIC_IRQ_BASE 8 -#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE -#define PIC_WD_IRQ (PIC_IRQ_BASE + PIC_IRT_WD_INDEX) -#define PIC_TIMER_0_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_0_INDEX) -#define PIC_TIMER_1_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_1_INDEX) -#define PIC_TIMER_2_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_2_INDEX) -#define PIC_TIMER_3_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_3_INDEX) -#define PIC_TIMER_4_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_4_INDEX) -#define PIC_TIMER_5_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_5_INDEX) -#define PIC_TIMER_6_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_6_INDEX) -#define PIC_TIMER_7_IRQ (PIC_IRQ_BASE + PIC_IRT_TIMER_7_INDEX) -#define PIC_CLOCK_IRQ (PIC_TIMER_7_IRQ) -#define PIC_UART_0_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_0_INDEX) -#define PIC_UART_1_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_1_INDEX) -#define PIC_I2C_0_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_0_INDEX) -#define PIC_I2C_1_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_1_INDEX) -#define PIC_PCMCIA_IRQ (PIC_IRQ_BASE + PIC_IRT_PCMCIA_INDEX) -#define PIC_GPIO_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_INDEX) -#define PIC_HYPER_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_INDEX) -#define PIC_PCIX_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_INDEX) -#define PIC_GMAC_0_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC0_INDEX) -#define PIC_GMAC_1_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC1_INDEX) -#define PIC_GMAC_2_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC2_INDEX) -#define PIC_GMAC_3_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC3_INDEX) -#define PIC_XGS_0_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS0_INDEX) -#define PIC_XGS_1_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS1_INDEX) -#define PIC_HYPER_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_FATAL_INDEX) -#define PIC_PCIX_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_FATAL_INDEX) -#define PIC_BRIDGE_AERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_INDEX) -#define PIC_BRIDGE_BERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_BERR_INDEX) -#define PIC_BRIDGE_TB_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_TB_INDEX) -#define PIC_BRIDGE_AERR_NMI_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_NMI_INDEX) - -#define PIC_BRIDGE_ERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_ERR_INDEX) -#define PIC_PCIE_LINK0_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK0_INDEX) -#define PIC_PCIE_LINK1_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK1_INDEX) -#define PIC_PCIE_LINK2_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK2_INDEX) -#define PIC_PCIE_LINK3_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK3_INDEX) -#define PIC_PCIE_INT_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_INT__INDEX) -#define PIC_PCIE_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_FATAL_INDEX) -#define PIC_GPIO_B_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_B_INDEX) -#define PIC_USB_IRQ (PIC_IRQ_BASE + PIC_IRT_USB_INDEX) - -#define PIC_IRT_LAST_IRQ PIC_USB_IRQ - -#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) ( ((irq)>=PIC_TIMER_0_IRQ) && ((irq)<=PIC_TIMER_7_IRQ) ) - -#define PIC_IRQ_IS_IRT(irq) ( ((irq)>=PIC_IRT_FIRST_IRQ) && ((irq)<=PIC_IRT_LAST_IRQ) ) +#define PIC_UART_0_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_0_INDEX) +#define PIC_UART_1_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_1_INDEX) +#define PIC_I2C_0_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_0_INDEX) +#define PIC_I2C_1_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_1_INDEX) +#define PIC_PCMCIA_IRQ (PIC_IRQ_BASE + PIC_IRT_PCMCIA_INDEX) +#define PIC_GPIO_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_INDEX) +#define PIC_HYPER_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_INDEX) +#define PIC_PCIX_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_INDEX) +#define PIC_GMAC_0_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC0_INDEX) +#define PIC_GMAC_1_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC1_INDEX) +#define PIC_GMAC_2_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC2_INDEX) +#define PIC_GMAC_3_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC3_INDEX) +#define PIC_XGS_0_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS0_INDEX) +#define PIC_XGS_1_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS1_INDEX) +#define PIC_HYPER_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_FATAL_INDEX) +#define PIC_PCIX_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_FATAL_INDEX) +#define PIC_BRIDGE_AERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_INDEX) +#define PIC_BRIDGE_BERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_BERR_INDEX) +#define PIC_BRIDGE_TB_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_TB_INDEX) +#define PIC_BRIDGE_AERR_NMI_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_NMI_INDEX) +#define PIC_BRIDGE_ERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_ERR_INDEX) +#define PIC_PCIE_LINK0_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK0_INDEX) +#define PIC_PCIE_LINK1_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK1_INDEX) +#define PIC_PCIE_LINK2_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK2_INDEX) +#define PIC_PCIE_LINK3_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK3_INDEX) +#define PIC_PCIE_B0_LINK2_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_B0_LINK2_INDEX) +#define PIC_PCIE_B0_LINK3_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_B0_LINK3_INDEX) +#define PIC_PCIE_INT_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_INT_INDEX) +#define PIC_PCIE_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_FATAL_INDEX) +#define PIC_GPIO_B_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_B_INDEX) +#define PIC_USB_IRQ (PIC_IRQ_BASE + PIC_IRT_USB_INDEX) +#define PIC_IRQ_IS_PICINTR(irq) ((irq) >= PIC_IRQ_BASE && \ + (irq) < PIC_IRQ_BASE + PIC_NUM_IRTS) +#define PIC_IS_EDGE_TRIGGERED(i) ((i) >= PIC_IRT_TIMER_INDEX(0) && \ + (i) <= PIC_IRT_TIMER_INDEX(7)) extern struct mtx xlr_pic_lock; - -static __inline__ __uint32_t -pic_read_control(int haslock) +static __inline uint32_t +pic_read_control(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - __uint32_t reg; + uint32_t reg; - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_lock_spin(&xlr_pic_lock); + mtx_lock_spin(&xlr_pic_lock); xlr_read_reg(mmio, PIC_CTRL); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_unlock_spin(&xlr_pic_lock); - return reg; + mtx_unlock_spin(&xlr_pic_lock); + return (reg); } -static __inline__ void -pic_write_control(__uint32_t control, int haslock) +static __inline void +pic_write_control(uint32_t control) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_lock_spin(&xlr_pic_lock); + mtx_lock_spin(&xlr_pic_lock); xlr_write_reg(mmio, PIC_CTRL, control); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_unlock_spin(&xlr_pic_lock); + mtx_unlock_spin(&xlr_pic_lock); } -static __inline__ void -pic_update_control(__uint32_t control, int haslock) + +static __inline void +pic_update_control(__uint32_t control) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_lock_spin(&xlr_pic_lock); + mtx_lock_spin(&xlr_pic_lock); xlr_write_reg(mmio, PIC_CTRL, (control | xlr_read_reg(mmio, PIC_CTRL))); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_unlock_spin(&xlr_pic_lock); + mtx_unlock_spin(&xlr_pic_lock); } -static __inline__ void -pic_ack(int irq, int haslock) +static __inline void +pic_ack(int picintr) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - /* ack the pic, if needed */ - if (!PIC_IRQ_IS_IRT(irq)) - return; - - if (PIC_IRQ_IS_EDGE_TRIGGERED(irq)) { - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_lock_spin(&xlr_pic_lock); - xlr_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_unlock_spin(&xlr_pic_lock); - return; - } - return; + xlr_write_reg(mmio, PIC_INT_ACK, 1U << picintr); } -static inline void -pic_delayed_ack(int irq, int haslock) +static __inline +void pic_send_ipi(int cpu, int ipi) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + int tid, pid; - if (!PIC_IRQ_IS_IRT(irq)) - return; - - if (!PIC_IRQ_IS_EDGE_TRIGGERED(irq)) { - if ((rmi_spin_mutex_safe)&& (haslock == 0)) - mtx_lock_spin(&xlr_pic_lock); - xlr_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE))); - if ((rmi_spin_mutex_safe) && (haslock == 0)) - mtx_unlock_spin(&xlr_pic_lock); - return; - } + tid = cpu & 0x3; + pid = (cpu >> 2) & 0x7; + xlr_write_reg(mmio, PIC_IPI, (pid << 20) | (tid << 16) | ipi); } -static inline -void pic_send_ipi(int cpu, int ipi, int haslock) +static __inline +void pic_setup_intr(int picintr, int irq, uint32_t cpumask, int level) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - int tid, pid; - tid = cpu & 0x3; - pid = (cpu >> 2) & 0x7; - - xlr_write_reg(mmio, PIC_IPI, (pid << 20) | (tid << 16) | ipi); + mtx_lock_spin(&xlr_pic_lock); + xlr_write_reg(mmio, PIC_IRT_0(picintr), cpumask); + xlr_write_reg(mmio, PIC_IRT_1(picintr), ((1 << 31) | (level << 30) | + (1 << 6) | irq)); + mtx_unlock_spin(&xlr_pic_lock); } -#endif /* _RMI_PIC_H_ */ +static __inline void +pic_init_timer(int timer) +{ + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + uint32_t val; + + mtx_lock_spin(&xlr_pic_lock); + val = xlr_read_reg(mmio, PIC_CTRL); + val |= (1 << (8 + timer)); + xlr_write_reg(mmio, PIC_CTRL, val); + mtx_unlock_spin(&xlr_pic_lock); +} + +static __inline void +pic_set_timer(int timer, uint64_t maxval) +{ + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + + xlr_write_reg(mmio, PIC_TIMER_MAXVAL_0(timer), + (maxval & 0xffffffff)); + xlr_write_reg(mmio, PIC_TIMER_MAXVAL_1(timer), + (maxval >> 32) & 0xffffffff); +} + +static __inline uint32_t +pic_timer_count32(int timer) + { + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + + return (xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer))); +} + +/* + * The timer can wrap 32 bits between the two reads, so we + * need additional logic to detect that. + */ +static __inline uint64_t +pic_timer_count(int timer) +{ + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + uint32_t tu1, tu2, tl; + + tu1 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer)); + tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer)); + tu2 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer)); + if (tu2 != tu1) + tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer)); + return (((uint64_t)tu2 << 32) | tl); +} + +#endif /* _RMI_PIC_H_ */ diff --git a/sys/mips/rmi/shared_structs.h b/sys/mips/rmi/rmi_boot_info.h similarity index 96% rename from sys/mips/rmi/shared_structs.h rename to sys/mips/rmi/rmi_boot_info.h index 6e5ecd43cea..38c81bd395d 100644 --- a/sys/mips/rmi/shared_structs.h +++ b/sys/mips/rmi/rmi_boot_info.h @@ -26,13 +26,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef _SHARED_STRUCTS_H #define _SHARED_STRUCTS_H -/* If you make any changes to the below structs, shared_structs_offsets.h - * should be regenerated - */ #define BOOT1_INFO_VERSION 0x0001 struct boot1_info { diff --git a/sys/mips/rmi/rmi_mips_exts.h b/sys/mips/rmi/rmi_mips_exts.h index 824381ac906..fb2f886767b 100644 --- a/sys/mips/rmi/rmi_mips_exts.h +++ b/sys/mips/rmi/rmi_mips_exts.h @@ -26,119 +26,554 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * RMI_BSD */ + * RMI_BSD + * $FreeBSD$ + */ #ifndef __MIPS_EXTS_H__ -#define __MIPS_EXTS_H__ +#define __MIPS_EXTS_H__ -#define enable_KX(flags) __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noat\n" \ - ".set noreorder\n" \ - "mfc0 %0, $12\n\t" \ - "ori $1, %0, 0x81\n\t" \ - "xori $1, 1\n\t" \ - "mtc0 $1, $12\n" \ - ".set pop\n" \ - : "=r"(flags) ) +#define CPU_BLOCKID_IFU 0 +#define CPU_BLOCKID_ICU 1 +#define CPU_BLOCKID_IEU 2 +#define CPU_BLOCKID_LSU 3 +#define CPU_BLOCKID_MMU 4 +#define CPU_BLOCKID_PRF 5 -#define disable_KX(flags) __asm__ __volatile__ ( \ - ".set push\n" \ - "mtc0 %0, $12\n" \ - ".set pop\n" \ - : : "r"(flags) ) +#define LSU_CERRLOG_REGID 9 -#define CPU_BLOCKID_IFU 0 -#define CPU_BLOCKID_ICU 1 -#define CPU_BLOCKID_IEU 2 -#define CPU_BLOCKID_LSU 3 -#define CPU_BLOCKID_MMU 4 -#define CPU_BLOCKID_PRF 5 - -#define LSU_CERRLOG_REGID 9 - -static __inline__ unsigned int read_32bit_phnx_ctrl_reg(int block, int reg) +#if defined(__mips_n64) || defined(__mips_n32) +static __inline uint64_t +read_xlr_ctrl_register(int block, int reg) { - unsigned int __res; + uint64_t res; - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - "move $9, %1\n" - /* "mfcr\t$8, $9\n\t" */ - ".word 0x71280018\n" - "move %0, $8\n" - ".set\tpop" - : "=r" (__res) : "r"((block<<8)|reg) - : "$8", "$9" - ); - return __res; + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $9, %1\n\t" + ".word 0x71280018\n\t" /* mfcr $8, $9 */ + "move %0, $8\n\t" + ".set pop\n" + : "=r" (res) : "r"((block << 8) | reg) + : "$8", "$9" + ); + return (res); } -static __inline__ void write_32bit_phnx_ctrl_reg(int block, int reg, unsigned int value) +static __inline void +write_xlr_ctrl_register(int block, int reg, uint64_t value) { - __asm__ __volatile__( - ".set\tpush\n\t" - ".set\tnoreorder\n\t" - "move $8, %0\n" - "move $9, %1\n" - /* "mtcr\t$8, $9\n\t" */ - ".word 0x71280019\n" - ".set\tpop" - : - : "r" (value), "r"((block<<8)|reg) - : "$8", "$9" - ); + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + "move $8, %0\n" + "move $9, %1\n" + ".word 0x71280019\n" /* mtcr $8, $9 */ + ".set pop\n" + : + : "r" (value), "r" ((block << 8) | reg) + : "$8", "$9" + ); } -static __inline__ unsigned long long read_64bit_phnx_ctrl_reg(int block, int reg) +#else /* !(defined(__mips_n64) || defined(__mips_n32)) */ + +static __inline uint64_t +read_xlr_ctrl_register(int block, int reg) { - unsigned int high, low; - - __asm__ __volatile__( - ".set\tmips64\n\t" - "move $9, %2\n" - /* "mfcr $8, $9\n" */ - ".word 0x71280018\n" - "dsrl32 %0, $8, 0\n\t" - "dsll32 $8, $8, 0\n\t" - "dsrl32 %1, $8, 0\n\t" - ".set mips0" - : "=r" (high), "=r"(low) - : "r"((block<<8)|reg) - : "$8", "$9" - ); - - return ( (((unsigned long long)high)<<32) | low); + uint32_t high, low; + + __asm__ __volatile__( + ".set push\n\t" + ".set noreorder\n\t" + ".set mips64\n\t" + "move $9, %2\n" + ".word 0x71280018\n" /* "mfcr $8, $9\n" */ + "dsra32 %0, $8, 0\n\t" + "sll %1, $8, 0\n\t" + ".set pop" + : "=r" (high), "=r"(low) + : "r" ((block << 8) | reg) + : "$8", "$9"); + + return ( (((uint64_t)high) << 32) | low); } -static __inline__ void write_64bit_phnx_ctrl_reg(int block, int reg,unsigned long long value) +static __inline void +write_xlr_ctrl_register(int block, int reg, uint64_t value) { - __uint32_t low, high; + uint32_t low, high; high = value >> 32; low = value & 0xffffffff; __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set mips4\n\t" - /* Set up "rs" */ - "move $9, %0\n" + ".set push\n\t" + ".set noreorder\n\t" + ".set mips64\n\t" + "dsll32 $9, %0, 0\n\t" + "dsll32 $8, %1, 0\n\t" + "dsrl32 $8, $8, 0\n\t" + "or $8, $9, $8\n\t" + "move $9, %2\n\t" + ".word 0x71280019\n\t" /* mtcr $8, $9 */ + ".set pop\n" + : /* No outputs */ + : "r" (high), "r" (low), "r"((block << 8) | reg) + : "$8", "$9"); +} +#endif /* defined(__mips_n64) || defined(__mips_n32) */ - /* Store 64 bit value in "rt" */ - "dsll32 $10, %1, 0 \n\t" - "dsll32 $8, %2, 0 \n\t" - "dsrl32 $8, $8, 0 \n\t" - "or $10, $8, $8 \n\t" +/* + * 32 bit read write for c0 + */ +#define read_c0_register32(reg, sel) \ +({ \ + uint32_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) - ".word 0x71280019\n" /* mtcr $8, $9 */ +#define write_c0_register32(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); - ".set pop\n" +#define read_c2_register32(reg, sel) \ +({ \ + uint32_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mfc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) - : /* No outputs */ - : "r"((block<<8)|reg), "r" (high), "r" (low) - : "$8", "$9", "$10" - ); +#define write_c2_register32(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips32\n\t" \ + "mtc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); + +#if defined(__mips_n64) || defined(__mips_n32) +/* + * On 64 bit compilation, the operations are simple + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint64_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmfc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) + +#define write_c0_register64(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmtc0 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); + +#define read_c2_register64(reg, sel) \ +({ \ + uint64_t __rv; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmfc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : "=r" (__rv) : "i" (reg), "i" (sel) ); \ + __rv; \ + }) + +#define write_c2_register64(reg, sel, value) \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set mips64\n\t" \ + "dmtc2 %0, $%1, %2\n\t" \ + ".set pop\n" \ + : : "r" (value), "i" (reg), "i" (sel) ); + +#else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ + +/* + * 32 bit compilation, 64 bit values has to split + */ +#define read_c0_register64(reg, sel) \ +({ \ + uint32_t __high, __low; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dmfc0 $8, $%2, %3\n\t" \ + "dsra32 %0, $8, 0\n\t" \ + "sll %1, $8, 0\n\t" \ + ".set pop\n" \ + : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ + : "$8"); \ + ((uint64_t)__high << 32) | __low; \ +}) + +#define write_c0_register64(reg, sel, value) \ +do { \ + uint32_t __high = value >> 32; \ + uint32_t __low = value & 0xffffffff; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dsll32 $8, %1, 0\n\t" \ + "dsll32 $9, %0, 0\n\t" \ + "dsrl32 $8, $8, 0\n\t" \ + "or $8, $8, $9\n\t" \ + "dmtc0 $8, $%2, %3\n\t" \ + ".set pop" \ + :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + :"$8", "$9"); \ +} while(0) + +#define read_c2_register64(reg, sel) \ +({ \ + uint32_t __high, __low; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dmfc2 $8, $%2, %3\n\t" \ + "dsra32 %0, $8, 0\n\t" \ + "sll %1, $8, 0\n\t" \ + ".set pop\n" \ + : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ + : "$8"); \ + ((uint64_t)__high << 32) | __low; \ +}) + +#define write_c2_register64(reg, sel, value) \ +do { \ + uint32_t __high = value >> 32; \ + uint32_t __low = value & 0xffffffff; \ + __asm__ __volatile__( \ + ".set push\n\t" \ + ".set noreorder\n\t" \ + ".set mips64\n\t" \ + "dsll32 $8, %1, 0\n\t" \ + "dsll32 $9, %0, 0\n\t" \ + "dsrl32 $8, $8, 0\n\t" \ + "or $8, $8, $9\n\t" \ + "dmtc2 $8, $%2, %3\n\t" \ + ".set pop" \ + :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ + :"$8", "$9"); \ +} while(0) + +#endif /* defined(__mips_n64) || defined(__mips_n32) */ + +static __inline int +xlr_cpu_id(void) +{ + + return (read_c0_register32(15, 1) & 0x1f); } +static __inline int +xlr_core_id(void) +{ + + return (xlr_cpu_id() / 4); +} + +static __inline int +xlr_thr_id(void) +{ + + return (read_c0_register32(15, 1) & 0x3); +} + +/* Additional registers on the XLR */ +#define MIPS_COP_0_OSSCRATCH 22 +#define XLR_CACHELINE_SIZE 32 + +/* functions to write to and read from the extended + * cp0 registers. + * EIRR : Extended Interrupt Request Register + * cp0 register 9 sel 6 + * bits 0...7 are same as cause register 8...15 + * EIMR : Extended Interrupt Mask Register + * cp0 register 9 sel 7 + * bits 0...7 are same as status register 8...15 + */ +static __inline uint64_t +read_c0_eirr64(void) +{ + + return (read_c0_register64(9, 6)); +} + +static __inline void +write_c0_eirr64(uint64_t val) +{ + + write_c0_register64(9, 6, val); +} + +static __inline uint64_t +read_c0_eimr64(void) +{ + + return (read_c0_register64(9, 7)); +} + +static __inline void +write_c0_eimr64(uint64_t val) +{ + + write_c0_register64(9, 7, val); +} + +static __inline int +xlr_test_and_set(int *lock) +{ + int oldval = 0; + + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "move $9, %2\n" + "li $8, 1\n" + // "swapw $8, $9\n" + ".word 0x71280014\n" + "move %1, $8\n" + ".set pop\n" + : "+m"(*lock), "=r"(oldval) + : "r"((unsigned long)lock) + : "$8", "$9" + ); + + return (oldval == 0 ? 1 /* success */ : 0 /* failure */); +} + +static __inline uint32_t +xlr_mfcr(uint32_t reg) +{ + uint32_t val; + + __asm__ __volatile__( + "move $8, %1\n" + ".word 0x71090018\n" + "move %0, $9\n" + : "=r"(val) + : "r"(reg):"$8", "$9"); + + return val; +} + +static __inline void +xlr_mtcr(uint32_t reg, uint32_t val) +{ + __asm__ __volatile__( + "move $8, %1\n" + "move $9, %0\n" + ".word 0x71090019\n" + :: "r"(val), "r"(reg) + : "$8", "$9"); +} + +/* + * Atomic increment a unsigned int + */ +static __inline unsigned int +xlr_ldaddwu(unsigned int value, unsigned int *addr) +{ + __asm__ __volatile__( + ".set push\n" + ".set noreorder\n" + "move $8, %2\n" + "move $9, %3\n" + ".word 0x71280011\n" /* ldaddwu $8, $9 */ + "move %0, $8\n" + ".set pop\n" + : "=&r"(value), "+m"(*addr) + : "0"(value), "r" ((unsigned long)addr) + : "$8", "$9"); + + return (value); +} + +#if defined(__mips_n64) +static __inline uint32_t +xlr_paddr_lw(uint64_t paddr) +{ + + paddr |= 0x9800000000000000ULL; + return (*(uint32_t *)(uintptr_t)paddr); +} + +static __inline uint64_t +xlr_paddr_ld(uint64_t paddr) +{ + + paddr |= 0x9800000000000000ULL; + return (*(uint64_t *)(uintptr_t)paddr); +} + +#elif defined(__mips_n32) +static __inline uint32_t +xlr_paddr_lw(uint64_t paddr) +{ + uint32_t val; + + paddr |= 0x9800000000000000ULL; + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "lw %0, 0(%1) \n\t" + ".set pop \n" + : "=r"(val) + : "r"(paddr)); + + return (val); +} + +static __inline uint64_t +xlr_paddr_ld(uint64_t paddr) +{ + uint64_t val; + + paddr |= 0x9800000000000000ULL; + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "ld %0, 0(%1) \n\t" + ".set pop \n" + : "=r"(val) + : "r"(paddr)); + + return (val); +} + +#else /* o32 compilation */ +static __inline uint32_t +xlr_paddr_lw(uint64_t paddr) +{ + uint32_t addrh, addrl; + uint32_t val; + + addrh = 0x98000000 | (paddr >> 32); + addrl = paddr & 0xffffffff; + + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "dsll32 $8, %1, 0 \n\t" + "dsll32 $9, %2, 0 \n\t" /* get rid of the */ + "dsrl32 $9, $9, 0 \n\t" /* sign extend */ + "or $9, $8, $8 \n\t" + "lw %0, 0($9) \n\t" + ".set pop \n" + : "=r"(val) + : "r"(addrh), "r"(addrl) + : "$8", "$9"); + + return (val); +} + +static __inline uint64_t +xlr_paddr_ld(uint64_t paddr) +{ + uint32_t addrh, addrl; + uint32_t valh, vall; + + addrh = 0x98000000 | (paddr >> 32); + addrl = paddr & 0xffffffff; + + __asm__ __volatile__( + ".set push \n\t" + ".set mips64 \n\t" + "dsll32 %0, %2, 0 \n\t" + "dsll32 %1, %3, 0 \n\t" /* get rid of the */ + "dsrl32 %1, %1, 0 \n\t" /* sign extend */ + "or %0, %0, %1 \n\t" + "lw %1, 4(%0) \n\t" + "lw %0, 0(%0) \n\t" + ".set pop \n" + : "=&r"(valh), "=&r"(vall) + : "r"(addrh), "r"(addrl)); + + return (((uint64_t)valh << 32) | vall); +} +#endif + +/* + * XXX: Not really needed in n32 or n64, retain for now + */ +#if defined(__mips_n64) || defined(__mips_n32) +static __inline uint32_t +xlr_enable_kx(void) +{ + + return (0); +} + +static __inline void +xlr_restore_kx(uint32_t sr) +{ +} + +#else /* !defined(__mips_n64) && !defined(__mips_n32) */ +/* + * o32 compilation, we will disable interrupts and enable + * the KX bit so that we can use XKPHYS to access any 40bit + * physical address + */ +static __inline uint32_t +xlr_enable_kx(void) +{ + uint32_t sr = mips_rd_status(); + + mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); + return (sr); +} + +static __inline void +xlr_restore_kx(uint32_t sr) +{ + + mips_wr_status(sr); +} +#endif /* defined(__mips_n64) || defined(__mips_n32) */ + +/* + * XLR/XLS processors have maximum 8 cores, and maximum 4 threads + * per core + */ +#define XLR_MAX_CORES 8 +#define XLR_NTHREADS 4 + +/* + * FreeBSD can be started with few threads and cores turned off, + * so have a hardware thread id to FreeBSD cpuid mapping. + */ +extern int xlr_ncores; +extern int xlr_threads_per_core; +extern uint32_t xlr_hw_thread_mask; +extern int xlr_cpuid_to_hwtid[]; +extern int xlr_hwtid_to_cpuid[]; #endif diff --git a/sys/mips/rmi/shared_structs_func.h b/sys/mips/rmi/shared_structs_func.h deleted file mode 100644 index be964140835..00000000000 --- a/sys/mips/rmi/shared_structs_func.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - * - * RMI_BSD */ -/* DO NOT EDIT THIS FILE - * This file has been autogenerated by ./gen_struct_offsets - */ -#ifndef _SHARED_STRUCTS_FUNC_H -#define _SHARED_STRUCTS_FUNC_H - -/* struct boot1_info function prototypes */ -#define boot1_info_uart_print_func(info_ptr, ...) ((void (*)(const char *, ...))(unsigned long)(info_ptr->uart_print))( __VA_ARGS__ ) -#define boot1_info_led_output_func(info_ptr, ...) ((void (*)(int))(unsigned long)(info_ptr->led_output))( __VA_ARGS__ ) -#define boot1_info_init_func(info_ptr, ...) ((void (*)(void))(unsigned long)(info_ptr->init))( __VA_ARGS__ ) -#define boot1_info_exit_func(info_ptr, ...) ((void (*)(void))(unsigned long)(info_ptr->exit))( __VA_ARGS__ ) -#define boot1_info_warm_reset_func(info_ptr, ...) ((void (*)(void))(unsigned long)(info_ptr->warm_reset))( __VA_ARGS__ ) -#define boot1_info_wakeup_func(info_ptr, ...) ((int (*)(void *, void *, unsigned int))(unsigned long)(info_ptr->wakeup))( __VA_ARGS__ ) -#define boot1_info_master_reentry_fn_func(info_ptr, ...) ((void (*)(void *))(unsigned long)(info_ptr->master_reentry_fn))( __VA_ARGS__ ) -#define boot1_info_slave_reentry_fn_func(info_ptr, ...) ((void (*)(void *))(unsigned long)(info_ptr->slave_reentry_fn))( __VA_ARGS__ ) -#define boot1_info_uart_putchar_func(info_ptr, ...) ((void (*)(char))(unsigned long)(info_ptr->uart_putchar))( __VA_ARGS__ ) -#define boot1_info_uart_getchar_func(info_ptr, ...) ((char (*)(void))(unsigned long)(info_ptr->uart_getchar))( __VA_ARGS__ ) -#define boot1_info_malloc_func(info_ptr, ...) ((void *(*)(size_t))(unsigned long)(info_ptr->malloc))( __VA_ARGS__ ) -#define boot1_info_free_func(info_ptr, ...) ((void (*)(void *))(unsigned long)(info_ptr->free))( __VA_ARGS__ ) -#define boot1_info_alloc_pbuf_func(info_ptr, ...) ((struct packet *(*)(void))(unsigned long)(info_ptr->alloc_pbuf))( __VA_ARGS__ ) -#define boot1_info_free_pbuf_func(info_ptr, ...) ((void (*)(struct packet *))(unsigned long)(info_ptr->free_pbuf))( __VA_ARGS__ ) -#define boot1_info_wakeup_os_func(info_ptr, ...) ((int (*)(void *, void *, unsigned int))(unsigned long)(info_ptr->wakeup_os))( __VA_ARGS__ ) - - -#endif diff --git a/sys/mips/rmi/shared_structs_offsets.h b/sys/mips/rmi/shared_structs_offsets.h deleted file mode 100644 index 605c735356c..00000000000 --- a/sys/mips/rmi/shared_structs_offsets.h +++ /dev/null @@ -1,76 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - * - * RMI_BSD */ -/* DO NOT EDIT THIS FILE - * This file has been autogenerated by ./gen_struct_offsets - */ -#ifndef _SHARED_STRUCTS_OFFSETS_H -#define _SHARED_STRUCTS_OFFSETS_H - -/* struct boot1_info offsets */ -#define boot1_info_boot_level_off 0 -#define boot1_info_io_base_off 8 -#define boot1_info_output_device_off 16 -#define boot1_info_uart_print_off 24 -#define boot1_info_led_output_off 32 -#define boot1_info_init_off 40 -#define boot1_info_exit_off 48 -#define boot1_info_warm_reset_off 56 -#define boot1_info_wakeup_off 64 -#define boot1_info_cpu_online_map_off 72 -#define boot1_info_master_reentry_sp_off 80 -#define boot1_info_master_reentry_gp_off 88 -#define boot1_info_master_reentry_fn_off 96 -#define boot1_info_slave_reentry_fn_off 104 -#define boot1_info_magic_dword_off 112 -#define boot1_info_uart_putchar_off 120 -#define boot1_info_size_off 128 -#define boot1_info_uart_getchar_off 136 -#define boot1_info_nmi_handler_off 144 -#define boot1_info_psb_version_off 152 -#define boot1_info_mac_addr_off 160 -#define boot1_info_cpu_frequency_off 168 -#define boot1_info_board_version_off 176 -#define boot1_info_malloc_off 184 -#define boot1_info_free_off 192 -#define boot1_info_alloc_pbuf_off 200 -#define boot1_info_free_pbuf_off 208 -#define boot1_info_psb_os_cpu_map_off 216 -#define boot1_info_userapp_cpu_map_off 224 -#define boot1_info_wakeup_os_off 232 -#define boot1_info_psb_mem_map_off 240 - -/* struct boot1_info size */ -#define boot1_info_size 248 - -/* boot1_info version */ -#define boot1_info_version 1 - - -#endif diff --git a/sys/mips/rmi/tick.c b/sys/mips/rmi/tick.c index 7520caca3b7..3b83a5c78d6 100644 --- a/sys/mips/rmi/tick.c +++ b/sys/mips/rmi/tick.c @@ -62,8 +62,8 @@ struct timecounter *platform_timecounter; static DPCPU_DEFINE(uint32_t, cycles_per_tick); static uint32_t cycles_per_usec; -static DPCPU_DEFINE(uint32_t, counter_upper); -static DPCPU_DEFINE(uint32_t, counter_lower_last); +static DPCPU_DEFINE(volatile uint32_t, counter_upper); +static DPCPU_DEFINE(volatile uint32_t, counter_lower_last); static DPCPU_DEFINE(uint32_t, compare_ticks); static DPCPU_DEFINE(uint32_t, lost_ticks); @@ -108,23 +108,32 @@ tick_ticker(void) uint32_t t_lower_last, t_upper; /* - * XXX: MIPS64 platforms can read 64-bits of counter directly. - * Also: the tc code is supposed to cope with things wrapping - * from the time counter, so I'm not sure why all these hoops - * are even necessary. + * Disable preemption because we are working with cpu specific data. */ - ticktock = mips_rd_count(); critical_enter(); - t_lower_last = DPCPU_GET(counter_lower_last); - t_upper = DPCPU_GET(counter_upper); - if (ticktock < t_lower_last) - t_upper++; - t_lower_last = ticktock; - DPCPU_SET(counter_upper, t_upper); - DPCPU_SET(counter_lower_last, t_lower_last); + + /* + * Note that even though preemption is disabled, interrupts are + * still enabled. In particular there is a race with clock_intr() + * reading the values of 'counter_upper' and 'counter_lower_last'. + * + * XXX this depends on clock_intr() being executed periodically + * so that 'counter_upper' and 'counter_lower_last' are not stale. + */ + do { + t_upper = DPCPU_GET(counter_upper); + t_lower_last = DPCPU_GET(counter_lower_last); + } while (t_upper != DPCPU_GET(counter_upper)); + + ticktock = mips_rd_count(); + critical_exit(); - ret = ((uint64_t)t_upper << 32) | t_lower_last; + /* COUNT register wrapped around */ + if (ticktock < t_lower_last) + t_upper++; + + ret = ((uint64_t)t_upper << 32) | ticktock; return (ret); } @@ -268,11 +277,11 @@ clock_intr(void *arg) } else /* In one-shot mode timer should be stopped after the event. */ mips_wr_compare(0xffffffff); - critical_enter(); + /* COUNT register wrapped around */ if (count < DPCPU_GET(counter_lower_last)) { DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); - DPCPU_SET(counter_lower_last, count); } + DPCPU_SET(counter_lower_last, count); if (cycles_per_tick > 0) { @@ -302,7 +311,6 @@ clock_intr(void *arg) } if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); - critical_exit(); return (FILTER_HANDLED); } diff --git a/sys/mips/rmi/xlr_machdep.c b/sys/mips/rmi/xlr_machdep.c index 0e2401e84d8..8f9663375e8 100644 --- a/sys/mips/rmi/xlr_machdep.c +++ b/sys/mips/rmi/xlr_machdep.c @@ -66,14 +66,14 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include -#include #include -#include #include #include +#include +#include +#include void mpwait(void); unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE); @@ -82,11 +82,12 @@ unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE); the dynamic kenv is setup */ char boot1_env[4096]; int rmi_spin_mutex_safe=0; +struct mtx xlr_pic_lock; + /* * Parameters from boot loader */ struct boot1_info xlr_boot1_info; -struct xlr_loader_info xlr_loader_info; /* FIXME : Unused */ int xlr_run_mode; int xlr_argc; int32_t *xlr_argv, *xlr_envp; @@ -104,7 +105,7 @@ int xlr_hwtid_to_cpuid[MAXCPU]; static void xlr_setup_mmu_split(void) { - int mmu_setup; + uint64_t mmu_setup; int val = 0; if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0) @@ -119,7 +120,7 @@ xlr_setup_mmu_split(void) val = 3; break; } - mmu_setup = read_32bit_phnx_ctrl_reg(4, 0); + mmu_setup = read_xlr_ctrl_register(4, 0); mmu_setup = mmu_setup & ~0x06; mmu_setup |= (val << 1); @@ -127,7 +128,7 @@ xlr_setup_mmu_split(void) if (xlr_shtlb_enabled) mmu_setup |= 0x01; - write_32bit_phnx_ctrl_reg(4, 0, mmu_setup); + write_xlr_ctrl_register(4, 0, mmu_setup); } static void @@ -166,6 +167,14 @@ xlr_parse_mmu_options(void) */ xlr_ncores = 1; cpu_map = xlr_boot1_info.cpu_online_map; + +#ifndef SMP /* Uniprocessor! */ + if (cpu_map != 0x1) { + printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n" + "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map); + cpu_map = 0x1; + } +#endif core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: @@ -187,9 +196,9 @@ xlr_parse_mmu_options(void) xlr_ncores++; } } + xlr_hw_thread_mask = cpu_map; /* setup hardware processor id to cpu id mapping */ - xlr_hw_thread_mask = xlr_boot1_info.cpu_online_map; for (i = 0; i< MAXCPU; i++) xlr_cpuid_to_hwtid[i] = xlr_hwtid_to_cpuid [i] = -1; @@ -264,8 +273,8 @@ mips_init(void) init_param1(); init_param2(physmem); - /* XXX: Catch 22. Something touches the tlb. */ mips_cpu_init(); + cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); #ifdef DDB kdb_init(); @@ -277,20 +286,131 @@ mips_init(void) mutex_init(); } +u_int +platform_get_timecount(struct timecounter *tc __unused) +{ + + return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER)); +} + +static void +xlr_pic_init(void) +{ + struct timecounter pic_timecounter = { + platform_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + ~0U, /* counter_mask */ + PIC_TIMER_HZ, /* frequency */ + "XLRPIC", /* name */ + 2000, /* quality (adjusted in code) */ + }; + xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); + int i, irq; + + write_c0_eimr64(0ULL); + mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN); + xlr_write_reg(mmio, PIC_CTRL, 0); + + /* Initialize all IRT entries */ + for (i = 0; i < PIC_NUM_IRTS; i++) { + irq = PIC_INTR_TO_IRQ(i); + + /* + * Disable all IRTs. Set defaults (local scheduling, high + * polarity, level * triggered, and CPU irq) + */ + xlr_write_reg(mmio, PIC_IRT_1(i), (1 << 30) | (1 << 6) | irq); + /* Bind all PIC irqs to cpu 0 */ + xlr_write_reg(mmio, PIC_IRT_0(i), 0x01); + } + + /* Setup timer 7 of PIC as a timestamp, no interrupts */ + pic_init_timer(PIC_CLOCK_TIMER); + pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0)); + platform_timecounter = &pic_timecounter; +} + +static void +xlr_mem_init(void) +{ + struct xlr_boot1_mem_map *boot_map; + vm_size_t physsz = 0; + int i, j; + + /* get physical memory info from boot loader */ + boot_map = (struct xlr_boot1_mem_map *) + (unsigned long)xlr_boot1_info.psb_mem_map; + for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) { + if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) { + if (j == 14) { + printf("*** ERROR *** memory map too large ***\n"); + break; + } + if (j == 0) { + /* TODO FIXME */ + /* start after kernel end */ + phys_avail[0] = (vm_paddr_t) + MIPS_KSEG0_TO_PHYS(&_end) + 0x20000; + /* boot loader start */ + /* HACK to Use bootloaders memory region */ + /* TODO FIXME */ + if (boot_map->physmem_map[0].size == 0x0c000000) { + boot_map->physmem_map[0].size = 0x0ff00000; + } + phys_avail[1] = boot_map->physmem_map[0].addr + + boot_map->physmem_map[0].size; + printf("First segment: addr:%p -> %p \n", + (void *)phys_avail[0], + (void *)phys_avail[1]); + + } else { +/* + * Can't use this code yet, because most of the fixed allocations happen from + * the biggest physical area. If we have more than 512M memory the kernel will try + * to map from the second are which is not in KSEG0 and not mapped + */ + phys_avail[j] = (vm_paddr_t) + boot_map->physmem_map[i].addr; + phys_avail[j + 1] = phys_avail[j] + + boot_map->physmem_map[i].size; + if (phys_avail[j + 1] < phys_avail[j] ) { + /* Houston we have an issue. Memory is + * larger than possible. Its probably in + * 64 bit > 4Gig and we are in 32 bit mode. + */ + phys_avail[j + 1] = 0xfffff000; + printf("boot map size was %jx\n", + (intmax_t)boot_map->physmem_map[i].size); + boot_map->physmem_map[i].size = phys_avail[j + 1] + - phys_avail[j]; + printf("reduced to %jx\n", + (intmax_t)boot_map->physmem_map[i].size); + } + printf("Next segment : addr:%p -> %p \n", + (void *)phys_avail[j], + (void *)phys_avail[j+1]); + } + physsz += boot_map->physmem_map[i].size; + } + } + + /* FIXME XLR TODO */ + phys_avail[j] = phys_avail[j + 1] = 0; + realmem = physmem = btoc(physsz); +} + void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { - vm_size_t physsz = 0; - int i, j; - struct xlr_boot1_mem_map *boot_map; + int i; #ifdef SMP uint32_t tmp; void (*wakeup) (void *, void *, unsigned int); - #endif + /* XXX FIXME the code below is not 64 bit clean */ /* Save boot loader and other stuff from scratch regs */ xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0); @@ -345,64 +465,7 @@ platform_start(__register_t a0 __unused, xlr_set_boot_flags(); xlr_parse_mmu_options(); - /* get physical memory info from boot loader */ - boot_map = (struct xlr_boot1_mem_map *) - (unsigned long)xlr_boot1_info.psb_mem_map; - for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) { - if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) { - if (j == 14) { - printf("*** ERROR *** memory map too large ***\n"); - break; - } - if (j == 0) { - /* TODO FIXME */ - /* start after kernel end */ - phys_avail[0] = (vm_paddr_t) - MIPS_KSEG0_TO_PHYS(&_end) + 0x20000; - /* boot loader start */ - /* HACK to Use bootloaders memory region */ - /* TODO FIXME */ - if (boot_map->physmem_map[0].size == 0x0c000000) { - boot_map->physmem_map[0].size = 0x0ff00000; - } - phys_avail[1] = boot_map->physmem_map[0].addr + - boot_map->physmem_map[0].size; - printf("First segment: addr:%p -> %p \n", - (void *)phys_avail[0], - (void *)phys_avail[1]); - - } else { -/* - * Can't use this code yet, because most of the fixed allocations happen from - * the biggest physical area. If we have more than 512M memory the kernel will try - * to map from the second are which is not in KSEG0 and not mapped - */ - phys_avail[j] = (vm_paddr_t) - boot_map->physmem_map[i].addr; - phys_avail[j + 1] = phys_avail[j] + - boot_map->physmem_map[i].size; - if (phys_avail[j + 1] < phys_avail[j] ) { - /* Houston we have an issue. Memory is - * larger than possible. Its probably in - * 64 bit > 4Gig and we are in 32 bit mode. - */ - phys_avail[j + 1] = 0xfffff000; - printf("boot map size was %jx\n", (intmax_t)boot_map->physmem_map[i].size); - boot_map->physmem_map[i].size = phys_avail[j + 1] - phys_avail[j]; - printf("reduced to %jx\n", (intmax_t)boot_map->physmem_map[i].size); - } - printf("Next segment : addr:%p -> %p \n", - (void *)phys_avail[j], - (void *)phys_avail[j+1]); - } - physsz += boot_map->physmem_map[i].size; - } - } - - /* FIXME XLR TODO */ - phys_avail[j] = phys_avail[j + 1] = 0; - realmem = physmem = btoc(physsz); - + xlr_mem_init(); /* Set up hz, among others. */ mips_init(); @@ -436,14 +499,14 @@ platform_start(__register_t a0 __unused, #endif /* xlr specific post initialization */ - /* - * The expectation is that mutex_init() is already done in - * mips_init() XXX NOTE: We may need to move this to SMP based init - * code for each CPU, later. - */ - rmi_spin_mutex_safe = 1; - on_chip_init(); + /* initialize other on chip stuff */ + xlr_board_info_setup(); + xlr_msgring_config(); + xlr_pic_init(); + xlr_msgring_cpu_init(); + mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0); + printf("Platform specific startup now completes\n"); } @@ -455,6 +518,7 @@ platform_cpu_init() void platform_identify(void) { + printf("Board [%d:%d], processor 0x%08x\n", (int)xlr_boot1_info.board_major_version, (int)xlr_boot1_info.board_minor_version, mips_rd_prid()); } @@ -517,11 +581,12 @@ platform_init_ap(int cpuid) stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT; mips_wr_status(stat); - xlr_unmask_hard_irq((void *)IRQ_IPI); - xlr_unmask_hard_irq((void *)IRQ_TIMER); + write_c0_eimr64(0ULL); + xlr_enable_irq(IRQ_IPI); + xlr_enable_irq(IRQ_TIMER); if (xlr_thr_id() == 0) { xlr_msgring_cpu_init(); - xlr_unmask_hard_irq((void *)IRQ_MSGRING); + xlr_enable_irq(IRQ_MSGRING); } return; @@ -530,14 +595,15 @@ platform_init_ap(int cpuid) int platform_ipi_intrnum(void) { + return (IRQ_IPI); } void platform_ipi_send(int cpuid) { - pic_send_ipi(xlr_cpuid_to_hwtid[cpuid], - platform_ipi_intrnum(), 0); + + pic_send_ipi(xlr_cpuid_to_hwtid[cpuid], platform_ipi_intrnum()); } void @@ -548,18 +614,21 @@ platform_ipi_clear(void) int platform_processor_id(void) { + return (xlr_hwtid_to_cpuid[xlr_cpu_id()]); } int platform_num_processors(void) { + return (xlr_ncores * xlr_threads_per_core); } struct cpu_group * platform_smp_topo() { + return (smp_topo_2level(CG_SHARE_L2, xlr_ncores, CG_SHARE_L1, xlr_threads_per_core, CG_FLAG_THREAD)); } diff --git a/sys/mips/rmi/xlr_pci.c b/sys/mips/rmi/xlr_pci.c index d70979b80bf..3204691bec4 100644 --- a/sys/mips/rmi/xlr_pci.c +++ b/sys/mips/rmi/xlr_pci.c @@ -38,23 +38,24 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include -#include -#include -#include +#include + #include #include #include -#include #include #include +#include +#include +#include +#include + +#include +#include #include #include -#include #include #include @@ -112,7 +113,7 @@ __FBSDID("$FreeBSD$"); #endif struct xlr_pcib_softc { - int junk; /* no softc */ + bus_dma_tag_t sc_pci_dmat; /* PCI DMA tag pointer */ }; static devclass_t pcib_devclass; @@ -122,6 +123,7 @@ static struct rman irq_rman, port_rman, mem_rman; static void xlr_pci_init_resources(void) { + irq_rman.rm_start = 0; irq_rman.rm_end = 255; irq_rman.rm_type = RMAN_ARRAY; @@ -150,6 +152,7 @@ xlr_pci_init_resources(void) static int xlr_pcib_probe(device_t dev) { + if (xlr_board_info.is_xls) device_set_desc(dev, "XLS PCIe bus"); else @@ -158,12 +161,13 @@ xlr_pcib_probe(device_t dev) xlr_pci_init_resources(); xlr_pci_config_base = (void *)MIPS_PHYS_TO_KSEG1(DEFAULT_PCI_CONFIG_BASE); - return 0; + return (0); } static int xlr_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { + switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; @@ -190,18 +194,20 @@ xlr_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) static int xlr_pcib_maxslots(device_t dev) { + return (PCI_SLOTMAX); } static __inline__ void disable_and_clear_cache_error(void) { - uint64_t lsu_cfg0 = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID); + uint64_t lsu_cfg0; + lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID); lsu_cfg0 = lsu_cfg0 & ~0x2e; - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); /* Clear cache error log */ - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); } static __inline__ void @@ -210,13 +216,13 @@ clear_and_enable_cache_error(void) uint64_t lsu_cfg0 = 0; /* first clear the cache error logging register */ - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERROVF_REGID, 0); - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRINT_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERROVF_REGID, 0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CERRINT_REGID, 0); - lsu_cfg0 = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID); + lsu_cfg0 = read_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID); lsu_cfg0 = lsu_cfg0 | 0x2e; - write_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); + write_xlr_ctrl_register(CPU_BLOCKID_LSU, LSU_CFG0_REGID, lsu_cfg0); } static uint32_t @@ -227,17 +233,17 @@ pci_cfg_read_32bit(uint32_t addr) uint64_t cerr_cpu_log = 0; disable_and_clear_cache_error(); - temp = bswap32(*p); /* Read cache err log */ - cerr_cpu_log = read_64bit_phnx_ctrl_reg(CPU_BLOCKID_LSU, LSU_CERRLOG_REGID); + cerr_cpu_log = read_xlr_ctrl_register(CPU_BLOCKID_LSU, + LSU_CERRLOG_REGID); if (cerr_cpu_log) { /* Device don't exist. */ temp = ~0x0; } clear_and_enable_cache_error(); - return temp; + return (temp); } static u_int32_t @@ -258,7 +264,7 @@ xlr_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, else if (width == 2) return ((data >> ((reg & 3) << 3)) & 0xffff); else - return data; + return (data); } static void @@ -294,154 +300,174 @@ xlr_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, static int xlr_pcib_attach(device_t dev) { + struct xlr_pcib_softc *sc; + sc = device_get_softc(dev); + + /* + * XLR C revision chips cannot do DMA above 2G physical address + * create a parent tag with this lowaddr + */ + if (xlr_is_c_revision()) { + if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, + 0x7fffffff, ~0, NULL, NULL, 0x7fffffff, + 0xff, 0x7fffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + panic("%s: bus_dma_tag_create failed", __func__); + } device_add_child(dev, "pci", 0); bus_generic_attach(dev); - return 0; + return (0); } static void xlr_pcib_identify(driver_t * driver, device_t parent) { - if (xlr_board_info.is_xls) { - xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET); - xlr_reg_t reg_link0 = xlr_read_reg(pcie_mmio_le, (0x80 >> 2)); - xlr_reg_t reg_link1 = xlr_read_reg(pcie_mmio_le, (0x84 >> 2)); - - if ((uint16_t) reg_link0 & PCIE_LINK_STATE) { - device_printf(parent, "Link 0 up\n"); - } - if ((uint16_t) reg_link1 & PCIE_LINK_STATE) { - device_printf(parent, "Link 1 up\n"); - } - } BUS_ADD_CHILD(parent, 0, "pcib", 0); } +/* + * XLS PCIe can have upto 4 links, and each link has its on IRQ + * Find the link on which the device is on + */ static int -xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) +xls_pcie_link(device_t pcib, device_t dev) { - int pciirq; - int i; device_t parent, tmp; - /* find the lane on which the slot is connected to */ + printf("xls_pcie_link : bus %s dev %s\n", device_get_nameunit(pcib), + device_get_nameunit(dev)); tmp = dev; while (1) { parent = device_get_parent(tmp); if (parent == NULL || parent == pcib) { device_printf(dev, "Cannot find parent bus\n"); - return ENXIO; + return (-1); } if (strcmp(device_get_nameunit(parent), "pci0") == 0) break; tmp = parent; } + return (pci_get_slot(tmp)); +} - switch (pci_get_slot(tmp)) { +/* + * Find the IRQ for the link, each link has a different interrupt + * at the XLS pic + */ +static int +xls_pcie_link_irq(int link) +{ + + switch (link) { case 0: - pciirq = PIC_PCIE_LINK0_IRQ; - break; + return (PIC_PCIE_LINK0_IRQ); case 1: - pciirq = PIC_PCIE_LINK1_IRQ; - break; + return (PIC_PCIE_LINK1_IRQ); case 2: - pciirq = PIC_PCIE_LINK2_IRQ; - break; + if (xlr_is_xls_b0()) + return (PIC_PCIE_B0_LINK2_IRQ); + else + return (PIC_PCIE_LINK2_IRQ); case 3: - pciirq = PIC_PCIE_LINK3_IRQ; - break; - default: - return ENXIO; + if (xlr_is_xls_b0()) + return (PIC_PCIE_B0_LINK3_IRQ); + else + return (PIC_PCIE_LINK3_IRQ); } + return (-1); +} + +static int +xlr_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) +{ + int i, link; - irqs[0] = pciirq; /* - * For now put in some fixed values for the other requested MSI, - * TODO handle multiple messages + * Each link has 32 MSIs that can be allocated, but for now + * we only support one device per link. + * msi_alloc() equivalent is needed when we start supporting + * bridges on the PCIe link. */ - for (i = 1; i < count; i++) - irqs[i] = pciirq + 64 * i; + link = xls_pcie_link(pcib, dev); + if (link == -1) + return (ENXIO); - return 0; + /* + * encode the irq so that we know it is a MSI interrupt when we + * setup interrupts + */ + for (i = 0; i < count; i++) + irqs[i] = 64 + link * 32 + i; + + return (0); } static int xlr_release_msi(device_t pcib, device_t dev, int count, int *irqs) { - device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), count); - return 0; + device_printf(dev, "%s: msi release %d\n", device_get_nameunit(pcib), + count); + return (0); } static int -xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t * addr, uint32_t * data) +xlr_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, + uint32_t *data) { - switch (irq) { - case PIC_PCIE_LINK0_IRQ: - case PIC_PCIE_LINK1_IRQ: - case PIC_PCIE_LINK2_IRQ: - case PIC_PCIE_LINK3_IRQ: - *addr = MIPS_MSI_ADDR(0); - *data = MIPS_MSI_DATA(irq); - return 0; + int msi; - default: - device_printf(dev, "%s: map_msi for irq %d - ignored", device_get_nameunit(pcib), - irq); + if (irq >= 64) { + msi = irq - 64; + *addr = MIPS_MSI_ADDR(0); + *data = MIPS_MSI_DATA(msi); + return (0); + } else { + device_printf(dev, "%s: map_msi for irq %d - ignored", + device_get_nameunit(pcib), irq); return (ENXIO); } - } static void -bridge_pcix_ack(void *arg) +bridge_pcix_ack(int irq) { + xlr_read_reg(xlr_io_mmio(XLR_IO_PCIX_OFFSET), 0x140 >> 2); } static void -bridge_pcix_mask_ack(void *arg) +bridge_pcie_ack(int irq) { - xlr_mask_hard_irq(arg); - bridge_pcix_ack(arg); -} - -static void -bridge_pcie_ack(void *arg) -{ - int irq = (intptr_t)arg; uint32_t reg; xlr_reg_t *pcie_mmio_le = xlr_io_mmio(XLR_IO_PCIE_1_OFFSET); switch (irq) { - case PIC_PCIE_LINK0_IRQ : reg = PCIE_LINK0_MSI_STATUS; break; - case PIC_PCIE_LINK1_IRQ : reg = PCIE_LINK1_MSI_STATUS; break; - case PIC_PCIE_LINK2_IRQ : reg = PCIE_LINK2_MSI_STATUS; break; - case PIC_PCIE_LINK3_IRQ : reg = PCIE_LINK3_MSI_STATUS; break; + case PIC_PCIE_LINK0_IRQ: + reg = PCIE_LINK0_MSI_STATUS; + break; + case PIC_PCIE_LINK1_IRQ: + reg = PCIE_LINK1_MSI_STATUS; + break; + case PIC_PCIE_LINK2_IRQ: + case PIC_PCIE_B0_LINK2_IRQ: + reg = PCIE_LINK2_MSI_STATUS; + break; + case PIC_PCIE_LINK3_IRQ: + case PIC_PCIE_B0_LINK3_IRQ: + reg = PCIE_LINK3_MSI_STATUS; + break; default: return; } - xlr_write_reg(pcie_mmio_le, reg>>2, 0xffffffff); } -static void -bridge_pcie_mask_ack(void *arg) -{ - xlr_mask_hard_irq(arg); - bridge_pcie_ack(arg); -} - static int mips_platform_pci_setup_intr(device_t dev, device_t child, - struct resource *irq, int flags, - driver_filter_t * filt, - driver_intr_t * intr, void *arg, - void **cookiep) + struct resource *irq, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) { - int level; - xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); int error = 0; int xlrirq; @@ -451,43 +477,37 @@ mips_platform_pci_setup_intr(device_t dev, device_t child, if (rman_get_start(irq) != rman_get_end(irq)) { device_printf(dev, "Interrupt allocation %lu != %lu\n", rman_get_start(irq), rman_get_end(irq)); - return EINVAL; + return (EINVAL); } xlrirq = rman_get_start(irq); if (strcmp(device_get_name(dev), "pcib") != 0) - return 0; + return (0); if (xlr_board_info.is_xls == 0) { - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - level = PIC_IRQ_IS_EDGE_TRIGGERED(PIC_IRT_PCIX_INDEX); - xlr_write_reg(mmio, PIC_IRT_0_PCIX, 0x01); - xlr_write_reg(mmio, PIC_IRT_1_PCIX, ((1 << 31) | (level << 30) | - (1 << 6) | (PIC_PCIX_IRQ))); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - xlr_cpu_establish_hardintr(device_get_name(child), filt, - intr, arg, PIC_PCIX_IRQ, flags, cookiep, - bridge_pcix_mask_ack, xlr_unmask_hard_irq, - bridge_pcix_ack, NULL); + xlr_establish_intr(device_get_name(child), filt, + intr, arg, PIC_PCIX_IRQ, flags, cookiep, bridge_pcix_ack); + pic_setup_intr(PIC_IRT_PCIX_INDEX, PIC_PCIX_IRQ, 0x1, 1); } else { - if (rmi_spin_mutex_safe) - mtx_lock_spin(&xlr_pic_lock); - xlr_write_reg(mmio, PIC_IRT_0_BASE + xlrirq - PIC_IRQ_BASE, 0x01); - xlr_write_reg(mmio, PIC_IRT_1_BASE + xlrirq - PIC_IRQ_BASE, - ((1 << 31) | (1 << 30) | (1 << 6) | xlrirq)); - if (rmi_spin_mutex_safe) - mtx_unlock_spin(&xlr_pic_lock); - - xlr_cpu_establish_hardintr(device_get_name(child), filt, - intr, arg, xlrirq, flags, cookiep, - bridge_pcie_mask_ack, xlr_unmask_hard_irq, - bridge_pcie_ack, NULL); + /* + * temporary hack for MSI, we support just one device per + * link, and assign the link interrupt to the device interrupt + */ + if (xlrirq >= 64) { + xlrirq -= 64; + if (xlrirq % 32 != 0) + return (0); + xlrirq = xls_pcie_link_irq(xlrirq / 32); + if (xlrirq == -1) + return (EINVAL); + } + xlr_establish_intr(device_get_name(child), filt, + intr, arg, xlrirq, flags, cookiep, bridge_pcie_ack); + pic_setup_intr(xlrirq - PIC_IRQ_BASE, xlrirq, 0x1, 1); } - return bus_generic_setup_intr(dev, child, irq, flags, filt, intr, - arg, cookiep); + return (bus_generic_setup_intr(dev, child, irq, flags, filt, intr, + arg, cookiep)); } static int @@ -498,7 +518,7 @@ mips_platform_pci_teardown_intr(device_t dev, device_t child, /* if needed reprogram the pic to clear pcix related entry */ device_printf(dev, "teardown intr\n"); } - return bus_generic_teardown_intr(dev, child, irq, cookie); + return (bus_generic_teardown_intr(dev, child, irq, cookie)); } static struct resource * @@ -524,12 +544,12 @@ xlr_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, break; default: - return 0; + return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == 0) - return 0; + return (0); rman_set_rid(rv, *rid); @@ -547,20 +567,31 @@ xlr_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, return (NULL); } } - return rv; + return (rv); } static int xlr_pci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + return (rman_release_resource(r)); } +static bus_dma_tag_t +xlr_pci_get_dma_tag(device_t bus, device_t child) +{ + struct xlr_pcib_softc *sc; + + sc = device_get_softc(bus); + return (sc->sc_pci_dmat); +} + static int xlr_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + return (rman_activate_resource(r)); } @@ -568,12 +599,15 @@ static int xlr_pci_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { + return (rman_deactivate_resource(r)); } static int mips_pci_route_interrupt(device_t bus, device_t dev, int pin) { + int irq, link; + /* * Validate requested pin number. */ @@ -581,20 +615,13 @@ mips_pci_route_interrupt(device_t bus, device_t dev, int pin) return (255); if (xlr_board_info.is_xls) { - switch (pin) { - case 1: - return PIC_PCIE_LINK0_IRQ; - case 2: - return PIC_PCIE_LINK1_IRQ; - case 3: - return PIC_PCIE_LINK2_IRQ; - case 4: - return PIC_PCIE_LINK3_IRQ; - } + link = xls_pcie_link(bus, dev); + irq = xls_pcie_link_irq(link); + if (irq != -1) + return (irq); } else { - if (pin == 1) { - return (16); - } + if (pin == 1) + return (PIC_PCIX_IRQ); } return (255); @@ -612,6 +639,7 @@ static device_method_t xlr_pcib_methods[] = { DEVMETHOD(bus_write_ivar, xlr_pcib_write_ivar), DEVMETHOD(bus_alloc_resource, xlr_pci_alloc_resource), DEVMETHOD(bus_release_resource, xlr_pci_release_resource), + DEVMETHOD(bus_get_dma_tag, xlr_pci_get_dma_tag), DEVMETHOD(bus_activate_resource, xlr_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, xlr_pci_deactivate_resource), DEVMETHOD(bus_setup_intr, mips_platform_pci_setup_intr), diff --git a/sys/mips/rmi/xlr_pcmcia.c b/sys/mips/rmi/xlr_pcmcia.c new file mode 100644 index 00000000000..86322669c8b --- /dev/null +++ b/sys/mips/rmi/xlr_pcmcia.c @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2003-2009 RMI Corporation + * 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 RMI Corporation, 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 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. + * + * RMI_BSD */ +/* + * ATA driver for the XLR_PCMCIA Host adapter on the RMI XLR/XLS/. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define XLR_PCMCIA_DATA_REG 0x1f0 +#define XLR_PCMCIA_ERROR_REG 0x1f1 +#define XLR_PCMCIA_SECT_CNT_REG 0x1f2 +#define XLR_PCMCIA_SECT_NUM_REG 0x1f3 +#define XLR_PCMCIA_CYLINDER_LOW_REG 0x1f4 +#define XLR_PCMCIA_CYLINDER_HIGH_REG 0x1f5 +#define XLR_PCMCIA_SECT_DRIVE_HEAD_REG 0x1f6 +#define XLR_PCMCIA_CMD_STATUS_REG 0x1f7 +#define XLR_PCMCIA_ALT_STATUS_REG 0x3f6 +#define XLR_PCMCIA_CONTROL_REG 0x3f6 + +/* + * Device methods + */ +static int xlr_pcmcia_probe(device_t); +static int xlr_pcmcia_attach(device_t); +static int xlr_pcmcia_detach(device_t); + +static int +xlr_pcmcia_probe(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + + ch->unit = 0; + ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE ; + device_set_desc(dev, "PCMCIA ATA controller"); + + return (ata_probe(dev)); +} + +/* + * We add all the devices which we know about. + * The generic attach routine will attach them if they are alive. + */ +static int +xlr_pcmcia_attach(device_t dev) +{ + struct ata_channel *ch = device_get_softc(dev); + int i; + int rid =0; + struct resource *mem_res; + + + mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + for (i = 0; i < ATA_MAX_RES; i++) + ch->r_io[i].res = mem_res; + + /* + * CF+ Specification. + */ + ch->r_io[ATA_DATA].offset = XLR_PCMCIA_DATA_REG; + ch->r_io[ATA_FEATURE].offset = XLR_PCMCIA_ERROR_REG; + ch->r_io[ATA_COUNT].offset = XLR_PCMCIA_SECT_CNT_REG; + ch->r_io[ATA_SECTOR].offset = XLR_PCMCIA_SECT_NUM_REG; + ch->r_io[ATA_CYL_LSB].offset = XLR_PCMCIA_CYLINDER_LOW_REG; + ch->r_io[ATA_CYL_MSB].offset = XLR_PCMCIA_CYLINDER_HIGH_REG; + ch->r_io[ATA_DRIVE].offset = XLR_PCMCIA_SECT_DRIVE_HEAD_REG; + ch->r_io[ATA_COMMAND].offset = XLR_PCMCIA_CMD_STATUS_REG; + ch->r_io[ATA_ERROR].offset = XLR_PCMCIA_ERROR_REG; + ch->r_io[ATA_IREASON].offset = XLR_PCMCIA_SECT_CNT_REG; + ch->r_io[ATA_STATUS].offset = XLR_PCMCIA_CMD_STATUS_REG; + ch->r_io[ATA_ALTSTAT].offset = XLR_PCMCIA_ALT_STATUS_REG; + ch->r_io[ATA_CONTROL].offset = XLR_PCMCIA_CONTROL_REG; + + /* Should point at the base of registers. */ + ch->r_io[ATA_IDX_ADDR].offset = XLR_PCMCIA_DATA_REG; + + ata_generic_hw(dev); + + return (ata_attach(dev)); +} + +static int +xlr_pcmcia_detach(device_t dev) +{ + bus_generic_detach(dev); + + return (0); +} + +static device_method_t xlr_pcmcia_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, xlr_pcmcia_probe), + DEVMETHOD(device_attach, xlr_pcmcia_attach), + DEVMETHOD(device_detach, xlr_pcmcia_detach), + + { 0, 0 } +}; + +static driver_t xlr_pcmcia_driver = { + "ata", + xlr_pcmcia_methods, + sizeof(struct ata_channel), +}; + +DRIVER_MODULE(ata, iodi, xlr_pcmcia_driver, ata_devclass, 0, 0); diff --git a/sys/mips/rmi/xlrconfig.h b/sys/mips/rmi/xlrconfig.h deleted file mode 100644 index 1b22f7cc6db..00000000000 --- a/sys/mips/rmi/xlrconfig.h +++ /dev/null @@ -1,360 +0,0 @@ -/*- - * Copyright (c) 2003-2009 RMI Corporation - * 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 RMI Corporation, 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 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. - __FBSDID("$FreeBSD$"); - * - * RMI_BSD */ -#ifndef XLRCONFIG_H -#define XLRCONFIG_H - -#include -#include -#include - -#define read_c0_register32(reg, sel) \ -({ unsigned int __rv; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mfc0\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : "=r" (__rv) : "i" (reg), "i" (sel) ); \ - __rv;}) - -#define write_c0_register32(reg, sel, value) \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mtc0\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : : "r" (value), "i" (reg), "i" (sel) ); - -#define read_c0_register64(reg, sel) \ - ({ unsigned int __high, __low; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips64\n\t" \ - "dmfc0\t $8, $%2, %3\n\t" \ - "dsrl32\t%0, $8, 0\n\t" \ - "dsll32\t$8, $8, 0\n\t" \ - "dsrl32\t%1, $8, 0\n\t" \ - ".set\tpop" \ - : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel): "$8" );\ - (((unsigned long long)__high << 32) | __low);}) - -#define write_c0_register64(reg, sel, value) \ - do{ \ - unsigned int __high = val>>32; \ - unsigned int __low = val & 0xffffffff; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips64\n\t" \ - "dsll32\t$8, %1, 0\n\t" \ - "dsll32\t$9, %0, 0\n\t" \ - "or\t $8, $8, $9\n\t" \ - "dmtc0\t $8, $%2, %3\n\t" \ - ".set\tpop" \ - :: "r"(high), "r"(low), "i"(reg), "i"(sel):"$8", "$9");\ - } while(0) - -#define read_c2_register32(reg, sel) \ -({ unsigned int __rv; \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mfc2\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : "=r" (__rv) : "i" (reg), "i" (sel) ); \ - __rv;}) - -#define write_c2_register32(reg, sel, value) \ - __asm__ __volatile__( \ - ".set\tpush\n\t" \ - ".set mips32\n\t" \ - "mtc2\t%0,$%1,%2\n\t" \ - ".set\tpop" \ - : : "r" (value), "i" (reg), "i" (sel) ); - -#define read_c2_register64(reg, sel) \ - ({ unsigned int __high, __low; \ - __asm__ __volatile__( \ - ".set mips64\n\t" \ - "dmfc2\t $8, $%2, %3\n\t" \ - "dsrl32\t%0, $8, 0\n\t" \ - "dsll32\t$8, $8, 0\n\t" \ - "dsrl32\t%1, $8, 0\n\t" \ - ".set\tmips0" \ - : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel): "$8" );\ - (((unsigned long long)__high << 32) | __low);}) - -#define write_c2_register64(reg, sel, value) \ - do{ \ - unsigned int __high = value>>32; \ - unsigned int __low = value & 0xffffffff; \ - __asm__ __volatile__( \ - ".set mips64\n\t" \ - "dsll32\t$8, %1, 0\n\t" \ - "dsll32\t$9, %0, 0\n\t" \ - "dsrl32\t$8, $8, 0\n\t" \ - "or\t $8, $8, $9\n\t" \ - "dmtc2\t $8, $%2, %3\n\t" \ - ".set\tmips0" \ - :: "r"(__high), "r"(__low), \ - "i"(reg), "i"(sel) \ - :"$8", "$9"); \ - } while(0) - -#define xlr_cpu_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x1f\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id;}) - -#define xlr_core_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x1f\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id/4;}) - -#define xlr_thr_id() \ -({int __id; \ - __asm__ __volatile__ ( \ - ".set push\n" \ - ".set noreorder\n" \ - "mfc0 $8, $15, 1\n" \ - "andi %0, $8, 0x3\n" \ - ".set pop\n" \ - : "=r" (__id) : : "$8"); \ - __id;}) - - -/* Additional registers on the XLR */ -#define MIPS_COP_0_OSSCRATCH 22 - -#define XLR_CACHELINE_SIZE 32 - -#define XLR_MAX_CORES 8 - -/* functions to write to and read from the extended - * cp0 registers. - * EIRR : Extended Interrupt Request Register - * cp0 register 9 sel 6 - * bits 0...7 are same as cause register 8...15 - * EIMR : Extended Interrupt Mask Register - * cp0 register 9 sel 7 - * bits 0...7 are same as status register 8...15 - */ - -static inline uint64_t -read_c0_eirr64(void) -{ - __uint32_t high, low; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n" - - ".word 0x40214806 \n\t" - "nop \n\t" - "dsra32 %0, $1, 0 \n\t" - "sll %1, $1, 0 \n\t" - - ".set pop\n" - - : "=r"(high), "=r"(low) - ); - - return (((__uint64_t) high) << 32) | low; -} - -static inline __uint64_t -read_c0_eimr64(void) -{ - __uint32_t high, low; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n" - - ".word 0x40214807 \n\t" - "nop \n\t" - "dsra32 %0, $1, 0 \n\t" - "sll %1, $1, 0 \n\t" - - ".set pop\n" - - : "=r"(high), "=r"(low) - ); - - return (((__uint64_t) high) << 32) | low; -} - -static inline void -write_c0_eirr64(__uint64_t value) -{ - __uint32_t low, high; - - high = value >> 32; - low = value & 0xffffffff; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n\t" - - "dsll32 $2, %1, 0 \n\t" - "dsll32 $1, %0, 0 \n\t" - "dsrl32 $2, $2, 0 \n\t" - "or $1, $1, $2 \n\t" - ".word 0x40a14806 \n\t" - "nop \n\t" - - ".set pop\n" - - : - : "r"(high), "r"(low) - : "$1", "$2"); -} - -static inline void -write_c0_eimr64(__uint64_t value) -{ - __uint32_t low, high; - - high = value >> 32; - low = value & 0xffffffff; - - __asm__ __volatile__( - ".set push\n" - ".set noreorder\n" - ".set noat\n" - ".set mips4\n\t" - - "dsll32 $2, %1, 0 \n\t" - "dsll32 $1, %0, 0 \n\t" - "dsrl32 $2, $2, 0 \n\t" - "or $1, $1, $2 \n\t" - ".word 0x40a14807 \n\t" - "nop \n\t" - - ".set pop\n" - - : - : "r"(high), "r"(low) - : "$1", "$2"); -} - -static __inline__ int -xlr_test_and_set(int *lock) -{ - int oldval = 0; - - __asm__ __volatile__(".set push\n" - ".set noreorder\n" - "move $9, %2\n" - "li $8, 1\n" - // "swapw $8, $9\n" - ".word 0x71280014\n" - "move %1, $8\n" - ".set pop\n" - : "+m"(*lock), "=r"(oldval) - : "r"((unsigned long)lock) - : "$8", "$9" - ); - - return (oldval == 0 ? 1 /* success */ : 0 /* failure */ ); -} - -static __inline__ uint32_t -xlr_mfcr(uint32_t reg) -{ - uint32_t val; - - __asm__ __volatile__( - "move $8, %1\n" - ".word 0x71090018\n" - "move %0, $9\n" - : "=r"(val) - : "r"(reg):"$8", "$9"); - - return val; -} - -static __inline__ void -xlr_mtcr(uint32_t reg, uint32_t val) -{ - __asm__ __volatile__( - "move $8, %1\n" - "move $9, %0\n" - ".word 0x71090019\n" - :: "r"(val), "r"(reg) - : "$8", "$9"); -} - -static __inline__ uint32_t -xlr_paddr_lw(uint64_t paddr) -{ - uint32_t high, low, tmp; - - high = 0x98000000 | (paddr >> 32); - low = paddr & 0xffffffff; - - __asm__ __volatile__( - ".set push \n\t" - ".set mips64 \n\t" - "dsll32 %1, %1, 0 \n\t" - "dsll32 %2, %2, 0 \n\t" /* get rid of the */ - "dsrl32 %2, %2, 0 \n\t" /* sign extend */ - "or %1, %1, %2 \n\t" - "lw %0, 0(%1) \n\t" - ".set pop \n" - : "=r"(tmp) - : "r"(high), "r"(low)); - - return tmp; -} - -/* for cpuid to hardware thread id mapping */ -extern uint32_t xlr_hw_thread_mask; -extern int xlr_cpuid_to_hwtid[]; -extern int xlr_hwtid_to_cpuid[]; -#endif diff --git a/sys/mips/sibyte/sb_machdep.c b/sys/mips/sibyte/sb_machdep.c index 45f39e8c99b..ba4b62e95a6 100644 --- a/sys/mips/sibyte/sb_machdep.c +++ b/sys/mips/sibyte/sb_machdep.c @@ -370,7 +370,7 @@ platform_init_ap(int cpuid) */ clock_int_mask = hard_int_mask(5); ipi_int_mask = hard_int_mask(platform_ipi_intrnum()); - set_intr_mask(MIPS_SR_INT_MASK & ~(ipi_int_mask | clock_int_mask)); + set_intr_mask(ipi_int_mask | clock_int_mask); } int diff --git a/sys/mips/sibyte/sb_zbbus.c b/sys/mips/sibyte/sb_zbbus.c index cd168564896..e166b8f2661 100644 --- a/sys/mips/sibyte/sb_zbbus.c +++ b/sys/mips/sibyte/sb_zbbus.c @@ -402,7 +402,7 @@ zbbus_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, } static device_t -zbbus_add_child(device_t bus, int order, const char *name, int unit) +zbbus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct zbbus_devinfo *dinfo; diff --git a/sys/mips/sibyte/sb_zbpci.c b/sys/mips/sibyte/sb_zbpci.c index 9a096451f0a..243ed08e7d7 100644 --- a/sys/mips/sibyte/sb_zbpci.c +++ b/sys/mips/sibyte/sb_zbpci.c @@ -349,7 +349,7 @@ zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes) pa_page = pa & ~(PAGE_SIZE - 1); if (zbpci_config_space[cpu].paddr != pa_page) { pmap_kremove(va_page); - pmap_kenter(va_page, pa_page); + pmap_kenter_attr(va_page, pa_page, PTE_C_UNCACHED); zbpci_config_space[cpu].paddr = pa_page; } return (va_page + (pa - pa_page)); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 8d8b394fcba..452cc8f907f 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -185,6 +185,7 @@ SUBDIR= ${_3dfx} \ ${_mly} \ mmc \ mmcsd \ + mps \ mpt \ mqueue \ msdosfs \ @@ -257,6 +258,7 @@ SUBDIR= ${_3dfx} \ ${_scsi_low} \ sdhci \ sem \ + send \ sf \ sge \ siba_bwn \ @@ -322,8 +324,8 @@ SUBDIR= ${_3dfx} \ ${_zfs} \ zlib \ -.if ${MACHINE_CPUARCH} != "powerpc" && ${MACHINE_ARCH} != "arm" && \ - ${MACHINE_ARCH} != "mips" +.if ${MACHINE_CPUARCH} != "powerpc" && ${MACHINE_CPUARCH} != "arm" && \ + ${MACHINE_CPUARCH} != "mips" _syscons= syscons _vpo= vpo .endif @@ -359,7 +361,7 @@ _pf= pf _pflog= pflog .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" # XXX some of these can move to the general case when de-i386'ed # XXX some of these can move now, but are untested on other architectures. _3dfx= 3dfx @@ -499,7 +501,7 @@ _snc= snc .endif .endif -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" _aac= aac _acpi= acpi .if ${MK_CRYPT} != "no" || defined(ALL_MODULES) @@ -589,7 +591,7 @@ _zfs= zfs .endif .endif -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" _aac= aac _aic= aic _an= an @@ -646,7 +648,7 @@ _zfs= zfs .endif .endif -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" _auxio= auxio _em= em _epic= epic diff --git a/sys/modules/aac/Makefile b/sys/modules/aac/Makefile index 6964defc820..5b6525f7dea 100644 --- a/sys/modules/aac/Makefile +++ b/sys/modules/aac/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../dev/aac -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SUBDIR= aac_linux .endif diff --git a/sys/modules/acpi/acpi/Makefile b/sys/modules/acpi/acpi/Makefile index e37b1d90a2c..c98e91f12ba 100644 --- a/sys/modules/acpi/acpi/Makefile +++ b/sys/modules/acpi/acpi/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" .error "ACPI can only be compiled into the kernel on the ia64 platform" .endif @@ -22,7 +22,7 @@ ${.CURDIR}/../../../pci \ ${.CURDIR}/../../../dev/acpica \ ${.CURDIR}/../../../dev/acpica/Osd \ - ${.CURDIR}/../../../${MACHINE_ARCH}/acpica + ${.CURDIR}/../../../${MACHINE_CPUARCH}/acpica KMOD= acpi @@ -39,7 +39,8 @@ SRCS+= exconfig.c exconvrt.c excreate.c exdebug.c exdump.c exfield.c SRCS+= exfldio.c exmisc.c exmutex.c exnames.c exoparg1.c exoparg2.c SRCS+= exoparg3.c exoparg6.c exprep.c exregion.c exresnte.c exresolv.c SRCS+= exresop.c exstore.c exstoren.c exstorob.c exsystem.c exutils.c -SRCS+= hwacpi.c hwgpe.c hwregs.c hwsleep.c hwtimer.c hwvalid.c hwxface.c +SRCS+= hwacpi.c hwgpe.c hwpci.c hwregs.c hwsleep.c hwtimer.c hwvalid.c +SRCS+= hwxface.c SRCS+= nsaccess.c nsalloc.c nsdump.c nseval.c nsinit.c nsload.c nsnames.c SRCS+= nsobject.c nsparse.c nspredef.c nsrepair.c nsrepair2.c nssearch.c SRCS+= nsutils.c nswalk.c nsxfeval.c nsxfname.c nsxfobj.c @@ -50,7 +51,7 @@ SRCS+= rsmemory.c rsmisc.c rsutils.c rsxface.c SRCS+= tbfadt.c tbfind.c tbinstal.c tbutils.c tbxface.c tbxfroot.c SRCS+= utalloc.c utcache.c utcopy.c utdebug.c utdelete.c uteval.c utglobal.c SRCS+= utids.c utinit.c utlock.c utmath.c utmisc.c utmutex.c utobject.c -SRCS+= utosi.c utresrc.c utstate.c utxface.c +SRCS+= utosi.c utresrc.c utstate.c utxface.c utxferror.c # OSPM layer and core hardware drivers SRCS+= acpi.c acpi_button.c acpi_isab.c acpi_package.c acpi_pci.c acpi_pcib.c @@ -98,29 +99,35 @@ SRCS+= acpi_machdep.c acpi_wakecode.h acpi_wakeup.c SRCS+= assym.s madt.c CLEANFILES+= acpi_wakecode.bin acpi_wakecode.h acpi_wakecode.o -.if ${MACHINE_ARCH} == "amd64" +SRCS+= opt_global.h + +.if ${MACHINE_CPUARCH} == "amd64" .if !defined(KERNBUILDDIR) CFLAGS+=-DSMP .endif SRCS+= acpi_switch.S acpi_wakedata.h CLEANFILES+= acpi_wakedata.h ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} +NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${WERROR} ${.IMPSRC} +NM?= nm acpi_switch.o: acpi_switch.S - ${CC} -c ${ASM_CFLAGS} ${WERROR} ${.IMPSRC} + ${NORMAL_S} acpi_wakecode.o: acpi_wakecode.S assym.s - ${CC} -c ${ASM_CFLAGS} ${WERROR} ${.IMPSRC} + ${NORMAL_S} acpi_wakecode.bin: acpi_wakecode.o objcopy -S -O binary acpi_wakecode.o ${.TARGET} acpi_wakecode.h: acpi_wakecode.bin file2c -sx 'static char wakecode[] = {' '};' < acpi_wakecode.bin > \ ${.TARGET} acpi_wakedata.h: acpi_wakecode.o - nm -n --defined-only ${.ALLSRC} | while read offset dummy what; do \ - echo "#define $${what} 0x$${offset}"; done > ${.TARGET} + ${NM} -n --defined-only acpi_wakecode.o | \ + while read offset dummy what; do \ + echo "#define $${what} 0x$${offset}"; \ + done > ${.TARGET} .else acpi_wakecode.h: acpi_wakecode.S assym.s - ${MAKE} -f ${.CURDIR}/../../../${MACHINE_ARCH}/acpica/Makefile \ - MAKESRCPATH=${.CURDIR}/../../../${MACHINE_ARCH}/acpica + ${MAKE} -f ${.CURDIR}/../../../${MACHINE_CPUARCH}/acpica/Makefile \ + MAKESRCPATH=${.CURDIR}/../../../${MACHINE_CPUARCH}/acpica .endif .include diff --git a/sys/modules/agp/Makefile b/sys/modules/agp/Makefile index 40263251beb..f77e38cfeff 100644 --- a/sys/modules/agp/Makefile +++ b/sys/modules/agp/Makefile @@ -4,14 +4,14 @@ KMOD= agp SRCS= agp.c agp_if.c -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= agp_i810.c agp_intel.c agp_via.c agp_sis.c agp_ali.c agp_amd.c \ agp_nvidia.c agp_ati.c .endif .if ${MACHINE} == "i386" SRCS+= agp_amd64.c .endif -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= agp_amd64.c agp_i810.c agp_via.c .endif SRCS+= device_if.h bus_if.h agp_if.h pci_if.h diff --git a/sys/modules/amr/Makefile b/sys/modules/amr/Makefile index 4c31997c844..02de047d2aa 100644 --- a/sys/modules/amr/Makefile +++ b/sys/modules/amr/Makefile @@ -3,7 +3,7 @@ .PATH: ${.CURDIR}/../../dev/amr SUBDIR= amr_cam -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" SUBDIR+= amr_linux .endif diff --git a/sys/modules/asr/Makefile b/sys/modules/asr/Makefile index 7addf52974f..5873415d028 100644 --- a/sys/modules/asr/Makefile +++ b/sys/modules/asr/Makefile @@ -7,7 +7,7 @@ SRCS= asr.c SRCS+= opt_scsi.h opt_cam.h SRCS+= device_if.h bus_if.h pci_if.h -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= opt_asr.h .endif diff --git a/sys/modules/bge/Makefile b/sys/modules/bge/Makefile index f8ebf42fd8d..9742e6b8f37 100644 --- a/sys/modules/bge/Makefile +++ b/sys/modules/bge/Makefile @@ -5,7 +5,7 @@ KMOD= if_bge SRCS= if_bge.c miibus_if.h miidevs.h device_if.h bus_if.h pci_if.h -.if ${MACHINE_ARCH} == sparc64 +.if ${MACHINE_CPUARCH} == sparc64 SRCS+= ofw_bus_if.h .endif diff --git a/sys/modules/cpufreq/Makefile b/sys/modules/cpufreq/Makefile index 894096ff14a..26fea830b8c 100644 --- a/sys/modules/cpufreq/Makefile +++ b/sys/modules/cpufreq/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../dev/cpufreq \ - ${.CURDIR}/../../${MACHINE_ARCH}/cpufreq + ${.CURDIR}/../../${MACHINE_CPUARCH}/cpufreq KMOD= cpufreq SRCS= ichss.c diff --git a/sys/modules/crypto/Makefile b/sys/modules/crypto/Makefile index be801db598d..bf7c566f133 100644 --- a/sys/modules/crypto/Makefile +++ b/sys/modules/crypto/Makefile @@ -12,7 +12,7 @@ KMOD = crypto SRCS = crypto.c cryptodev_if.c SRCS += criov.c cryptosoft.c xform.c SRCS += cast.c deflate.c rmd160.c rijndael-alg-fst.c rijndael-api.c -SRCS += skipjack.c bf_enc.c bf_skey.c +SRCS += skipjack.c bf_enc.c bf_ecb.c bf_skey.c SRCS += des_ecb.c des_enc.c des_setkey.c SRCS += sha1.c sha2.c SRCS += opt_param.h cryptodev_if.h bus_if.h device_if.h diff --git a/sys/modules/cryptodev/Makefile b/sys/modules/cryptodev/Makefile index 903bfbc52c3..a82517d5897 100644 --- a/sys/modules/cryptodev/Makefile +++ b/sys/modules/cryptodev/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../opencrypto KMOD = cryptodev SRCS = cryptodev.c -SRCS += bus_if.h device_if.h +SRCS += bus_if.h device_if.h opt_compat.h .include diff --git a/sys/modules/cxgb/Makefile b/sys/modules/cxgb/Makefile index 71cbb7add81..a6af8179daf 100644 --- a/sys/modules/cxgb/Makefile +++ b/sys/modules/cxgb/Makefile @@ -28,11 +28,11 @@ _toecore = toecore #_tom = tom .endif -.if ${MACHINE_ARCH} == "i386" && exists(${_toe_header}) +.if ${MACHINE_CPUARCH} == "i386" && exists(${_toe_header}) _iw_cxgb = iw_cxgb .endif -.if ${MACHINE_ARCH} == "amd64" && exists(${_toe_header}) +.if ${MACHINE_CPUARCH} == "amd64" && exists(${_toe_header}) _iw_cxgb = iw_cxgb .endif diff --git a/sys/modules/cyclic/Makefile b/sys/modules/cyclic/Makefile index 371dac68054..b29cac1bd6e 100644 --- a/sys/modules/cyclic/Makefile +++ b/sys/modules/cyclic/Makefile @@ -4,13 +4,13 @@ KMOD= cyclic SRCS= cyclic.c - + SRCS+= vnode_if.h CFLAGS+= -I${.CURDIR}/../../cddl/compat/opensolaris \ -I${.CURDIR}/../../cddl/contrib/opensolaris/uts/common \ -I${.CURDIR}/../.. \ - -I${.CURDIR}/../../cddl/dev/cyclic/${MACHINE_ARCH:S/amd64/i386/} + -I${.CURDIR}/../../cddl/dev/cyclic/${MACHINE_CPUARCH:S/amd64/i386/} CFLAGS+= -DDEBUG=1 diff --git a/sys/modules/dtrace/Makefile b/sys/modules/dtrace/Makefile index ba468788bbf..02c476697c6 100644 --- a/sys/modules/dtrace/Makefile +++ b/sys/modules/dtrace/Makefile @@ -14,10 +14,8 @@ SUBDIR= dtmalloc \ sdt \ systrace -.if ${MACHINE_ARCH} == "amd64" -SUBDIR+= fbt -.elif ${MACHINE_ARCH} == "i386" -SUBDIR+= fbt +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" +SUBDIR+= fasttrap fbt .endif .include diff --git a/sys/modules/dtrace/Makefile.inc b/sys/modules/dtrace/Makefile.inc index c35764b2998..db329604700 100644 --- a/sys/modules/dtrace/Makefile.inc +++ b/sys/modules/dtrace/Makefile.inc @@ -5,7 +5,7 @@ IGNORE_PRAGMA= 1 load : -kldload cyclic -kldload dtrace -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" -kldload sdt -kldload lockstat -kldload fbt @@ -18,7 +18,7 @@ load : unload : -kldunload systrace -kldunload profile -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" -kldunload prototype -kldunload fbt -kldunload lockstat diff --git a/sys/modules/dtrace/dtrace/Makefile b/sys/modules/dtrace/dtrace/Makefile index 08e61a94c4f..f359f8d9009 100644 --- a/sys/modules/dtrace/dtrace/Makefile +++ b/sys/modules/dtrace/dtrace/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -ARCHDIR= ${MACHINE_ARCH} +ARCHDIR= ${MACHINE_CPUARCH} .PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/uts/common/dtrace .PATH: ${.CURDIR}/../../../cddl/kern @@ -12,9 +12,10 @@ SRCS= dtrace.c \ dtrace_asm.S \ dtrace_subr.c -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" SRCS+= dis_tables.c \ instr_size.c +CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/intel .endif SRCS+= bus_if.h device_if.h vnode_if.h @@ -25,7 +26,7 @@ SRCS+= assym.s # These are needed for assym.s SRCS+= opt_compat.h opt_kstack_pages.h opt_nfs.h opt_hwpmc_hooks.h -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= opt_apic.h .endif diff --git a/sys/modules/dtrace/dtraceall/dtraceall.c b/sys/modules/dtrace/dtraceall/dtraceall.c index d8d330fda30..ecb5e344b03 100644 --- a/sys/modules/dtrace/dtraceall/dtraceall.c +++ b/sys/modules/dtrace/dtraceall/dtraceall.c @@ -68,6 +68,7 @@ MODULE_DEPEND(dtraceall, dtmalloc, 1, 1, 1); MODULE_DEPEND(dtraceall, dtnfsclient, 1, 1, 1); #if defined(__amd64__) || defined(__i386__) MODULE_DEPEND(dtraceall, fbt, 1, 1, 1); +MODULE_DEPEND(dtraceall, fasttrap, 1, 1, 1); #endif MODULE_DEPEND(dtraceall, lockstat, 1, 1, 1); MODULE_DEPEND(dtraceall, sdt, 1, 1, 1); diff --git a/sys/modules/dtrace/fasttrap/Makefile b/sys/modules/dtrace/fasttrap/Makefile index 104fd9af445..cf93c153099 100644 --- a/sys/modules/dtrace/fasttrap/Makefile +++ b/sys/modules/dtrace/fasttrap/Makefile @@ -1,17 +1,18 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../../cddl/dev/fasttrap +.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/uts/common/dtrace KMOD= fasttrap -SRCS= fasttrap.c +SRCS= fasttrap.c fasttrap_isa.c opt_compat.h SRCS+= vnode_if.h CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris \ -I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/common \ -I${.CURDIR}/../../.. -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" CFLAGS+= -I${.CURDIR}/../../../cddl/contrib/opensolaris/uts/intel +.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/uts/intel/dtrace .endif CFLAGS+= -DSMP -DDEBUG diff --git a/sys/modules/em/Makefile b/sys/modules/em/Makefile index 1fac033d55b..b74ddf101f9 100644 --- a/sys/modules/em/Makefile +++ b/sys/modules/em/Makefile @@ -18,10 +18,4 @@ CFLAGS += -I${.CURDIR}/../../dev/e1000 # DEVICE_POLLING for a non-interrupt-driven method #CFLAGS += -DDEVICE_POLLING -clean: - rm -f device_if.h bus_if.h pci_if.h setdef* - rm -f *.o *.kld *.ko - rm -f @ machine - rm -f ${CLEANFILES} - .include diff --git a/sys/modules/gem/Makefile b/sys/modules/gem/Makefile index 94db46251a7..941dc18f4a2 100644 --- a/sys/modules/gem/Makefile +++ b/sys/modules/gem/Makefile @@ -3,10 +3,15 @@ .PATH: ${.CURDIR}/../../dev/gem KMOD= if_gem -SRCS= bus_if.h device_if.h if_gem.c if_gem_pci.c miibus_if.h pci_if.h +SRCS= bus_if.h device_if.h if_gem.c if_gem_pci.c ${if_gem_sbus} miibus_if.h +SRCS+= ${ofw_bus_if} pci_if.h .if ${MACHINE} == "sparc64" -SRCS+= if_gem_sbus.c ofw_bus_if.h +if_gem_sbus= if_gem_sbus.c +.endif + +.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "sparc64" +ofw_bus_if= ofw_bus_if.h .endif .include diff --git a/sys/modules/hptmv/Makefile b/sys/modules/hptmv/Makefile index 05ceac7bb1f..134c207020d 100644 --- a/sys/modules/hptmv/Makefile +++ b/sys/modules/hptmv/Makefile @@ -13,7 +13,7 @@ SRCS+= bus_if.h device_if.h pci_if.h SRCS+= mv.c entry.c ioctl.c hptproc.c gui_lib.c OBJS+= hptmvraid.o -.if $(MACHINE_ARCH) == "amd64" +.if $(MACHINE_CPUARCH) == "amd64" HPTMV_RAID_O = amd64-elf.raid.o.uu .else HPTMV_RAID_O = i386-elf.raid.o.uu @@ -48,5 +48,5 @@ DEBUGOPT += -DFOR_DEMO .endif CFLAGS = ${DEBUGOPT} - + .include diff --git a/sys/modules/hptrr/Makefile b/sys/modules/hptrr/Makefile index 038c5a45f46..7cbd7e85a24 100644 --- a/sys/modules/hptrr/Makefile +++ b/sys/modules/hptrr/Makefile @@ -9,6 +9,6 @@ SRCS+= hptrr_os_bsd.c hptrr_osm_bsd.c hptrr_config.c OBJS = hptrr_lib.o hptrr_lib.o: - uudecode -p < ${HPTRR}/$(MACHINE_ARCH)-elf.hptrr_lib.o.uu > hptrr_lib.o + uudecode -p < ${HPTRR}/$(MACHINE_CPUARCH)-elf.hptrr_lib.o.uu > hptrr_lib.o .include diff --git a/sys/modules/hwpmc/Makefile b/sys/modules/hwpmc/Makefile index b295a67f5ae..b834f174dbf 100644 --- a/sys/modules/hwpmc/Makefile +++ b/sys/modules/hwpmc/Makefile @@ -8,23 +8,23 @@ KMOD= hwpmc SRCS= hwpmc_mod.c hwpmc_logging.c vnode_if.h -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= hwpmc_amd.c hwpmc_core.c hwpmc_intel.c hwpmc_piv.c hwpmc_tsc.c SRCS+= hwpmc_x86.c hwpmc_uncore.c SRCS+= device_if.h bus_if.h .endif -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "arm" SRCS+= hwpmc_arm.c .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= hwpmc_amd.c hwpmc_core.c hwpmc_intel.c hwpmc_piv.c hwpmc_ppro.c SRCS+= hwpmc_pentium.c hwpmc_tsc.c hwpmc_x86.c hwpmc_uncore.c SRCS+= device_if.h bus_if.h .endif -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" SRCS+= hwpmc_ia64.c .endif @@ -32,7 +32,7 @@ SRCS+= hwpmc_ia64.c SRCS+= hwpmc_powerpc.c .endif -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" SRCS+= hwpmc_sparc64.c .endif diff --git a/sys/modules/i2c/controllers/pcf/Makefile b/sys/modules/i2c/controllers/pcf/Makefile index 4714cfd9c1c..27d9339822f 100644 --- a/sys/modules/i2c/controllers/pcf/Makefile +++ b/sys/modules/i2c/controllers/pcf/Makefile @@ -6,12 +6,12 @@ KMOD= pcf SRCS= ${envctrl} pcf.c ${pcf_ebus} ${pcf_isa} SRCS+= bus_if.h device_if.h iicbus_if.h ${isa_if} ${ofw_bus_if} -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" isa_if= isa_if.h pcf_isa= pcf_isa.c .endif -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" envctrl= envctrl.c ofw_bus_if= ofw_bus_if.h pcf_ebus= pcf_ebus.c diff --git a/sys/modules/igb/Makefile b/sys/modules/igb/Makefile index 4d375e59d4f..a66c32a40dc 100644 --- a/sys/modules/igb/Makefile +++ b/sys/modules/igb/Makefile @@ -14,14 +14,4 @@ CFLAGS += -I${.CURDIR}/../../dev/e1000 -DSMP # not advisable since MSIX gives better results #CFLAGS += -DDEVICE_POLLING -clean: - rm -f device_if.h bus_if.h pci_if.h setdef* - rm -f *.o *.kld *.ko - rm -f @ machine - rm -f ${CLEANFILES} - -man: - mv /usr/share/man/man4/igb.4.gz /usr/share/man/man4/igbSAVE.4.gz - cp igb.4 /usr/share/man/man4/ - .include diff --git a/sys/modules/io/Makefile b/sys/modules/io/Makefile index d90a8e473b1..1612fa0eff5 100644 --- a/sys/modules/io/Makefile +++ b/sys/modules/io/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../dev/io -.PATH: ${.CURDIR}/../../${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${.CURDIR}/../../${MACHINE_CPUARCH}/${MACHINE_CPUARCH} KMOD= io SRCS= iodev.c io.c diff --git a/sys/modules/ixgbe/Makefile b/sys/modules/ixgbe/Makefile index 2de7549a581..56c39eda268 100644 --- a/sys/modules/ixgbe/Makefile +++ b/sys/modules/ixgbe/Makefile @@ -8,9 +8,4 @@ SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c SRCS += ixgbe_82599.c ixgbe_82598.c CFLAGS+= -I${.CURDIR}/../../dev/ixgbe -DSMP -DIXGBE_FDIR -clean: - rm -f device_if.h bus_if.h pci_if.h setdef* *_StripErr - rm -f *.o *.kld *.ko - rm -f @ machine - .include diff --git a/sys/modules/krpc/Makefile b/sys/modules/krpc/Makefile index ab52f5bdbd4..2f3d3a7f0ae 100644 --- a/sys/modules/krpc/Makefile +++ b/sys/modules/krpc/Makefile @@ -9,8 +9,6 @@ SRCS= auth_none.c \ clnt_rc.c \ clnt_vc.c \ getnetconfig.c \ - inet_ntop.c \ - inet_pton.c \ rpc_callmsg.c \ rpc_generic.c \ rpc_prot.c \ diff --git a/sys/modules/le/Makefile b/sys/modules/le/Makefile index dd202fb8955..d267cbec2c2 100644 --- a/sys/modules/le/Makefile +++ b/sys/modules/le/Makefile @@ -7,7 +7,7 @@ SRCS= am7990.c am79900.c ${if_le_cbus} ${if_le_isa} ${if_le_lebuffer} SRCS+= ${if_le_ledma} if_le_pci.c lance.c ${lebuffer_sbus} SRCS+= bus_if.h device_if.h ${isa_if} ${ofw_bus_if} pci_if.h -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" .if ${MACHINE} == "pc98" if_le_cbus= if_le_cbus.c .else diff --git a/sys/modules/linprocfs/Makefile b/sys/modules/linprocfs/Makefile index f0f00cbea6f..4b1b3754303 100644 --- a/sys/modules/linprocfs/Makefile +++ b/sys/modules/linprocfs/Makefile @@ -8,7 +8,7 @@ SRCS= vnode_if.h \ linprocfs.c \ opt_compat.h -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+=-DCOMPAT_LINUX32 .endif diff --git a/sys/modules/linsysfs/Makefile b/sys/modules/linsysfs/Makefile index 1320212004f..40179677920 100644 --- a/sys/modules/linsysfs/Makefile +++ b/sys/modules/linsysfs/Makefile @@ -8,7 +8,7 @@ SRCS= vnode_if.h \ linsysfs.c \ opt_compat.h -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" CFLAGS+=-DCOMPAT_LINUX32 .endif diff --git a/sys/modules/linux/Makefile b/sys/modules/linux/Makefile index 6474327df4f..78f6f8599ab 100644 --- a/sys/modules/linux/Makefile +++ b/sys/modules/linux/Makefile @@ -1,11 +1,11 @@ # $FreeBSD$ -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SFX= 32 CFLAGS+=-DCOMPAT_FREEBSD32 -DCOMPAT_LINUX32 .endif -.PATH: ${.CURDIR}/../../compat/linux ${.CURDIR}/../../${MACHINE_ARCH}/linux${SFX} +.PATH: ${.CURDIR}/../../compat/linux ${.CURDIR}/../../${MACHINE_CPUARCH}/linux${SFX} KMOD= linux SRCS= linux${SFX}_dummy.c linux_emul.c linux_file.c \ @@ -18,13 +18,13 @@ SRCS= linux${SFX}_dummy.c linux_emul.c linux_file.c \ # XXX: for assym.s SRCS+= opt_kstack_pages.h opt_nfs.h opt_compat.h opt_hwpmc_hooks.h -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= opt_apic.h .endif OBJS= linux${SFX}_locore.o linux${SFX}_support.o -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= linux_ptrace.c imgact_linux.c opt_cpu.h .endif diff --git a/sys/modules/mem/Makefile b/sys/modules/mem/Makefile index 812da143936..b65a4447dcd 100644 --- a/sys/modules/mem/Makefile +++ b/sys/modules/mem/Makefile @@ -2,17 +2,17 @@ .PATH: ${.CURDIR}/../../dev/mem .PATH: ${.CURDIR}/../../${MACHINE}/${MACHINE} -.PATH: ${.CURDIR}/../../${MACHINE_ARCH}/${MACHINE_ARCH} +.PATH: ${.CURDIR}/../../${MACHINE_CPUARCH}/${MACHINE_CPUARCH} KMOD= mem SRCS= memdev.c mem.c -.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" SRCS+= memutil.c .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= i686_mem.c k6_mem.c .endif -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= amd64_mem.c .endif SRCS+= bus_if.h device_if.h diff --git a/sys/modules/mfi/Makefile b/sys/modules/mfi/Makefile index a58e968ffd4..00caa57e177 100644 --- a/sys/modules/mfi/Makefile +++ b/sys/modules/mfi/Makefile @@ -4,7 +4,7 @@ SUBDIR= mfip -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" SUBDIR+= mfi_linux .endif diff --git a/sys/modules/mii/Makefile b/sys/modules/mii/Makefile index 6232b5e5808..c1ffae217be 100644 --- a/sys/modules/mii/Makefile +++ b/sys/modules/mii/Makefile @@ -12,8 +12,8 @@ SRCS+= rgephy.c rlphy.c ruephy.c tdkphy.c tlphy.c truephy.c ukphy.c SRCS+= ukphy_subr.c SRCS+= xmphy.c -EXPORT_SYMS= mii_mediachg \ - mii_phy_probe \ +EXPORT_SYMS= mii_attach \ + mii_mediachg \ mii_phy_reset \ mii_pollstat \ mii_tick diff --git a/sys/modules/mps/Makefile b/sys/modules/mps/Makefile new file mode 100644 index 00000000000..49e65da3363 --- /dev/null +++ b/sys/modules/mps/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/mps + +KMOD= mps +SRCS= mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c +SRCS+= opt_mps.h opt_cam.h opt_compat.h +SRCS+= device_if.h bus_if.h pci_if.h + +#CFLAGS += -DMPS_DEBUG +DEBUG += -g + +.include diff --git a/sys/modules/ndis/Makefile b/sys/modules/ndis/Makefile index 8ef7089ac3f..b4dc428bdb5 100644 --- a/sys/modules/ndis/Makefile +++ b/sys/modules/ndis/Makefile @@ -8,11 +8,11 @@ SRCS+= kern_windrv.c subr_usbd.c SRCS+= device_if.h bus_if.h pci_if.h vnode_if.h SRCS+= opt_bus.h opt_usb.h usb_if.h usbdevs.h -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= winx64_wrap.S .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= winx32_wrap.S .endif diff --git a/sys/modules/opensolaris/Makefile b/sys/modules/opensolaris/Makefile index eef8ffd6e35..ca4f12a39f6 100644 --- a/sys/modules/opensolaris/Makefile +++ b/sys/modules/opensolaris/Makefile @@ -8,8 +8,12 @@ SRCS= opensolaris.c \ opensolaris_kmem.c \ opensolaris_misc.c -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "ia64" || ${MACHINE_ARCH} == "sparc64" || ${MACHINE_ARCH} == "powerpc64" -.PATH: ${.CURDIR}/../../cddl/contrib/opensolaris/common/atomic/${MACHINE_ARCH} +_A=${.CURDIR}/../../cddl/contrib/opensolaris/common/atomic +.if exists(${_A}/${MACHINE_CPUARCH}/opensolaris_atomic.S) +.PATH: ${_A}/${MACHINE_CPUARCH} +SRCS+= opensolaris_atomic.S +.elif exists(${_A}/${MACHINE_ARCH}/opensolaris_atomic.S) +.PATH: ${_A}/${MACHINE_ARCH} SRCS+= opensolaris_atomic.S .else SRCS+= opensolaris_atomic.c diff --git a/sys/modules/ppc/Makefile b/sys/modules/ppc/Makefile index db36e733773..c097002a62c 100644 --- a/sys/modules/ppc/Makefile +++ b/sys/modules/ppc/Makefile @@ -6,18 +6,18 @@ SRCS= bus_if.h device_if.h ppbus_if.h isa_if.h pci_if.h serdev_if.h \ opt_ppc.h opt_isa.h \ ppc.c ppc_pci.c ppc_puc.c -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" SRCS+= ppc_acpi.c ppc_isa.c .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" .if ${MACHINE} != "pc98" SRCS+= ppc_acpi.c .endif SRCS+= ppc_isa.c .endif -.if ${MACHINE_ARCH} == "ia64" +.if ${MACHINE_CPUARCH} == "ia64" SRCS+= ppc_acpi.c .endif diff --git a/sys/modules/procfs/Makefile b/sys/modules/procfs/Makefile index 9a94838c70a..2b3b0620bbe 100644 --- a/sys/modules/procfs/Makefile +++ b/sys/modules/procfs/Makefile @@ -34,7 +34,7 @@ opt_compat.h: echo "#define COMPAT_FREEBSD4 1" >> ${.TARGET} echo "#define COMPAT_FREEBSD5 1" >> ${.TARGET} echo "#define COMPAT_FREEBSD6 1" >> ${.TARGET} -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" echo "#define COMPAT_FREEBSD32 1" >> ${.TARGET} echo "#define COMPAT_LINUX32 1" >> ${.TARGET} .endif diff --git a/sys/modules/scc/Makefile b/sys/modules/scc/Makefile index c1678b76f72..8a40e0b0007 100644 --- a/sys/modules/scc/Makefile +++ b/sys/modules/scc/Makefile @@ -5,7 +5,7 @@ .if ${MACHINE} == "sparc64" scc_bfe= scc_bfe_ebus.c scc_bfe_sbus.c .endif -.if ${MACHINE_ARCH} == "powerpc" +.if ${MACHINE_CPUARCH} == "powerpc" scc_bfe= scc_bfe_macio.c scc_bfe_quicc.c .endif diff --git a/sys/modules/send/Makefile b/sys/modules/send/Makefile new file mode 100644 index 00000000000..1cb976b9b8d --- /dev/null +++ b/sys/modules/send/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ +.PATH: ${.CURDIR}/../../netinet6 + +KMOD= send +SRCS= send.c + +.include diff --git a/sys/modules/smbfs/Makefile b/sys/modules/smbfs/Makefile index e8432e39297..476e598edb6 100644 --- a/sys/modules/smbfs/Makefile +++ b/sys/modules/smbfs/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ .PATH: ${.CURDIR}/../../crypto/des \ - ${.CURDIR}/../../crypto/des/arch/${MACHINE_ARCH} \ + ${.CURDIR}/../../crypto/des/arch/${MACHINE_CPUARCH} \ ${.CURDIR}/../../kern \ ${.CURDIR}/../../libkern \ ${.CURDIR}/../../netsmb \ @@ -21,7 +21,7 @@ SRCS= vnode_if.h \ # NETSMBCRYPTO SRCS+= des_ecb.c des_setkey.c -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= des_enc.S .else SRCS+= des_enc.c diff --git a/sys/modules/sound/driver/Makefile b/sys/modules/sound/driver/Makefile index c07a1c55337..ef018b2f607 100644 --- a/sys/modules/sound/driver/Makefile +++ b/sys/modules/sound/driver/Makefile @@ -5,11 +5,11 @@ SUBDIR+= envy24 envy24ht es137x ess fm801 hda ich maestro maestro3 SUBDIR+= neomagic sb16 sb8 sbc solo spicds t4dwave via8233 SUBDIR+= via82c686 vibes driver uaudio -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" SUBDIR+= cmi mss .endif -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" .if ${MACHINE} == "sparc64" SUBDIR+= audiocs .endif diff --git a/sys/modules/sound/sound/Makefile b/sys/modules/sound/sound/Makefile index 78f91d44553..42cfc24f011 100644 --- a/sys/modules/sound/sound/Makefile +++ b/sys/modules/sound/sound/Makefile @@ -44,7 +44,7 @@ CLEANFILES+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h EXPORT_SYMS= YES # XXX evaluate -.if ${MACHINE_ARCH} == "sparc64" || ${MACHINE_ARCH} == "powerpc" +.if ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "powerpc" # Create an empty opt_isa.h in order to keep kmod.mk from linking in an # existing one from KERNBUILDDIR which possibly has DEV_ISA defined so # sound.ko is always built without isadma support. diff --git a/sys/modules/svr4/Makefile b/sys/modules/svr4/Makefile index 50550989a6e..9fc0901ff46 100644 --- a/sys/modules/svr4/Makefile +++ b/sys/modules/svr4/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../${MACHINE_ARCH}/svr4 ${.CURDIR}/../../compat/svr4 +.PATH: ${.CURDIR}/../../${MACHINE_CPUARCH}/svr4 ${.CURDIR}/../../compat/svr4 KMOD= svr4 SRCS= svr4_sysent.c svr4_sysvec.c opt_compat.h opt_svr4.h \ vnode_if.h imgact_svr4.c svr4_signal.c svr4_fcntl.c \ diff --git a/sys/modules/syscons/Makefile b/sys/modules/syscons/Makefile index 13cbc57f000..b047845dece 100644 --- a/sys/modules/syscons/Makefile +++ b/sys/modules/syscons/Makefile @@ -14,11 +14,12 @@ SUBDIR= ${_apm} \ ${_star} \ ${_warp} -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" _apm= apm .endif -.if ${MACHINE_ARCH} != "sparc64" +.if ${MACHINE_CPUARCH} != "sparc64" +_beastie= beastie _beastie= beastie _daemon= daemon _dragon= dragon diff --git a/sys/modules/sysvipc/sysvmsg/Makefile b/sys/modules/sysvipc/sysvmsg/Makefile index e60b8a2fd1d..38fc2a24596 100644 --- a/sys/modules/sysvipc/sysvmsg/Makefile +++ b/sys/modules/sysvipc/sysvmsg/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../../kern KMOD= sysvmsg -SRCS= sysv_msg.c opt_sysvipc.h +SRCS= sysv_msg.c opt_sysvipc.h opt_compat.h .include diff --git a/sys/modules/sysvipc/sysvsem/Makefile b/sys/modules/sysvipc/sysvsem/Makefile index 13fe06ad3f8..abc95448c05 100644 --- a/sys/modules/sysvipc/sysvsem/Makefile +++ b/sys/modules/sysvipc/sysvsem/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../../kern KMOD= sysvsem -SRCS= sysv_sem.c opt_sysvipc.h +SRCS= sysv_sem.c opt_sysvipc.h opt_compat.h .include diff --git a/sys/modules/uart/Makefile b/sys/modules/uart/Makefile index 862930db80c..1a5ce4436da 100644 --- a/sys/modules/uart/Makefile +++ b/sys/modules/uart/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../dev/uart -.if ${MACHINE_ARCH} == "sparc64" +.if ${MACHINE_CPUARCH} == "sparc64" uart_bus_ebus= uart_bus_ebus.c ofw_bus_if= ofw_bus_if.h .endif diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile index 7f43e2bcc08..f486e9849a5 100644 --- a/sys/modules/usb/Makefile +++ b/sys/modules/usb/Makefile @@ -26,25 +26,25 @@ # SUBDIR = usb -SUBDIR += ehci musb ohci uhci uss820dci ${_at91dci} ${_atmegadci} +SUBDIR += ehci musb ohci uhci xhci uss820dci ${_at91dci} ${_atmegadci} SUBDIR += rum run uath upgt ural zyd ${_urtw} SUBDIR += atp uhid ukbd ums udbp ufm SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \ umct umodem umoscom uplcom uslcom uvisor uvscom -SUBDIR += uether aue axe cdce cue kue rue udav uhso +SUBDIR += uether aue axe cdce cue kue rue udav uhso ipheth SUBDIR += usfs umass urio SUBDIR += quirk template -.if ${MACHINE_ARCH} == "amd64" +.if ${MACHINE_CPUARCH} == "amd64" _urtw= urtw .endif -.if ${MACHINE_ARCH} == "arm" +.if ${MACHINE_CPUARCH} == "arm" _at91dci= at91dci _atmegadci= atmegadci .endif -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" _urtw= urtw .endif diff --git a/sys/modules/usb/ipheth/Makefile b/sys/modules/usb/ipheth/Makefile new file mode 100644 index 00000000000..b0553743957 --- /dev/null +++ b/sys/modules/usb/ipheth/Makefile @@ -0,0 +1,37 @@ +# +# $FreeBSD$ +# +# Copyright (c) 2010 Hans Petter Selasky. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# 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. +# + +S= ${.CURDIR}/../../.. + +.PATH: $S/dev/usb/net + +KMOD= if_ipheth +SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h usbdevs.h \ + miibus_if.h opt_inet.h \ + if_ipheth.c + +.include diff --git a/sys/modules/usb/xhci/Makefile b/sys/modules/usb/xhci/Makefile new file mode 100644 index 00000000000..07dcba0259c --- /dev/null +++ b/sys/modules/usb/xhci/Makefile @@ -0,0 +1,38 @@ +# +# $FreeBSD$ +# +# Copyright (c) 2010 Hans Petter Selasky. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# 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. +# + +S= ${.CURDIR}/../../.. + +.PATH: $S/dev/usb/controller + +KMOD= xhci +SRCS= bus_if.h device_if.h usb_if.h \ + opt_bus.h opt_usb.h \ + xhci_pci.c xhci.c \ + pci_if.h + +.include diff --git a/sys/modules/vx/Makefile b/sys/modules/vx/Makefile index 6293b1a21fd..e1822ea3459 100644 --- a/sys/modules/vx/Makefile +++ b/sys/modules/vx/Makefile @@ -4,7 +4,7 @@ KMOD= if_vx SRCS= if_vx.c if_vx_pci.c -.if ${MACHINE_ARCH} == "i386" +.if ${MACHINE_CPUARCH} == "i386" SRCS+= if_vx_eisa.c .endif SRCS+= device_if.h bus_if.h pci_if.h eisa_if.h diff --git a/sys/modules/wlan/Makefile b/sys/modules/wlan/Makefile index 79d5e75afad..682aab3cfa9 100644 --- a/sys/modules/wlan/Makefile +++ b/sys/modules/wlan/Makefile @@ -3,13 +3,13 @@ .PATH: ${.CURDIR}/../../net80211 KMOD= wlan -SRCS= ieee80211.c ieee80211_action.c ieee80211_ageq.c ieee80211_amrr.c \ +SRCS= ieee80211.c ieee80211_action.c ieee80211_ageq.c \ ieee80211_crypto.c ieee80211_crypto_none.c ieee80211_dfs.c \ ieee80211_freebsd.c ieee80211_input.c ieee80211_ioctl.c \ ieee80211_mesh.c ieee80211_node.c ieee80211_output.c ieee80211_phy.c \ ieee80211_power.c ieee80211_proto.c ieee80211_scan.c \ ieee80211_scan_sta.c ieee80211_radiotap.c ieee80211_ratectl.c \ - ieee80211_regdomain.c ieee80211_rssadapt.c \ + ieee80211_ratectl_none.c ieee80211_regdomain.c \ ieee80211_ht.c ieee80211_hwmp.c ieee80211_adhoc.c ieee80211_hostap.c \ ieee80211_monitor.c ieee80211_sta.c ieee80211_wds.c ieee80211_ddb.c SRCS+= bus_if.h device_if.h opt_inet.h opt_inet6.h opt_ipx.h opt_wlan.h \ diff --git a/sys/modules/zfs/Makefile b/sys/modules/zfs/Makefile index e4cf297fc7d..d0a6f44bde3 100644 --- a/sys/modules/zfs/Makefile +++ b/sys/modules/zfs/Makefile @@ -27,12 +27,15 @@ SRCS+= opensolaris_uio.c SRCS+= opensolaris_vfs.c SRCS+= opensolaris_zone.c -.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "ia64" || ${MACHINE_ARCH} == "sparc64" || ${MACHINE_ARCH} == "powerpc64" -.PATH: ${SUNW}/common/atomic/${MACHINE_ARCH} -SRCS+= opensolaris_atomic.S +_A=${.CURDIR}/../../cddl/contrib/opensolaris/common/atomic +.if exists(${_A}/${MACHINE_CPUARCH}/opensolaris_atomic.S) +.PATH: ${_A}/${MACHINE_CPUARCH} +SRCS+= opensolaris_atomic.S +.elif exists(${_A}/${MACHINE_ARCH}/opensolaris_atomic.S) +.PATH: ${_A}/${MACHINE_ARCH} +SRCS+= opensolaris_atomic.S .else -.PATH: ${.CURDIR}/../../cddl/compat/opensolaris/kern -SRCS+= opensolaris_atomic.c +SRCS+= opensolaris_atomic.c .endif .PATH: ${SUNW}/uts/common/fs diff --git a/sys/net/bpf.c b/sys/net/bpf.c index ab2ba1f2528..e5165731dae 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -1392,7 +1392,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, break; /* - * Set packet timestamp format and resolution. + * Get packet timestamp format and resolution. */ case BIOCGTSTAMP: *(u_int *)addr = d->bd_tstamp; diff --git a/sys/net/if.c b/sys/net/if.c index c387dbf498f..3c8486aa6b6 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -92,6 +92,11 @@ #include +#ifdef COMPAT_FREEBSD32 +#include +#include +#endif + struct ifindex_entry { struct ifnet *ife_ifnet; }; @@ -2402,6 +2407,17 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) return (error); } +#ifdef COMPAT_FREEBSD32 +struct ifconf32 { + int32_t ifc_len; + union { + uint32_t ifcu_buf; + uint32_t ifcu_req; + } ifc_ifcu; +}; +#define SIOCGIFCONF32 _IOWR('i', 36, struct ifconf32) +#endif + /* * Interface ioctls. */ @@ -2416,10 +2432,21 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) switch (cmd) { case SIOCGIFCONF: case OSIOCGIFCONF: -#ifdef __amd64__ - case SIOCGIFCONF32: -#endif return (ifconf(cmd, data)); + +#ifdef COMPAT_FREEBSD32 + case SIOCGIFCONF32: + { + struct ifconf32 *ifc32; + struct ifconf ifc; + + ifc32 = (struct ifconf32 *)data; + ifc.ifc_len = ifc32->ifc_len; + ifc.ifc_buf = PTRIN(ifc32->ifc_buf); + + return (ifconf(SIOCGIFCONF, (void *)&ifc)); + } +#endif } ifr = (struct ifreq *)data; @@ -2646,23 +2673,12 @@ static int ifconf(u_long cmd, caddr_t data) { struct ifconf *ifc = (struct ifconf *)data; -#ifdef __amd64__ - struct ifconf32 *ifc32 = (struct ifconf32 *)data; - struct ifconf ifc_swab; -#endif struct ifnet *ifp; struct ifaddr *ifa; struct ifreq ifr; struct sbuf *sb; int error, full = 0, valid_len, max_len; -#ifdef __amd64__ - if (cmd == SIOCGIFCONF32) { - ifc_swab.ifc_len = ifc32->ifc_len; - ifc_swab.ifc_buf = (caddr_t)(uintptr_t)ifc32->ifc_buf; - ifc = &ifc_swab; - } -#endif /* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */ max_len = MAXPHYS - 1; @@ -2726,7 +2742,7 @@ again: max_len += sa->sa_len; } - if (!sbuf_overflowed(sb)) + if (sbuf_error(sb) == 0) valid_len = sbuf_len(sb); } IF_ADDR_UNLOCK(ifp); @@ -2735,7 +2751,7 @@ again: sbuf_bcat(sb, &ifr, sizeof(ifr)); max_len += sizeof(ifr); - if (!sbuf_overflowed(sb)) + if (sbuf_error(sb) == 0) valid_len = sbuf_len(sb); } } @@ -2752,10 +2768,6 @@ again: } ifc->ifc_len = valid_len; -#ifdef __amd64__ - if (cmd == SIOCGIFCONF32) - ifc32->ifc_len = valid_len; -#endif sbuf_finish(sb); error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); sbuf_delete(sb); diff --git a/sys/net/if.h b/sys/net/if.h index ae0daf5b639..a99b4a7c8ad 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -391,16 +391,6 @@ struct ifconf { #define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */ }; -#if defined (__amd64__) -struct ifconf32 { - int ifc_len; /* size of associated buffer */ - union { - u_int ifcu_buf; - u_int ifcu_req; - } ifc_ifcu; -}; -#endif - /* * interface groups */ diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c index 13907e42461..2f623308c3d 100644 --- a/sys/net/if_epair.c +++ b/sys/net/if_epair.c @@ -832,6 +832,8 @@ epair_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) /* Tell the world, that we are ready to rock. */ sca->ifp->if_drv_flags |= IFF_DRV_RUNNING; scb->ifp->if_drv_flags |= IFF_DRV_RUNNING; + if_link_state_change(sca->ifp, LINK_STATE_UP); + if_link_state_change(scb->ifp, LINK_STATE_UP); return (0); } @@ -859,6 +861,8 @@ epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) scb = oifp->if_softc; DPRINTF("ifp=%p oifp=%p\n", ifp, oifp); + if_link_state_change(ifp, LINK_STATE_DOWN); + if_link_state_change(oifp, LINK_STATE_DOWN); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; oifp->if_drv_flags &= ~IFF_DRV_RUNNING; ether_ifdetach(oifp); @@ -888,9 +892,9 @@ epair_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) * we need to switch before freeing them. */ CURVNET_SET_QUIET(oifp->if_vnet); - if_free_type(oifp, IFT_ETHER); + if_free(oifp); CURVNET_RESTORE(); - if_free_type(ifp, IFT_ETHER); + if_free(ifp); free(scb, M_EPAIR); free(sca, M_EPAIR); ifc_free_unit(ifc, unit); diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c index cb146015fa7..8911cee1426 100644 --- a/sys/net/if_lagg.c +++ b/sys/net/if_lagg.c @@ -162,6 +162,14 @@ static const struct { { LAGG_PROTO_NONE, NULL } }; +SYSCTL_DECL(_net_link); +SYSCTL_NODE(_net_link, OID_AUTO, lagg, CTLFLAG_RW, 0, "Link Aggregation"); + +static int lagg_failover_rx_all = 0; /* Allow input on any failover links */ +SYSCTL_INT(_net_link_lagg, OID_AUTO, failover_rx_all, CTLFLAG_RW, + &lagg_failover_rx_all, 0, + "Accept input from any interface in a failover lagg"); + static int lagg_modevent(module_t mod, int type, void *data) { @@ -1560,7 +1568,7 @@ lagg_fail_input(struct lagg_softc *sc, struct lagg_port *lp, struct mbuf *m) struct ifnet *ifp = sc->sc_ifp; struct lagg_port *tmp_tp; - if (lp == sc->sc_primary) { + if (lp == sc->sc_primary || lagg_failover_rx_all) { m->m_pkthdr.rcvif = ifp; return (m); } diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c index d516dbc5acc..a0fb071d6f1 100644 --- a/sys/net/if_llatbl.c +++ b/sys/net/if_llatbl.c @@ -183,6 +183,7 @@ lltable_free(struct lltable *llt) free(llt, M_LLTABLE); } +#if 0 void lltable_drain(int af) { @@ -197,15 +198,18 @@ lltable_drain(int af) for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { + LLE_WLOCK(lle); if (lle->la_hold) { m_freem(lle->la_hold); lle->la_hold = NULL; } + LLE_WUNLOCK(lle); } } } LLTABLE_RUNLOCK(); } +#endif void lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask) diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h index debb416ca06..a4d02ab0790 100644 --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -186,7 +186,9 @@ struct lltable *lltable_init(struct ifnet *, int); void lltable_free(struct lltable *); void lltable_prefix_free(int, struct sockaddr *, struct sockaddr *); +#if 0 void lltable_drain(int); +#endif int lltable_sysctl_dumparp(int, struct sysctl_req *); void llentry_free(struct llentry *); diff --git a/sys/net/if_tap.c b/sys/net/if_tap.c index eb81e816dd9..ad29da04499 100644 --- a/sys/net/if_tap.c +++ b/sys/net/if_tap.c @@ -132,7 +132,7 @@ static struct filterops tap_write_filterops = { static struct cdevsw tap_cdevsw = { .d_version = D_VERSION, - .d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR, + .d_flags = D_PSEUDO | D_NEEDMINOR, .d_open = tapopen, .d_close = tapclose, .d_read = tapread, @@ -209,7 +209,6 @@ static void tap_destroy(struct tap_softc *tp) { struct ifnet *ifp = tp->tap_ifp; - int s; /* Unlocked read. */ KASSERT(!(tp->tap_flags & TAP_OPEN), @@ -217,10 +216,8 @@ tap_destroy(struct tap_softc *tp) knlist_destroy(&tp->tap_rsel.si_note); destroy_dev(tp->tap_dev); - s = splimp(); ether_ifdetach(ifp); if_free_type(ifp, IFT_ETHER); - splx(s); mtx_destroy(&tp->tap_mtx); free(tp, M_TAP); @@ -398,7 +395,7 @@ tapcreate(struct cdev *dev) struct tap_softc *tp = NULL; unsigned short macaddr_hi; uint32_t macaddr_mid; - int unit, s; + int unit; char *name = NULL; u_char eaddr[6]; @@ -442,22 +439,20 @@ tapcreate(struct cdev *dev) ifp->if_ioctl = tapifioctl; ifp->if_mtu = ETHERMTU; ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); - ifp->if_snd.ifq_maxlen = ifqmaxlen; + IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_capabilities |= IFCAP_LINKSTATE; ifp->if_capenable |= IFCAP_LINKSTATE; dev->si_drv1 = tp; tp->tap_dev = dev; - s = splimp(); ether_ifattach(ifp, eaddr); - splx(s); mtx_lock(&tp->tap_mtx); tp->tap_flags |= TAP_INITED; mtx_unlock(&tp->tap_mtx); - knlist_init_mtx(&tp->tap_rsel.si_note, NULL); + knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx); TAPDEBUG("interface %s is created. minor = %#x\n", ifp->if_xname, dev2unit(dev)); @@ -474,7 +469,7 @@ tapopen(struct cdev *dev, int flag, int mode, struct thread *td) { struct tap_softc *tp = NULL; struct ifnet *ifp = NULL; - int error, s; + int error; if (tapuopen == 0) { error = priv_check(td, PRIV_NET_TAP); @@ -497,15 +492,13 @@ tapopen(struct cdev *dev, int flag, int mode, struct thread *td) tp->tap_pid = td->td_proc->p_pid; tp->tap_flags |= TAP_OPEN; ifp = tp->tap_ifp; - mtx_unlock(&tp->tap_mtx); - s = splimp(); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (tapuponopen) ifp->if_flags |= IFF_UP; if_link_state_change(ifp, LINK_STATE_UP); - splx(s); + mtx_unlock(&tp->tap_mtx); TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev)); @@ -524,9 +517,9 @@ tapclose(struct cdev *dev, int foo, int bar, struct thread *td) struct ifaddr *ifa; struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; - int s; /* junk all pending output */ + mtx_lock(&tp->tap_mtx); IF_DRAIN(&ifp->if_snd); /* @@ -534,28 +527,26 @@ tapclose(struct cdev *dev, int foo, int bar, struct thread *td) * interface, if we are in VMnet mode. just close the device. */ - mtx_lock(&tp->tap_mtx); if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { mtx_unlock(&tp->tap_mtx); - s = splimp(); if_down(ifp); + mtx_lock(&tp->tap_mtx); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + mtx_unlock(&tp->tap_mtx); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { rtinit(ifa, (int)RTM_DELETE, 0); } if_purgeaddrs(ifp); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + mtx_lock(&tp->tap_mtx); } - splx(s); - } else - mtx_unlock(&tp->tap_mtx); + } if_link_state_change(ifp, LINK_STATE_DOWN); funsetown(&tp->tap_sigio); selwakeuppri(&tp->tap_rsel, PZERO+1); - KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); + KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); - mtx_lock(&tp->tap_mtx); tp->tap_flags &= ~TAP_OPEN; tp->tap_pid = 0; mtx_unlock(&tp->tap_mtx); @@ -580,8 +571,10 @@ tapifinit(void *xtp) TAPDEBUG("initializing %s\n", ifp->if_xname); + mtx_lock(&tp->tap_mtx); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + mtx_unlock(&tp->tap_mtx); /* attempt to start output */ tapifstart(ifp); @@ -599,7 +592,7 @@ tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct tap_softc *tp = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct ifstat *ifs = NULL; - int s, dummy; + int dummy; switch (cmd) { case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ @@ -612,7 +605,6 @@ tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; case SIOCGIFSTATUS: - s = splimp(); ifs = (struct ifstat *)data; dummy = strlen(ifs->ascii); mtx_lock(&tp->tap_mtx); @@ -621,14 +613,10 @@ tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sizeof(ifs->ascii) - dummy, "\tOpened by PID %d\n", tp->tap_pid); mtx_unlock(&tp->tap_mtx); - splx(s); break; default: - s = splimp(); - dummy = ether_ioctl(ifp, cmd, data); - splx(s); - return (dummy); + return (ether_ioctl(ifp, cmd, data)); /* NOT REACHED */ } @@ -645,7 +633,6 @@ static void tapifstart(struct ifnet *ifp) { struct tap_softc *tp = ifp->if_softc; - int s; TAPDEBUG("%s starting\n", ifp->if_xname); @@ -657,32 +644,28 @@ tapifstart(struct ifnet *ifp) mtx_lock(&tp->tap_mtx); if (((tp->tap_flags & TAP_VMNET) == 0) && ((tp->tap_flags & TAP_READY) != TAP_READY)) { - struct mbuf *m = NULL; - - mtx_unlock(&tp->tap_mtx); + struct mbuf *m; /* Unlocked read. */ TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, tp->tap_flags); - s = splimp(); - do { + for (;;) { IF_DEQUEUE(&ifp->if_snd, m); - if (m != NULL) + if (m != NULL) { m_freem(m); - ifp->if_oerrors ++; - } while (m != NULL); - splx(s); + ifp->if_oerrors++; + } else + break; + } + mtx_unlock(&tp->tap_mtx); return; } - mtx_unlock(&tp->tap_mtx); - s = splimp(); ifp->if_drv_flags |= IFF_DRV_OACTIVE; - if (ifp->if_snd.ifq_len != 0) { - mtx_lock(&tp->tap_mtx); + if (!IFQ_IS_EMPTY(&ifp->if_snd)) { if (tp->tap_flags & TAP_RWAIT) { tp->tap_flags &= ~TAP_RWAIT; wakeup(tp); @@ -691,16 +674,16 @@ tapifstart(struct ifnet *ifp) if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) { mtx_unlock(&tp->tap_mtx); pgsigio(&tp->tap_sigio, SIGIO, 0); - } else - mtx_unlock(&tp->tap_mtx); + mtx_lock(&tp->tap_mtx); + } selwakeuppri(&tp->tap_rsel, PZERO+1); - KNOTE_UNLOCKED(&tp->tap_rsel.si_note, 0); + KNOTE_LOCKED(&tp->tap_rsel.si_note, 0); ifp->if_opackets ++; /* obytes are counted in ether_output */ } ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - splx(s); + mtx_unlock(&tp->tap_mtx); } /* tapifstart */ @@ -715,7 +698,6 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; struct tapinfo *tapp = NULL; - int s; int f; #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) @@ -724,19 +706,21 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td switch (cmd) { case TAPSIFINFO: - s = splimp(); tapp = (struct tapinfo *)data; + mtx_lock(&tp->tap_mtx); ifp->if_mtu = tapp->mtu; ifp->if_type = tapp->type; ifp->if_baudrate = tapp->baudrate; - splx(s); + mtx_unlock(&tp->tap_mtx); break; case TAPGIFINFO: tapp = (struct tapinfo *)data; + mtx_lock(&tp->tap_mtx); tapp->mtu = ifp->if_mtu; tapp->type = ifp->if_type; tapp->baudrate = ifp->if_baudrate; + mtx_unlock(&tp->tap_mtx); break; case TAPSDEBUG: @@ -757,26 +741,26 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td break; case FIOASYNC: - s = splimp(); mtx_lock(&tp->tap_mtx); if (*(int *)data) tp->tap_flags |= TAP_ASYNC; else tp->tap_flags &= ~TAP_ASYNC; mtx_unlock(&tp->tap_mtx); - splx(s); break; case FIONREAD: - s = splimp(); - if (ifp->if_snd.ifq_head) { - struct mbuf *mb = ifp->if_snd.ifq_head; + if (!IFQ_IS_EMPTY(&ifp->if_snd)) { + struct mbuf *mb; - for(*(int *)data = 0;mb != NULL;mb = mb->m_next) + IFQ_LOCK(&ifp->if_snd); + IFQ_POLL_NOLOCK(&ifp->if_snd, mb); + for (*(int *)data = 0; mb != NULL; + mb = mb->m_next) *(int *)data += mb->m_len; + IFQ_UNLOCK(&ifp->if_snd); } else *(int *)data = 0; - splx(s); break; case FIOSETOWN: @@ -797,10 +781,6 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td /* VMware/VMnet port ioctl's */ - case SIOCGIFFLAGS: /* get ifnet flags */ - bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); - break; - #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD4) case _IO('V', 0): @@ -814,9 +794,9 @@ tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td f &= ~IFF_CANTCHANGE; f |= IFF_UP; - s = splimp(); + mtx_lock(&tp->tap_mtx); ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); - splx(s); + mtx_unlock(&tp->tap_mtx); break; case OSIOCGIFADDR: /* get MAC address of the remote side */ @@ -851,7 +831,7 @@ tapread(struct cdev *dev, struct uio *uio, int flag) struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; struct mbuf *m = NULL; - int error = 0, len, s; + int error = 0, len; TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev)); @@ -867,26 +847,27 @@ tapread(struct cdev *dev, struct uio *uio, int flag) } tp->tap_flags &= ~TAP_RWAIT; - mtx_unlock(&tp->tap_mtx); /* sleep until we get a packet */ do { - s = splimp(); IF_DEQUEUE(&ifp->if_snd, m); - splx(s); if (m == NULL) { - if (flag & O_NONBLOCK) + if (flag & O_NONBLOCK) { + mtx_unlock(&tp->tap_mtx); return (EWOULDBLOCK); + } - mtx_lock(&tp->tap_mtx); tp->tap_flags |= TAP_RWAIT; - mtx_unlock(&tp->tap_mtx); - error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0); - if (error) + error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1), + "taprd", 0); + if (error) { + mtx_unlock(&tp->tap_mtx); return (error); + } } } while (m == NULL); + mtx_unlock(&tp->tap_mtx); /* feed packet to bpf */ BPF_MTAP(ifp, m); @@ -982,14 +963,14 @@ tappoll(struct cdev *dev, int events, struct thread *td) { struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; - int s, revents = 0; + int revents = 0; TAPDEBUG("%s polling, minor = %#x\n", ifp->if_xname, dev2unit(dev)); - s = splimp(); if (events & (POLLIN | POLLRDNORM)) { - if (ifp->if_snd.ifq_len > 0) { + IFQ_LOCK(&ifp->if_snd); + if (!IFQ_IS_EMPTY(&ifp->if_snd)) { TAPDEBUG("%s have data in queue. len = %d, " \ "minor = %#x\n", ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev)); @@ -1001,12 +982,12 @@ tappoll(struct cdev *dev, int events, struct thread *td) selrecord(td, &tp->tap_rsel); } + IFQ_UNLOCK(&ifp->if_snd); } if (events & (POLLOUT | POLLWRNORM)) revents |= (events & (POLLOUT | POLLWRNORM)); - splx(s); return (revents); } /* tappoll */ @@ -1019,11 +1000,9 @@ tappoll(struct cdev *dev, int events, struct thread *td) static int tapkqfilter(struct cdev *dev, struct knote *kn) { - int s; struct tap_softc *tp = dev->si_drv1; struct ifnet *ifp = tp->tap_ifp; - s = splimp(); switch (kn->kn_filter) { case EVFILT_READ: TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n", @@ -1040,13 +1019,11 @@ tapkqfilter(struct cdev *dev, struct knote *kn) default: TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n", ifp->if_xname, dev2unit(dev)); - splx(s); return (EINVAL); /* NOT REACHED */ } - splx(s); - kn->kn_hook = (caddr_t) dev; + kn->kn_hook = tp; knlist_add(&tp->tap_rsel.si_note, kn, 0); return (0); @@ -1061,12 +1038,11 @@ tapkqfilter(struct cdev *dev, struct knote *kn) static int tapkqread(struct knote *kn, long hint) { - int ret, s; - struct cdev *dev = (struct cdev *)(kn->kn_hook); - struct tap_softc *tp = dev->si_drv1; + int ret; + struct tap_softc *tp = kn->kn_hook; + struct cdev *dev = tp->tap_dev; struct ifnet *ifp = tp->tap_ifp; - s = splimp(); if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n", ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev)); @@ -1076,7 +1052,6 @@ tapkqread(struct knote *kn, long hint) ifp->if_xname, dev2unit(dev)); ret = 0; } - splx(s); return (ret); } /* tapkqread */ @@ -1090,13 +1065,10 @@ tapkqread(struct knote *kn, long hint) static int tapkqwrite(struct knote *kn, long hint) { - int s; - struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; + struct tap_softc *tp = kn->kn_hook; struct ifnet *ifp = tp->tap_ifp; - s = splimp(); kn->kn_data = ifp->if_mtu; - splx(s); return (1); } /* tapkqwrite */ @@ -1105,7 +1077,7 @@ tapkqwrite(struct knote *kn, long hint) static void tapkqdetach(struct knote *kn) { - struct tap_softc *tp = ((struct cdev *) kn->kn_hook)->si_drv1; + struct tap_softc *tp = kn->kn_hook; knlist_remove(&tp->tap_rsel.si_note, kn, 0); } /* tapkqdetach */ diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c index 1da63ba3765..7c01ebe14cf 100644 --- a/sys/net/if_tun.c +++ b/sys/net/if_tun.c @@ -165,7 +165,7 @@ static struct filterops tun_write_filterops = { static struct cdevsw tun_cdevsw = { .d_version = D_VERSION, - .d_flags = D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR, + .d_flags = D_PSEUDO | D_NEEDMINOR, .d_open = tunopen, .d_close = tunclose, .d_read = tunread, @@ -344,13 +344,13 @@ tunstart(struct ifnet *ifp) tp->tun_flags &= ~TUN_RWAIT; wakeup(tp); } + selwakeuppri(&tp->tun_rsel, PZERO + 1); + KNOTE_LOCKED(&tp->tun_rsel.si_note, 0); if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio) { mtx_unlock(&tp->tun_mtx); pgsigio(&tp->tun_sigio, SIGIO, 0); } else mtx_unlock(&tp->tun_mtx); - selwakeuppri(&tp->tun_rsel, PZERO + 1); - KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0); } /* XXX: should return an error code so it can fail. */ @@ -385,7 +385,7 @@ tuncreate(const char *name, struct cdev *dev) IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = 0; IFQ_SET_READY(&ifp->if_snd); - knlist_init_mtx(&sc->tun_rsel.si_note, NULL); + knlist_init_mtx(&sc->tun_rsel.si_note, &sc->tun_mtx); ifp->if_capabilities |= IFCAP_LINKSTATE; ifp->if_capenable |= IFCAP_LINKSTATE; @@ -426,10 +426,10 @@ tunopen(struct cdev *dev, int flag, int mode, struct thread *td) tp->tun_pid = td->td_proc->p_pid; tp->tun_flags |= TUN_OPEN; - mtx_unlock(&tp->tun_mtx); ifp = TUN2IFP(tp); if_link_state_change(ifp, LINK_STATE_UP); TUNDEBUG(ifp, "open\n"); + mtx_unlock(&tp->tun_mtx); return (0); } @@ -443,7 +443,6 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) { struct tun_softc *tp; struct ifnet *ifp; - int s; tp = dev->si_drv1; ifp = TUN2IFP(tp); @@ -451,27 +450,25 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) mtx_lock(&tp->tun_mtx); tp->tun_flags &= ~TUN_OPEN; tp->tun_pid = 0; - mtx_unlock(&tp->tun_mtx); /* * junk all pending output */ CURVNET_SET(ifp->if_vnet); - s = splimp(); IFQ_PURGE(&ifp->if_snd); - splx(s); if (ifp->if_flags & IFF_UP) { - s = splimp(); + mtx_unlock(&tp->tun_mtx); if_down(ifp); - splx(s); + mtx_lock(&tp->tun_mtx); } /* Delete all addresses and routes which reference this interface. */ if (ifp->if_drv_flags & IFF_DRV_RUNNING) { struct ifaddr *ifa; - s = splimp(); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + mtx_unlock(&tp->tun_mtx); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { /* deal w/IPv4 PtP destination; unlocked read */ if (ifa->ifa_addr->sa_family == AF_INET) { @@ -482,16 +479,14 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) } } if_purgeaddrs(ifp); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - splx(s); + mtx_lock(&tp->tun_mtx); } if_link_state_change(ifp, LINK_STATE_DOWN); CURVNET_RESTORE(); - mtx_lock(&tp->tun_mtx); funsetown(&tp->tun_sigio); selwakeuppri(&tp->tun_rsel, PZERO + 1); - KNOTE_UNLOCKED(&tp->tun_rsel.si_note, 0); + KNOTE_LOCKED(&tp->tun_rsel.si_note, 0); TUNDEBUG (ifp, "closed\n"); cv_broadcast(&tp->tun_cv); @@ -502,14 +497,15 @@ tunclose(struct cdev *dev, int foo, int bar, struct thread *td) static int tuninit(struct ifnet *ifp) { -#ifdef INET struct tun_softc *tp = ifp->if_softc; +#ifdef INET struct ifaddr *ifa; #endif int error = 0; TUNDEBUG(ifp, "tuninit\n"); + mtx_lock(&tp->tun_mtx); ifp->if_flags |= IFF_UP; ifp->if_drv_flags |= IFF_DRV_RUNNING; getmicrotime(&ifp->if_lastchange); @@ -521,18 +517,17 @@ tuninit(struct ifnet *ifp) struct sockaddr_in *si; si = (struct sockaddr_in *)ifa->ifa_addr; - mtx_lock(&tp->tun_mtx); if (si->sin_addr.s_addr) tp->tun_flags |= TUN_IASET; si = (struct sockaddr_in *)ifa->ifa_dstaddr; if (si && si->sin_addr.s_addr) tp->tun_flags |= TUN_DSTADDR; - mtx_unlock(&tp->tun_mtx); } } if_addr_runlock(ifp); #endif + mtx_unlock(&tp->tun_mtx); return (error); } @@ -545,9 +540,8 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ifreq *ifr = (struct ifreq *)data; struct tun_softc *tp = ifp->if_softc; struct ifstat *ifs; - int error = 0, s; + int error = 0; - s = splimp(); switch(cmd) { case SIOCGIFSTATUS: ifs = (struct ifstat *)data; @@ -576,7 +570,6 @@ tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data) default: error = EINVAL; } - splx(s); return (error); } @@ -682,7 +675,6 @@ tunoutput( static int tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) { - int s; int error; struct tun_softc *tp = dev->si_drv1; struct tuninfo *tunp; @@ -697,15 +689,19 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td if (error) return (error); } + mtx_lock(&tp->tun_mtx); TUN2IFP(tp)->if_mtu = tunp->mtu; TUN2IFP(tp)->if_type = tunp->type; TUN2IFP(tp)->if_baudrate = tunp->baudrate; + mtx_unlock(&tp->tun_mtx); break; case TUNGIFINFO: tunp = (struct tuninfo *)data; + mtx_lock(&tp->tun_mtx); tunp->mtu = TUN2IFP(tp)->if_mtu; tunp->type = TUN2IFP(tp)->if_type; tunp->baudrate = TUN2IFP(tp)->if_baudrate; + mtx_unlock(&tp->tun_mtx); break; case TUNSDEBUG: tundebug = *(int *)data; @@ -732,7 +728,6 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td mtx_unlock(&tp->tun_mtx); break; case TUNGIFHEAD: - /* Could be unlocked read? */ mtx_lock(&tp->tun_mtx); *(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0; mtx_unlock(&tp->tun_mtx); @@ -745,9 +740,11 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td switch (*(int *)data & ~IFF_MULTICAST) { case IFF_POINTOPOINT: case IFF_BROADCAST: + mtx_lock(&tp->tun_mtx); TUN2IFP(tp)->if_flags &= ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST); TUN2IFP(tp)->if_flags |= *(int *)data; + mtx_unlock(&tp->tun_mtx); break; default: return(EINVAL); @@ -769,17 +766,15 @@ tunioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td mtx_unlock(&tp->tun_mtx); break; case FIONREAD: - s = splimp(); if (!IFQ_IS_EMPTY(&TUN2IFP(tp)->if_snd)) { struct mbuf *mb; IFQ_LOCK(&TUN2IFP(tp)->if_snd); IFQ_POLL_NOLOCK(&TUN2IFP(tp)->if_snd, mb); - for( *(int *)data = 0; mb != 0; mb = mb->m_next) + for (*(int *)data = 0; mb != NULL; mb = mb->m_next) *(int *)data += mb->m_len; IFQ_UNLOCK(&TUN2IFP(tp)->if_snd); } else *(int *)data = 0; - splx(s); break; case FIOSETOWN: return (fsetown(*(int *)data, &tp->tun_sigio)); @@ -813,7 +808,7 @@ tunread(struct cdev *dev, struct uio *uio, int flag) struct tun_softc *tp = dev->si_drv1; struct ifnet *ifp = TUN2IFP(tp); struct mbuf *m; - int error=0, len, s; + int error=0, len; TUNDEBUG (ifp, "read\n"); mtx_lock(&tp->tun_mtx); @@ -824,27 +819,24 @@ tunread(struct cdev *dev, struct uio *uio, int flag) } tp->tun_flags &= ~TUN_RWAIT; - mtx_unlock(&tp->tun_mtx); - s = splimp(); do { IFQ_DEQUEUE(&ifp->if_snd, m); if (m == NULL) { if (flag & O_NONBLOCK) { - splx(s); + mtx_unlock(&tp->tun_mtx); return (EWOULDBLOCK); } - mtx_lock(&tp->tun_mtx); tp->tun_flags |= TUN_RWAIT; - mtx_unlock(&tp->tun_mtx); - if ((error = tsleep(tp, PCATCH | (PZERO + 1), - "tunread", 0)) != 0) { - splx(s); + error = mtx_sleep(tp, &tp->tun_mtx, PCATCH | (PZERO + 1), + "tunread", 0); + if (error != 0) { + mtx_unlock(&tp->tun_mtx); return (error); } } } while (m == NULL); - splx(s); + mtx_unlock(&tp->tun_mtx); while (m && uio->uio_resid > 0 && error == 0) { len = min(uio->uio_resid, m->m_len); @@ -957,13 +949,11 @@ tunwrite(struct cdev *dev, struct uio *uio, int flag) static int tunpoll(struct cdev *dev, int events, struct thread *td) { - int s; struct tun_softc *tp = dev->si_drv1; struct ifnet *ifp = TUN2IFP(tp); int revents = 0; struct mbuf *m; - s = splimp(); TUNDEBUG(ifp, "tunpoll\n"); if (events & (POLLIN | POLLRDNORM)) { @@ -981,7 +971,6 @@ tunpoll(struct cdev *dev, int events, struct thread *td) if (events & (POLLOUT | POLLWRNORM)) revents |= events & (POLLOUT | POLLWRNORM); - splx(s); return (revents); } @@ -991,11 +980,9 @@ tunpoll(struct cdev *dev, int events, struct thread *td) static int tunkqfilter(struct cdev *dev, struct knote *kn) { - int s; struct tun_softc *tp = dev->si_drv1; struct ifnet *ifp = TUN2IFP(tp); - s = splimp(); switch(kn->kn_filter) { case EVFILT_READ: TUNDEBUG(ifp, "%s kqfilter: EVFILT_READ, minor = %#x\n", @@ -1012,12 +999,10 @@ tunkqfilter(struct cdev *dev, struct knote *kn) default: TUNDEBUG(ifp, "%s kqfilter: invalid filter, minor = %#x\n", ifp->if_xname, dev2unit(dev)); - splx(s); return(EINVAL); } - splx(s); - kn->kn_hook = (caddr_t) dev; + kn->kn_hook = tp; knlist_add(&tp->tun_rsel.si_note, kn, 0); return (0); @@ -1029,12 +1014,11 @@ tunkqfilter(struct cdev *dev, struct knote *kn) static int tunkqread(struct knote *kn, long hint) { - int ret, s; - struct cdev *dev = (struct cdev *)(kn->kn_hook); - struct tun_softc *tp = dev->si_drv1; + int ret; + struct tun_softc *tp = kn->kn_hook; + struct cdev *dev = tp->tun_dev; struct ifnet *ifp = TUN2IFP(tp); - s = splimp(); if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) { TUNDEBUG(ifp, "%s have data in the queue. Len = %d, minor = %#x\n", @@ -1046,7 +1030,6 @@ tunkqread(struct knote *kn, long hint) dev2unit(dev)); ret = 0; } - splx(s); return (ret); } @@ -1057,13 +1040,10 @@ tunkqread(struct knote *kn, long hint) static int tunkqwrite(struct knote *kn, long hint) { - int s; - struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct tun_softc *tp = kn->kn_hook; struct ifnet *ifp = TUN2IFP(tp); - s = splimp(); kn->kn_data = ifp->if_mtu; - splx(s); return (1); } @@ -1071,7 +1051,7 @@ tunkqwrite(struct knote *kn, long hint) static void tunkqdetach(struct knote *kn) { - struct tun_softc *tp = ((struct cdev *)kn->kn_hook)->si_drv1; + struct tun_softc *tp = kn->kn_hook; knlist_remove(&tp->tun_rsel.si_note, kn, 0); } diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index ae72bd9bd89..f2b0369022e 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -1473,6 +1473,7 @@ sysctl_iflist(int af, struct walkarg *w) TAILQ_FOREACH(ifp, &V_ifnet, if_link) { if (w->w_arg && w->w_arg != ifp->if_index) continue; + IF_ADDR_LOCK(ifp); ifa = ifp->if_addr; info.rti_info[RTAX_IFP] = ifa->ifa_addr; len = rt_msg2(RTM_IFINFO, &info, NULL, w); @@ -1530,10 +1531,13 @@ sysctl_iflist(int af, struct walkarg *w) goto done; } } + IF_ADDR_UNLOCK(ifp); info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = info.rti_info[RTAX_BRD] = NULL; } done: + if (ifp != NULL) + IF_ADDR_UNLOCK(ifp); IFNET_RUNLOCK(); return (error); } diff --git a/sys/net/vnet.c b/sys/net/vnet.c index fb0db347b32..8fc52b22798 100644 --- a/sys/net/vnet.c +++ b/sys/net/vnet.c @@ -208,11 +208,15 @@ static TAILQ_HEAD(, vnet_data_free) vnet_data_free_head = static struct sx vnet_data_free_lock; SDT_PROVIDER_DEFINE(vnet); -SDT_PROBE_DEFINE1(vnet, functions, vnet_alloc, entry, "int"); -SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, alloc, "int", "struct vnet *"); -SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, return, "int", "struct vnet *"); -SDT_PROBE_DEFINE2(vnet, functions, vnet_destroy, entry, "int", "struct vnet *"); -SDT_PROBE_DEFINE1(vnet, functions, vnet_destroy, return, "int"); +SDT_PROBE_DEFINE1(vnet, functions, vnet_alloc, entry, entry, "int"); +SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, alloc, alloc, "int", + "struct vnet *"); +SDT_PROBE_DEFINE2(vnet, functions, vnet_alloc, return, return, + "int", "struct vnet *"); +SDT_PROBE_DEFINE2(vnet, functions, vnet_destroy, entry, entry, + "int", "struct vnet *"); +SDT_PROBE_DEFINE1(vnet, functions, vnet_destroy, return, entry, + "int"); #ifdef DDB static void db_show_vnet_print_vs(struct vnet_sysinit *, int); diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index e3c2769259f..2dc48712f03 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1404,7 +1404,8 @@ ieee80211_fakeup_adhoc_node(struct ieee80211vap *vap, #endif } ieee80211_node_setuptxparms(ni); - ieee80211_ratectl_node_init(ni); + if (vap->iv_caps & IEEE80211_C_RATECTL) + ieee80211_ratectl_node_init(ni); if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, 1); /* XXX not right for 802.1x/WPA */ @@ -1474,7 +1475,8 @@ ieee80211_add_neighbor(struct ieee80211vap *vap, if (ieee80211_iserp_rateset(&ni->ni_rates)) ni->ni_flags |= IEEE80211_NODE_ERP; ieee80211_node_setuptxparms(ni); - ieee80211_ratectl_node_init(ni); + if (vap->iv_caps & IEEE80211_C_RATECTL) + ieee80211_ratectl_node_init(ni); if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, 1); /* XXX not right for 802.1x/WPA */ @@ -2343,7 +2345,8 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp) ); ieee80211_node_setuptxparms(ni); - ieee80211_ratectl_node_init(ni); + if (vap->iv_caps & IEEE80211_C_RATECTL) + ieee80211_ratectl_node_init(ni); /* give driver a chance to setup state like ni_txrate */ if (ic->ic_newassoc != NULL) ic->ic_newassoc(ni, newassoc); diff --git a/sys/net80211/ieee80211_ratectl.c b/sys/net80211/ieee80211_ratectl.c index 2e8eb7e2153..ea3d8d412c5 100644 --- a/sys/net80211/ieee80211_ratectl.c +++ b/sys/net80211/ieee80211_ratectl.c @@ -39,6 +39,14 @@ __FBSDID("$FreeBSD$"); static const struct ieee80211_ratectl *ratectls[IEEE80211_RATECTL_MAX]; +static const char *ratectl_modnames[IEEE80211_RATECTL_MAX] = { + [IEEE80211_RATECTL_AMRR] = "wlan_amrr", + [IEEE80211_RATECTL_RSSADAPT] = "wlan_rssadapt", + [IEEE80211_RATECTL_ONOE] = "wlan_onoe", + [IEEE80211_RATECTL_SAMPLE] = "wlan_sample", + [IEEE80211_RATECTL_NONE] = "wlan_none", +}; + MALLOC_DEFINE(M_80211_RATECTL, "80211ratectl", "802.11 rate control"); void @@ -62,5 +70,15 @@ ieee80211_ratectl_set(struct ieee80211vap *vap, int type) { if (type >= IEEE80211_RATECTL_MAX) return; + if (ratectls[type] == NULL) { + ieee80211_load_module(ratectl_modnames[type]); + if (ratectls[type] == NULL) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_RATECTL, + "%s: unable to load algo %u, module %s\n", + __func__, type, ratectl_modnames[type]); + vap->iv_rate = ratectls[IEEE80211_RATECTL_NONE]; + return; + } + } vap->iv_rate = ratectls[type]; } diff --git a/sys/net80211/ieee80211_ratectl.h b/sys/net80211/ieee80211_ratectl.h index 73b4f321650..87b26984dc0 100644 --- a/sys/net80211/ieee80211_ratectl.h +++ b/sys/net80211/ieee80211_ratectl.h @@ -26,10 +26,11 @@ */ enum ieee80211_ratealgs { - IEEE80211_RATECTL_AMRR = 0, + IEEE80211_RATECTL_AMRR = 0, IEEE80211_RATECTL_RSSADAPT = 1, IEEE80211_RATECTL_ONOE = 2, IEEE80211_RATECTL_SAMPLE = 3, + IEEE80211_RATECTL_NONE = 4, IEEE80211_RATECTL_MAX }; diff --git a/sys/net80211/ieee80211_ratectl_none.c b/sys/net80211/ieee80211_ratectl_none.c new file mode 100644 index 00000000000..0979e9d942c --- /dev/null +++ b/sys/net80211/ieee80211_ratectl_none.c @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 2010 Bernhard Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef INET +#include +#include +#endif + +#include +#include + +static void +none_init(struct ieee80211vap *vap) +{ +} + +static void +none_deinit(struct ieee80211vap *vap) +{ + free(vap->iv_rs, M_80211_RATECTL); +} + +static void +none_node_init(struct ieee80211_node *ni) +{ +} + +static void +none_node_deinit(struct ieee80211_node *ni) +{ +} + +static int +none_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) +{ + int rix = 0; + + ni->ni_txrate = ni->ni_rates.rs_rates[rix] & IEEE80211_RATE_VAL; + return rix; +} + +static void +none_tx_complete(const struct ieee80211vap *vap, + const struct ieee80211_node *ni, int ok, + void *arg1, void *arg2 __unused) +{ +} + +static void +none_tx_update(const struct ieee80211vap *vap, const struct ieee80211_node *ni, + void *arg1, void *arg2, void *arg3) +{ +} + +static void +none_setinterval(const struct ieee80211vap *vap, int msecs) +{ +} + +/* number of references from net80211 layer */ +static int nrefs = 0; + +static const struct ieee80211_ratectl none = { + .ir_name = "none", + .ir_attach = NULL, + .ir_detach = NULL, + .ir_init = none_init, + .ir_deinit = none_deinit, + .ir_node_init = none_node_init, + .ir_node_deinit = none_node_deinit, + .ir_rate = none_rate, + .ir_tx_complete = none_tx_complete, + .ir_tx_update = none_tx_update, + .ir_setinterval = none_setinterval, +}; +IEEE80211_RATECTL_MODULE(ratectl_none, 1); +IEEE80211_RATECTL_ALG(none, IEEE80211_RATECTL_NONE, none); diff --git a/sys/net80211/ieee80211_scan_sta.c b/sys/net80211/ieee80211_scan_sta.c index 294a63e3b2d..a1d0c42324c 100644 --- a/sys/net80211/ieee80211_scan_sta.c +++ b/sys/net80211/ieee80211_scan_sta.c @@ -1361,7 +1361,7 @@ sta_age(struct ieee80211_scan_state *ss) KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode %u", vap->iv_opmode)); if (vap->iv_roaming == IEEE80211_ROAMING_AUTO && - (vap->iv_ic->ic_flags & IEEE80211_F_BGSCAN) && + (vap->iv_flags & IEEE80211_F_BGSCAN) && vap->iv_state >= IEEE80211_S_RUN) /* XXX vap is implicit */ sta_roam_check(ss, vap); diff --git a/sys/netgraph/ng_UI.c b/sys/netgraph/ng_UI.c index a8968776f84..2c3f132092e 100644 --- a/sys/netgraph/ng_UI.c +++ b/sys/netgraph/ng_UI.c @@ -197,7 +197,7 @@ ng_UI_rcvdata(hook_p hook, item_p item) mtod(m, u_char *)[0] = HDLC_UI; NG_FWD_NEW_DATA(error, item, priv->downlink, m); /* m -> NULL */ } else - panic(__func__); + panic("%s", __func__); done: NG_FREE_M(m); /* does nothing if m == NULL */ @@ -234,7 +234,7 @@ ng_UI_disconnect(hook_p hook) else if (hook == priv->uplink) priv->uplink = NULL; else - panic(__func__); + panic("%s", __func__); /* * If we are not already shutting down, * and we have no more hooks, then DO shut down. diff --git a/sys/netgraph/ng_async.c b/sys/netgraph/ng_async.c index 77c96df6d46..acbd76aefdc 100644 --- a/sys/netgraph/ng_async.c +++ b/sys/netgraph/ng_async.c @@ -256,7 +256,7 @@ nga_rcvdata(hook_p hook, item_p item) return (nga_rcv_sync(sc, item)); if (hook == sc->async) return (nga_rcv_async(sc, item)); - panic(__func__); + panic("%s", __func__); } /* @@ -372,7 +372,7 @@ nga_disconnect(hook_p hook) else if (hook == sc->sync) hookp = &sc->sync; else - panic(__func__); + panic("%s", __func__); if (!*hookp) panic("%s 2", __func__); *hookp = NULL; diff --git a/sys/netgraph/ng_frame_relay.c b/sys/netgraph/ng_frame_relay.c index 599e80ee310..670ef17a1b2 100644 --- a/sys/netgraph/ng_frame_relay.c +++ b/sys/netgraph/ng_frame_relay.c @@ -396,7 +396,7 @@ ngfrm_rcvdata(hook_p hook, item_p item) data[3] |= BYTEX_EA; break; default: - panic(__func__); + panic("%s", __func__); } /* Send it */ diff --git a/sys/netgraph/ng_gif_demux.c b/sys/netgraph/ng_gif_demux.c index a5ac5e149a4..3e882199c3d 100644 --- a/sys/netgraph/ng_gif_demux.c +++ b/sys/netgraph/ng_gif_demux.c @@ -391,7 +391,7 @@ ng_gif_demux_disconnect(hook_p hook) else { iffam = get_iffam_from_hook(priv, hook); if (iffam == NULL) - panic(__func__); + panic("%s", __func__); *get_hook_from_iffam(priv, iffam) = NULL; } diff --git a/sys/netgraph/ng_iface.c b/sys/netgraph/ng_iface.c index f94fd14930f..03ad016c2ab 100644 --- a/sys/netgraph/ng_iface.c +++ b/sys/netgraph/ng_iface.c @@ -821,7 +821,7 @@ ng_iface_disconnect(hook_p hook) const iffam_p iffam = get_iffam_from_hook(priv, hook); if (iffam == NULL) - panic(__func__); + panic("%s", __func__); *get_hook_from_iffam(priv, iffam) = NULL; return (0); } diff --git a/sys/netgraph/ng_rfc1490.c b/sys/netgraph/ng_rfc1490.c index 99f8641cdd4..fff7c28aa48 100644 --- a/sys/netgraph/ng_rfc1490.c +++ b/sys/netgraph/ng_rfc1490.c @@ -440,7 +440,7 @@ switch_on_etype: etype = ntohs(*((const u_int16_t *)ptr)); mtod(m, u_char *)[7] = 0x07; NG_FWD_NEW_DATA(error, item, priv->downlink, m); } else - panic(__func__); + panic("%s", __func__); done: if (item) @@ -485,7 +485,7 @@ ng_rfc1490_disconnect(hook_p hook) else if (hook == priv->ethernet) priv->ethernet = NULL; else - panic(__func__); + panic("%s", __func__); return (0); } diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c index 8080f689344..50b53181e85 100644 --- a/sys/netgraph/ng_socket.c +++ b/sys/netgraph/ng_socket.c @@ -621,7 +621,7 @@ ng_detach_common(struct ngpcb *pcbp, int which) priv->datasock = NULL; break; default: - panic(__func__); + panic("%s", __func__); } pcbp->sockdata = NULL; diff --git a/sys/netgraph/ng_tty.c b/sys/netgraph/ng_tty.c index 84083170d8a..492d21b8bfd 100644 --- a/sys/netgraph/ng_tty.c +++ b/sys/netgraph/ng_tty.c @@ -211,7 +211,7 @@ ngt_disconnect(hook_p hook) const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); if (hook != sc->hook) - panic(__func__); + panic("%s", __func__); NGTLOCK(sc); sc->hook = NULL; @@ -317,7 +317,7 @@ ngt_rcvdata(hook_p hook, item_p item) struct mbuf *m; if (hook != sc->hook) - panic(__func__); + panic("%s", __func__); NGI_GET_M(item, m); NG_FREE_ITEM(item); diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c index d4c8e99cdab..b02d30beb63 100644 --- a/sys/netinet/igmp.c +++ b/sys/netinet/igmp.c @@ -1219,8 +1219,8 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, if (ifp->if_flags & IFF_LOOPBACK) return (0); - if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr) || - !in_hosteq(igmp->igmp_group, ip->ip_dst))) { + if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || + !in_hosteq(igmp->igmp_group, ip->ip_dst)) { IGMPSTAT_INC(igps_rcv_badreports); return (EINVAL); } diff --git a/sys/netinet/in.c b/sys/netinet/in.c index b5873d85064..b2ae8d94f54 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -599,6 +599,21 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, } IF_ADDR_LOCK(ifp); + /* Re-check that ia is still part of the list. */ + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa == &ia->ia_ifa) + break; + } + if (ifa == NULL) { + /* + * If we lost the race with another thread, there is no need to + * try it again for the next loop as there is no other exit + * path between here and out. + */ + IF_ADDR_UNLOCK(ifp); + error = EADDRNOTAVAIL; + goto out; + } TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); IF_ADDR_UNLOCK(ifp); ifa_free(&ia->ia_ifa); /* if_addrhead */ @@ -1039,9 +1054,10 @@ in_addprefix(struct in_ifaddr *target, int flags) if (ia->ia_flags & IFA_ROUTE) { #ifdef RADIX_MPATH if (ia->ia_addr.sin_addr.s_addr == - target->ia_addr.sin_addr.s_addr) + target->ia_addr.sin_addr.s_addr) { + IN_IFADDR_RUNLOCK(); return (EEXIST); - else + } else break; #endif if (V_sameprefixcarponly && diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 9eb3b177c16..d5e42905986 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -252,6 +252,7 @@ __END_DECLS /* Only used internally, so can be outside the range of valid IP protocols. */ #define IPPROTO_DIVERT 258 /* divert pseudo-protocol */ +#define IPPROTO_SEND 259 /* SeND pseudo-protocol */ /* * Defined to avoid confusion. The master value is defined by @@ -725,6 +726,8 @@ int in_localip(struct in_addr); int inet_aton(const char *, struct in_addr *); /* in libkern */ char *inet_ntoa(struct in_addr); /* in libkern */ char *inet_ntoa_r(struct in_addr ina, char *buf); /* in libkern */ +char *inet_ntop(int, const void *, char *, socklen_t); /* in libkern */ +int inet_pton(int af, const char *, void *); /* in libkern */ void in_ifdetach(struct ifnet *); #define in_hosteq(s, t) ((s).s_addr == (t).s_addr) diff --git a/sys/netinet/in_debug.c b/sys/netinet/in_debug.c new file mode 100644 index 00000000000..7624f1deedf --- /dev/null +++ b/sys/netinet/in_debug.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2010 Bjoern A. Zeeb + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include +#include +#include + +#ifdef DDB +#include +#endif + +#include +#include + +#include +#include + +#ifdef DDB +static void +in_show_sockaddr_in(struct sockaddr_in *sin) +{ + +#define SIN_DB_RPINTF(f, e) db_printf("\t %s = " f "\n", #e, sin->e); + db_printf("\tsockaddr_in = %p\n", sin); + SIN_DB_RPINTF("%u", sin_len); + SIN_DB_RPINTF("%u", sin_family); + SIN_DB_RPINTF("%u", sin_port); + SIN_DB_RPINTF("0x%08x", sin_addr.s_addr); + db_printf("\t %s = %02x%02x%02x%02x%02x%02x%02x%02x\n", + "sin_zero[8]", + sin->sin_zero[0], sin->sin_zero[1], + sin->sin_zero[2], sin->sin_zero[3], + sin->sin_zero[4], sin->sin_zero[5], + sin->sin_zero[6], sin->sin_zero[7]); +#undef SIN_DB_RPINTF +} + +DB_SHOW_COMMAND(sin, db_show_sin) +{ + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)addr; + if (sin == NULL) { + /* usage: No need to confess if you didn't sin. */ + db_printf("usage: show sin \n"); + return; + } + + in_show_sockaddr_in(sin); +} + +static void +in_show_in_ifaddr(struct in_ifaddr *ia) +{ + +#define IA_DB_RPINTF(f, e) db_printf("\t %s = " f "\n", #e, ia->e); +#define IA_DB_RPINTF_PTR(f, e) db_printf("\t %s = " f "\n", #e, &ia->e); +#define IA_DB_RPINTF_DPTR(f, e) db_printf("\t *%s = " f "\n", #e, *ia->e); + db_printf("\tin_ifaddr = %p\n", ia); + IA_DB_RPINTF_PTR("%p", ia_ifa); + IA_DB_RPINTF("0x%08lx", ia_net); + IA_DB_RPINTF("0x%08lx", ia_netmask); + IA_DB_RPINTF("0x%08lx", ia_subnet); + IA_DB_RPINTF("0x%08lx", ia_subnetmask); + IA_DB_RPINTF("0x%08x", ia_netbroadcast.s_addr); + IA_DB_RPINTF("%p", ia_hash.le_next); + IA_DB_RPINTF("%p", ia_hash.le_prev); + IA_DB_RPINTF_DPTR("%p", ia_hash.le_prev); + IA_DB_RPINTF("%p", ia_link.tqe_next); + IA_DB_RPINTF("%p", ia_link.tqe_prev); + IA_DB_RPINTF_DPTR("%p", ia_link.tqe_prev); + IA_DB_RPINTF_PTR("%p", ia_addr); + IA_DB_RPINTF_PTR("%p", ia_dstaddr); + IA_DB_RPINTF_PTR("%p", ia_sockmask); +#undef IA_DB_RPINTF_DPTR +#undef IA_DB_RPINTF_PTR +#undef IA_DB_RPINTF +} + +DB_SHOW_COMMAND(in_ifaddr, db_show_in_ifaddr) +{ + struct in_ifaddr *ia; + + ia = (struct in_ifaddr *)addr; + if (ia == NULL) { + db_printf("usage: show in_ifaddr \n"); + return; + } + + in_show_in_ifaddr(ia); +} +#endif diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index 96406aa45cf..1389873eb80 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -121,12 +121,13 @@ in_matroute(void *v_arg, struct radix_node_head *head) struct radix_node *rn = rn_match(v_arg, head); struct rtentry *rt = (struct rtentry *)rn; - /*XXX locking? */ - if (rt && rt->rt_refcnt == 0) { /* this is first reference */ + if (rt) { + RT_LOCK(rt); if (rt->rt_flags & RTPRF_OURS) { rt->rt_flags &= ~RTPRF_OURS; rt->rt_rmx.rmx_expire = 0; } + RT_UNLOCK(rt); } return rn; } diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 8de168463e8..d2d99b9d8e1 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -2313,6 +2313,7 @@ carp_mod_cleanup(void) if_clone_detach(&carp_cloner); #ifdef INET if (proto_reg[CARP_INET] == 0) { + (void)ipproto_unregister(IPPROTO_CARP); pf_proto_unregister(PF_INET, IPPROTO_CARP, SOCK_RAW); proto_reg[CARP_INET] = -1; } @@ -2320,6 +2321,7 @@ carp_mod_cleanup(void) #endif #ifdef INET6 if (proto_reg[CARP_INET6] == 0) { + (void)ip6proto_unregister(IPPROTO_CARP); pf_proto_unregister(PF_INET6, IPPROTO_CARP, SOCK_RAW); proto_reg[CARP_INET6] = -1; } @@ -2335,6 +2337,7 @@ carp_mod_cleanup(void) static int carp_mod_load(void) { + int err; if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, carp_ifdetach, NULL, EVENTHANDLER_PRI_ANY); @@ -2355,7 +2358,13 @@ carp_mod_load(void) printf("carp: error %d attaching to PF_INET6\n", proto_reg[CARP_INET6]); carp_mod_cleanup(); - return (EINVAL); + return (proto_reg[CARP_INET6]); + } + err = ip6proto_register(IPPROTO_CARP); + if (err) { + printf("carp: error %d registering with INET6\n", err); + carp_mod_cleanup(); + return (err); } #endif #ifdef INET @@ -2365,7 +2374,13 @@ carp_mod_load(void) printf("carp: error %d attaching to PF_INET\n", proto_reg[CARP_INET]); carp_mod_cleanup(); - return (EINVAL); + return (proto_reg[CARP_INET]); + } + err = ipproto_register(IPPROTO_CARP); + if (err) { + printf("carp: error %d registering with INET\n", err); + carp_mod_cleanup(); + return (err); } #endif return 0; @@ -2405,4 +2420,4 @@ static moduledata_t carp_mod = { 0 }; -DECLARE_MODULE(carp, carp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +DECLARE_MODULE(carp, carp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index acee34112a2..0837d2e2529 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -592,8 +592,8 @@ div_pcblist(SYSCTL_HANDLER_ARGS) */ if (req->oldptr == 0) { n = V_divcbinfo.ipi_count; - req->oldidx = 2 * (sizeof xig) - + (n + n/8) * sizeof(struct xinpcb); + n += imax(n / 8, 10); + req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); return 0; } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 40b494a640b..6e1153d0b73 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1287,12 +1287,12 @@ ip_drain(void) * in inetsw[], either statically or through pf_proto_register(). */ int -ipproto_register(u_char ipproto) +ipproto_register(short ipproto) { struct protosw *pr; /* Sanity checks. */ - if (ipproto == 0) + if (ipproto <= 0 || ipproto >= IPPROTO_MAX) return (EPROTONOSUPPORT); /* @@ -1310,24 +1310,20 @@ ipproto_register(u_char ipproto) pr < inetdomain.dom_protoswNPROTOSW; pr++) { if (pr->pr_domain->dom_family == PF_INET && pr->pr_protocol && pr->pr_protocol == ipproto) { - /* Be careful to only index valid IP protocols. */ - if (pr->pr_protocol < IPPROTO_MAX) { - ip_protox[pr->pr_protocol] = pr - inetsw; - return (0); - } else - return (EINVAL); + ip_protox[pr->pr_protocol] = pr - inetsw; + return (0); } } return (EPROTONOSUPPORT); } int -ipproto_unregister(u_char ipproto) +ipproto_unregister(short ipproto) { struct protosw *pr; /* Sanity checks. */ - if (ipproto == 0) + if (ipproto <= 0 || ipproto >= IPPROTO_MAX) return (EPROTONOSUPPORT); /* Check if the protocol was indeed registered. */ diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c index 3465d4b5f5b..50a6ce44a49 100644 --- a/sys/netinet/ip_ipsec.c +++ b/sys/netinet/ip_ipsec.c @@ -239,7 +239,7 @@ ip_ipsec_mtu(struct mbuf *m, int mtu) if (sp->req != NULL && sp->req->sav != NULL && sp->req->sav->sah != NULL) { - ro = &sp->req->sav->sah->sa_route; + ro = &sp->req->sav->sah->route_cache.sa_route; if (ro->ro_rt && ro->ro_rt->rt_ifp) { mtu = ro->ro_rt->rt_rmx.rmx_mtu ? diff --git a/sys/netinet/ip_options.c b/sys/netinet/ip_options.c index a7afbfdcdd5..53ba713bd7f 100644 --- a/sys/netinet/ip_options.c +++ b/sys/netinet/ip_options.c @@ -341,7 +341,7 @@ dropit: } (void)memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); - if (ifa_ifwithaddr((SA)&ipaddr) == NULL) + if (ifa_ifwithaddr_check((SA)&ipaddr) == 0) continue; cp[IPOPT_OFFSET] += sizeof(struct in_addr); off += sizeof(struct in_addr); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 1a933c51fd9..e292b606346 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1121,6 +1121,7 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FAITH: case IP_ONESBCAST: case IP_DONTFRAG: + case IP_BINDANY: switch (sopt->sopt_name) { case IP_TOS: @@ -1176,6 +1177,9 @@ ip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_DONTFRAG: optval = OPTBIT(INP_DONTFRAG); break; + case IP_BINDANY: + optval = OPTBIT(INP_BINDANY); + break; } error = sooptcopyout(sopt, &optval, sizeof optval); break; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 4415001fc27..222b7efea51 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -220,8 +220,8 @@ extern int int ip_output(struct mbuf *, struct mbuf *, struct route *, int, struct ip_moptions *, struct inpcb *); -int ipproto_register(u_char); -int ipproto_unregister(u_char); +int ipproto_register(short); +int ipproto_unregister(short); struct mbuf * ip_reass(struct mbuf *); struct in_ifaddr * diff --git a/sys/netinet/ipfw/dn_sched.h b/sys/netinet/ipfw/dn_sched.h index b6bf24e466a..ab823fe7c80 100644 --- a/sys/netinet/ipfw/dn_sched.h +++ b/sys/netinet/ipfw/dn_sched.h @@ -166,6 +166,8 @@ dn_dequeue(struct dn_queue *q) if (m == NULL) return NULL; q->mq.head = m->m_nextpkt; + + /* Update stats for the queue */ q->ni.length--; q->ni.len_bytes -= m->m_pkthdr.len; if (q->_si) { diff --git a/sys/netinet/ipfw/dn_sched_qfq.c b/sys/netinet/ipfw/dn_sched_qfq.c index 44555ee09e2..c37b65e1ee2 100644 --- a/sys/netinet/ipfw/dn_sched_qfq.c +++ b/sys/netinet/ipfw/dn_sched_qfq.c @@ -61,7 +61,7 @@ typedef unsigned long bitmap; * bitmaps ops are critical. Some linux versions have __fls * and the bitmap ops. Some machines have ffs */ -#if defined(_WIN32) +#if defined(_WIN32) || (defined(__MIPSEL__) && defined(LINUX_24)) int fls(unsigned int n) { int i = 0; @@ -71,7 +71,7 @@ int fls(unsigned int n) } #endif -#if !defined(_KERNEL) || defined( __FreeBSD__ ) || defined(_WIN32) +#if !defined(_KERNEL) || defined( __FreeBSD__ ) || defined(_WIN32) || (defined(__MIPSEL__) && defined(LINUX_24)) static inline unsigned long __fls(unsigned long word) { return fls(word) - 1; @@ -107,7 +107,7 @@ void __clear_bit(int ix, bitmap *p) #endif /* !__linux__ */ #ifdef __MIPSEL__ -#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix)) +#define __clear_bit(ix, pData) (*pData) &= ~(1<<(ix)) #endif /*-------------------------------------------*/ diff --git a/sys/netinet/ipfw/dn_sched_wf2q.c b/sys/netinet/ipfw/dn_sched_wf2q.c index 55a49550b7f..7f16719d378 100644 --- a/sys/netinet/ipfw/dn_sched_wf2q.c +++ b/sys/netinet/ipfw/dn_sched_wf2q.c @@ -318,7 +318,7 @@ wf2qp_free_queue(struct dn_queue *q) { struct wf2qp_queue *alg_fq = (struct wf2qp_queue *)q; struct wf2qp_si *si = (struct wf2qp_si *)(q->_si + 1); - + if (alg_fq->S >= alg_fq->F + 1) return 0; /* nothing to do, not in any heap */ si->wsum -= q->fs->fs.par[0]; diff --git a/sys/netinet/ipfw/ip_dn_glue.c b/sys/netinet/ipfw/ip_dn_glue.c index a31ec1f71b8..9a819121b38 100644 --- a/sys/netinet/ipfw/ip_dn_glue.c +++ b/sys/netinet/ipfw/ip_dn_glue.c @@ -1,4 +1,4 @@ -/*- +/*- * Copyright (c) 2010 Riccardo Panicucci, Universita` di Pisa * All rights reserved * diff --git a/sys/netinet/ipfw/ip_dn_io.c b/sys/netinet/ipfw/ip_dn_io.c index 152010eda48..52a0f9e2db6 100644 --- a/sys/netinet/ipfw/ip_dn_io.c +++ b/sys/netinet/ipfw/ip_dn_io.c @@ -120,10 +120,6 @@ SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, io_fast, CTLFLAG_RW, DC(io_fast), 0, "Enable fast dummynet io."); SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, debug, CTLFLAG_RW, DC(debug), 0, "Dummynet debug level"); -SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire, - CTLFLAG_RW, DC(expire), 0, "Expire empty queues/pipes"); -SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire_cycle, - CTLFLAG_RD, DC(expire_cycle), 0, "Expire cycle for queues/pipes"); /* RED parameters */ SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, red_lookup_depth, @@ -147,6 +143,12 @@ SYSCTL_LONG(_net_inet_ip_dummynet, OID_AUTO, tick_lost, CTLFLAG_RD, &tick_lost, 0, "Number of ticks coalesced by dummynet taskqueue."); +/* Drain parameters */ +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire, + CTLFLAG_RW, DC(expire), 0, "Expire empty queues/pipes"); +SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, expire_cycle, + CTLFLAG_RD, DC(expire_cycle), 0, "Expire cycle for queues/pipes"); + /* statistics */ SYSCTL_INT(_net_inet_ip_dummynet, OID_AUTO, schk_count, CTLFLAG_RD, DC(schk_count), 0, "Number of schedulers"); @@ -463,14 +465,16 @@ serve_sched(struct mq *q, struct dn_sch_inst *si, uint64_t now) done = 0; while (si->credit >= 0 && (m = s->fp->dequeue(si)) != NULL) { uint64_t len_scaled; + done++; len_scaled = (bw == 0) ? 0 : hz * - (m->m_pkthdr.len * 8 + extra_bits(m, s)); + (m->m_pkthdr.len * 8 + extra_bits(m, s)); si->credit -= len_scaled; /* Move packet in the delay line */ dn_tag_get(m)->output_time += s->link.delay ; mq_append(&si->dline.mq, m); } + /* * If credit >= 0 the instance is idle, mark time. * Otherwise put back in the heap, and adjust the output @@ -752,8 +756,11 @@ dummynet_io(struct mbuf **m0, int dir, struct ip_fw_args *fwa) } /* compute the initial allowance */ - { + if (si->idle_time < dn_cfg.curr_time) { + /* Do this only on the first packet on an idle pipe */ struct dn_link *p = &fs->sched->link; + + si->sched_time = dn_cfg.curr_time; si->credit = dn_cfg.io_fast ? p->bandwidth : 0; if (p->burst) { uint64_t burst = (dn_cfg.curr_time - si->idle_time) * p->bandwidth; diff --git a/sys/netinet/ipfw/ip_dn_private.h b/sys/netinet/ipfw/ip_dn_private.h index 03b43dba55d..159ddc9ab8b 100644 --- a/sys/netinet/ipfw/ip_dn_private.h +++ b/sys/netinet/ipfw/ip_dn_private.h @@ -49,10 +49,6 @@ MALLOC_DECLARE(M_DUMMYNET); -#ifndef FREE_PKT -#define FREE_PKT(m) m_freem(m) -#endif - #ifndef __linux__ #define div64(a, b) ((int64_t)(a) / (int64_t)(b)) #endif @@ -351,13 +347,14 @@ enum { DN_DETACH = 0x0010, DN_ACTIVE = 0x0020, /* object is in evheap */ DN_F_DLINE = 0x0040, /* object is a delay line */ - DN_F_SCHI = 0x00C0, /* object is a sched.instance */ + DN_DEL_SAFE = 0x0080, /* delete a queue only if no longer needed + * by scheduler */ DN_QHT_IS_Q = 0x0100, /* in flowset, qht is a single queue */ }; extern struct dn_parms dn_cfg; //VNET_DECLARE(struct dn_parms, _base_dn_cfg); -//#define dn_cfg VNET(_base_dn_cfg) +//#define dn_cfg VNET(_base_dn_cfg) int dummynet_io(struct mbuf **, int , struct ip_fw_args *); void dummynet_task(void *context, int pending); diff --git a/sys/netinet/ipfw/ip_dummynet.c b/sys/netinet/ipfw/ip_dummynet.c index 01714aa6634..67327e31898 100644 --- a/sys/netinet/ipfw/ip_dummynet.c +++ b/sys/netinet/ipfw/ip_dummynet.c @@ -445,6 +445,7 @@ si_new(uintptr_t key, int flags, void *arg) si = malloc(l, M_DUMMYNET, M_NOWAIT | M_ZERO); if (si == NULL) goto error; + /* Set length only for the part passed up to userland. */ set_oid(&si->ni.oid, DN_SCH_I, sizeof(struct dn_flow)); set_oid(&(si->dline.oid), DN_DELAY_LINE, @@ -1571,7 +1572,7 @@ config_profile(struct dn_profile *pf, struct dn_id *arg) */ if (s->profile == NULL) s->profile = malloc(pf->oid.len, - M_DUMMYNET, M_NOWAIT | M_ZERO); + M_DUMMYNET, M_NOWAIT | M_ZERO); if (s->profile == NULL) { D("no memory for profile %d", i); err = ENOMEM; @@ -2300,7 +2301,7 @@ MODULE_VERSION(dummynet, 1); * VNET_SYSINIT is also called for each existing vnet and each new vnet. */ //VNET_SYSINIT(vnet_dn_init, DN_SI_SUB, DN_MODEV_ORD+2, ip_dn_init, NULL); - + /* * Shutdown handlers up shop. These are done in REVERSE ORDER, but still * after dummynet_modevent() has been called. Not called on reboot. diff --git a/sys/netinet/ipfw/ip_fw_log.c b/sys/netinet/ipfw/ip_fw_log.c index 2995f2cc155..3560e137f1e 100644 --- a/sys/netinet/ipfw/ip_fw_log.c +++ b/sys/netinet/ipfw/ip_fw_log.c @@ -103,6 +103,24 @@ log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) return EINVAL; } +static int +ipfw_log_output(struct ifnet *ifp, struct mbuf *m, + struct sockaddr *dst, struct route *ro) +{ + if (m != NULL) + m_freem(m); + return EINVAL; +} + +static void +ipfw_log_start(struct ifnet* ifp) +{ + panic("ipfw_log_start() must not be called"); +} + +static const u_char ipfwbroadcastaddr[6] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + void ipfw_log_bpf(int onoff) { @@ -119,11 +137,12 @@ ipfw_log_bpf(int onoff) ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_init = (void *)log_dummy; ifp->if_ioctl = log_dummy; - ifp->if_start = (void *)log_dummy; - ifp->if_output = (void *)log_dummy; + ifp->if_start = ipfw_log_start; + ifp->if_output = ipfw_log_output; ifp->if_addrlen = 6; ifp->if_hdrlen = 14; if_attach(ifp); + ifp->if_broadcastaddr = ipfwbroadcastaddr; ifp->if_baudrate = IF_Mbps(10); bpfattach(ifp, DLT_EN10MB, 14); log_if = ifp; diff --git a/sys/netinet/ipfw/ip_fw_nat.c b/sys/netinet/ipfw/ip_fw_nat.c index f30b754dc16..6f223ed0de6 100644 --- a/sys/netinet/ipfw/ip_fw_nat.c +++ b/sys/netinet/ipfw/ip_fw_nat.c @@ -295,12 +295,9 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) struct udphdr *uh; u_short cksum; - /* XXX check if ip_len can stay in net format */ - cksum = in_pseudo( - ip->ip_src.s_addr, - ip->ip_dst.s_addr, - htons(ip->ip_p + ntohs(ip->ip_len) - (ip->ip_hl << 2)) - ); + ip->ip_len = ntohs(ip->ip_len); + cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2))); switch (ip->ip_p) { case IPPROTO_TCP: @@ -326,6 +323,7 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) in_delayed_cksum(mcl); mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } + ip->ip_len = htons(ip->ip_len); } args->m = mcl; return (IP_FW_NAT); diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c index e87a4c973fe..248e4dd8a75 100644 --- a/sys/netinet/ipfw/ip_fw_pfil.c +++ b/sys/netinet/ipfw/ip_fw_pfil.c @@ -231,6 +231,11 @@ again: break; case IP_FW_NAT: + /* honor one-pass in case of successful nat */ + if (V_fw_one_pass) + break; /* ret is already 0 */ + goto again; + case IP_FW_REASS: goto again; /* continue with packet */ diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3 index 8f7d93ffe46..31702e8adf9 100644 --- a/sys/netinet/libalias/libalias.3 +++ b/sys/netinet/libalias/libalias.3 @@ -899,7 +899,6 @@ protocols (except for IP, TCP and UDP) to external modules. .Sh ACKNOWLEDGMENTS Listed below, in approximate chronological order, are individuals who have provided valuable comments and/or debugging assistance. -.Pp .Bd -ragged -offset indent .An -split .An Gary Roberts diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 0b77b5b8496..c91d4a9da9f 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -741,6 +741,8 @@ rip_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (err == 0) ia->ia_flags |= IFA_ROUTE; err = ifa_add_loopback_route((struct ifaddr *)ia, sa); + if (err == 0) + ia->ia_flags |= IFA_RTSELF; ifa_free(&ia->ia_ifa); break; } @@ -993,8 +995,8 @@ rip_pcblist(SYSCTL_HANDLER_ARGS) */ if (req->oldptr == 0) { n = V_ripcbinfo.ipi_count; - req->oldidx = 2 * (sizeof xig) - + (n + n/8) * sizeof(struct xinpcb); + n += imax(n / 8, 10); + req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); return (0); } diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index ce5ac0a07cb..1335e82fb1a 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -155,10 +155,8 @@ struct sctp_paramhdr { /* CMT ON/OFF socket option */ #define SCTP_CMT_ON_OFF 0x00001200 #define SCTP_CMT_USE_DAC 0x00001201 -/* EY - NR_SACK on/off socket option */ -#define SCTP_NR_SACK_ON_OFF 0x00001300 /* JRS - Pluggable Congestion Control Socket option */ -#define SCTP_PLUGGABLE_CC 0x00001202 +#define SCTP_PLUGGABLE_CC 0x00001202 /* read only */ #define SCTP_GET_SNDBUF_USE 0x00001101 diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index ee5dc0d21b1..288381de413 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -581,8 +581,8 @@ sctp_process_asconf_set_primary(struct mbuf *m, } if (sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { - sctp_move_chunks_from_deleted_prim(stcb, - stcb->asoc.primary_destination); + sctp_move_chunks_from_net(stcb, + stcb->asoc.deleted_primary); } sctp_delete_prim_timer(stcb->sctp_ep, stcb, stcb->asoc.deleted_primary); @@ -1041,47 +1041,6 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn) } } -void -sctp_move_chunks_from_deleted_prim(struct sctp_tcb *stcb, struct sctp_nets *dst) -{ - struct sctp_association *asoc; - struct sctp_stream_out *outs; - struct sctp_tmit_chunk *chk; - struct sctp_stream_queue_pending *sp; - - if (dst->dest_state & SCTP_ADDR_UNCONFIRMED) { - return; - } - if (stcb->asoc.deleted_primary == NULL) { - return; - } - asoc = &stcb->asoc; - - /* - * now through all the streams checking for chunks sent to our bad - * network. - */ - TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { - /* now clean up any chunks here */ - TAILQ_FOREACH(sp, &outs->outqueue, next) { - if (sp->net == asoc->deleted_primary) { - sctp_free_remote_addr(sp->net); - sp->net = dst; - atomic_add_int(&dst->ref_count, 1); - } - } - } - /* Now check the pending queue */ - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->whoTo == asoc->deleted_primary) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = dst; - atomic_add_int(&dst->ref_count, 1); - } - } - -} - void sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet) @@ -2080,13 +2039,11 @@ sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val) struct sctp_asconf_iterator *asc; struct sctp_ifa *ifa; struct sctp_laddr *l; - int type; int cnt_invalid = 0; asc = (struct sctp_asconf_iterator *)ptr; LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { ifa = l->ifa; - type = l->action; if (ifa->address.sa.sa_family == AF_INET6) { /* invalid if we're not a v6 endpoint */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { diff --git a/sys/netinet/sctp_asconf.h b/sys/netinet/sctp_asconf.h index 9622871b966..bf3d5665e54 100644 --- a/sys/netinet/sctp_asconf.h +++ b/sys/netinet/sctp_asconf.h @@ -79,8 +79,6 @@ extern void sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int, struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t); -extern void - sctp_move_chunks_from_deleted_prim(struct sctp_tcb *, struct sctp_nets *); extern void sctp_assoc_immediate_retrans(struct sctp_tcb *, struct sctp_nets *); extern void diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 3341c50651d..f106048720e 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -614,7 +614,7 @@ sctp_auth_key_release(struct sctp_tcb *stcb, uint16_t key_id) if ((skey->refcount <= 1) && (skey->deactivated)) { /* notify ULP that key is no longer used */ sctp_ulp_notify(SCTP_NOTIFY_AUTH_FREE_KEY, stcb, - key_id, 0, SCTP_SO_NOT_LOCKED); + key_id, 0, SCTP_SO_LOCKED); SCTPDBG(SCTP_DEBUG_AUTH2, "%s: stcb %p key %u no longer used, %d\n", __FUNCTION__, stcb, key_id, skey->refcount); diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c index 4c5a9aa6c83..90fd9a13443 100644 --- a/sys/netinet/sctp_bsd_addr.c +++ b/sys/netinet/sctp_bsd_addr.c @@ -298,7 +298,6 @@ sctp_init_vrf_list(int vrfid) void sctp_addr_change(struct ifaddr *ifa, int cmd) { - struct sctp_ifa *ifap = NULL; uint32_t ifa_flags = 0; /* @@ -339,7 +338,7 @@ sctp_addr_change(struct ifaddr *ifa, int cmd) return; } if (cmd == RTM_ADD) { - ifap = sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, + (void)sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID, (void *)ifa->ifa_ifp, ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type, ifa->ifa_ifp->if_xname, (void *)ifa, ifa->ifa_addr, ifa_flags, 1); diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c index 8beff191628..e40639b40fc 100644 --- a/sys/netinet/sctp_cc_functions.c +++ b/sys/netinet/sctp_cc_functions.c @@ -44,18 +44,27 @@ #include #include __FBSDID("$FreeBSD$"); + void sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net) { - /* - * We take the max of the burst limit times a MTU or the - * INITIAL_CWND. We then limit this to 4 MTU's of sending. cwnd must - * be at least 2 MTU. - */ - net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND)); - net->ssthresh = stcb->asoc.peers_rwnd; + struct sctp_association *assoc; + uint32_t cwnd_in_mtu; - if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { + assoc = &stcb->asoc; + /* + * We take the minimum of the burst limit and the initial congestion + * window. The initial congestion window is at least two times the + * MTU. + */ + cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd); + if ((assoc->max_burst > 0) && (cwnd_in_mtu > assoc->max_burst)) + cwnd_in_mtu = assoc->max_burst; + net->cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu; + net->ssthresh = assoc->peers_rwnd; + + if (SCTP_BASE_SYSCTL(sctp_logging_level) & + (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) { sctp_log_cwnd(stcb, net, 0, SCTP_CWND_INITIALIZATION); } } @@ -71,7 +80,8 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb, * (net->fast_retran_loss_recovery == 0))) */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1)) { + if ((asoc->fast_retran_loss_recovery == 0) || + (asoc->sctp_cmt_on_off == 1)) { /* out of a RFC2582 Fast recovery window? */ if (net->net_ack > 0) { /* @@ -170,7 +180,7 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, * So, first of all do we need to have a Early FR * timer running? */ - if (((TAILQ_FIRST(&asoc->sent_queue)) && + if ((!TAILQ_EMPTY(&asoc->sent_queue) && (net->ref_count > 1) && (net->flight_size < net->cwnd)) || (reneged_all)) { @@ -232,11 +242,11 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, * * Should we stop any running T3 timer here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); + net->cwnd = net->mtu * asoc->sctp_cmt_pf; SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", net, net->cwnd); /* @@ -260,7 +270,9 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, */ #endif - if (asoc->fast_retran_loss_recovery && will_exit == 0 && SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { + if (asoc->fast_retran_loss_recovery && + (will_exit == 0) && + (asoc->sctp_cmt_on_off == 0)) { /* * If we are in loss recovery we skip any cwnd * update @@ -271,7 +283,8 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb, * CMT: CUC algorithm. Update cwnd if pseudo-cumack has * moved. */ - if (accum_moved || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && net->new_pseudo_cumack)) { + if (accum_moved || + ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { /* If the cumulative ack moved we can proceed */ if (net->cwnd <= net->ssthresh) { /* We are in slow start */ @@ -652,7 +665,6 @@ sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net) int old_cwnd = net->cwnd; cur_val = net->cwnd >> 10; - indx = net->last_hs_used; if (cur_val < sctp_cwnd_adjust[0].cwnd) { /* normal mode */ net->ssthresh = net->cwnd / 2; @@ -697,7 +709,8 @@ sctp_hs_cwnd_update_after_fr(struct sctp_tcb *stcb, * (net->fast_retran_loss_recovery == 0))) */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1)) { + if ((asoc->fast_retran_loss_recovery == 0) || + (asoc->sctp_cmt_on_off == 1)) { /* out of a RFC2582 Fast recovery window? */ if (net->net_ack > 0) { /* @@ -788,7 +801,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, * So, first of all do we need to have a Early FR * timer running? */ - if (((TAILQ_FIRST(&asoc->sent_queue)) && + if ((!TAILQ_EMPTY(&asoc->sent_queue) && (net->ref_count > 1) && (net->flight_size < net->cwnd)) || (reneged_all)) { @@ -850,11 +863,11 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, * * Should we stop any running T3 timer here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); + net->cwnd = net->mtu * asoc->sctp_cmt_pf; SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", net, net->cwnd); /* @@ -878,7 +891,9 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, */ #endif - if (asoc->fast_retran_loss_recovery && will_exit == 0 && SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { + if (asoc->fast_retran_loss_recovery && + (will_exit == 0) && + (asoc->sctp_cmt_on_off == 0)) { /* * If we are in loss recovery we skip any cwnd * update @@ -889,7 +904,8 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb, * CMT: CUC algorithm. Update cwnd if pseudo-cumack has * moved. */ - if (accum_moved || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && net->new_pseudo_cumack)) { + if (accum_moved || + ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { /* If the cumulative ack moved we can proceed */ if (net->cwnd <= net->ssthresh) { /* We are in slow start */ @@ -1271,7 +1287,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, * So, first of all do we need to have a Early FR * timer running? */ - if (((TAILQ_FIRST(&asoc->sent_queue)) && + if ((!TAILQ_EMPTY(&asoc->sent_queue) && (net->ref_count > 1) && (net->flight_size < net->cwnd)) || (reneged_all)) { @@ -1333,11 +1349,11 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, * * Should we stop any running T3 timer here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); + net->cwnd = net->mtu * asoc->sctp_cmt_pf; SCTPDBG(SCTP_DEBUG_INDATA1, "Destination %p moved from PF to reachable with cwnd %d.\n", net, net->cwnd); /* @@ -1361,7 +1377,9 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, */ #endif - if (asoc->fast_retran_loss_recovery && will_exit == 0 && SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) { + if (asoc->fast_retran_loss_recovery && + will_exit == 0 && + (asoc->sctp_cmt_on_off == 0)) { /* * If we are in loss recovery we skip any cwnd * update @@ -1372,7 +1390,8 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb, * CMT: CUC algorithm. Update cwnd if pseudo-cumack has * moved. */ - if (accum_moved || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && net->new_pseudo_cumack)) { + if (accum_moved || + ((asoc->sctp_cmt_on_off == 1) && net->new_pseudo_cumack)) { htcp_cong_avoid(stcb, net); measure_achieved_throughput(stcb, net); } else { @@ -1412,7 +1431,8 @@ sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb, * (net->fast_retran_loss_recovery == 0))) */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((asoc->fast_retran_loss_recovery == 0) || (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1)) { + if ((asoc->fast_retran_loss_recovery == 0) || + (asoc->sctp_cmt_on_off == 1)) { /* out of a RFC2582 Fast recovery window? */ if (net->net_ack > 0) { /* diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 078981de310..212a2f9e05f 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -948,6 +948,9 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_TIME_WAIT 60 +#define SCTP_SEND_BUFFER_SPLITTING 0x00000001 +#define SCTP_RECV_BUFFER_SPLITTING 0x00000002 + /* The system retains a cache of free chunks such to * cut down on calls the memory allocation system. There * is a per association limit of free items and a overall diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c index d9ae238835f..0ab8039ac06 100644 --- a/sys/netinet/sctp_crc32.c +++ b/sys/netinet/sctp_crc32.c @@ -115,20 +115,15 @@ sctp_calculate_cksum(struct mbuf *m, uint32_t offset) return (base); } -#else - -uint32_t -sctp_calculate_cksum(struct mbuf *m, uint32_t offset) -{ - return (0); -} - #endif /* !defined(SCTP_WITH_NO_CSUM) */ void sctp_delayed_cksum(struct mbuf *m, uint32_t offset) { +#if defined(SCTP_WITH_NO_CSUM) + panic("sctp_delayed_cksum() called when using no SCTP CRC."); +#else struct ip *ip; uint32_t checksum; @@ -149,4 +144,5 @@ sctp_delayed_cksum(struct mbuf *m, uint32_t offset) return; } *(uint32_t *) (m->m_data + offset) = checksum; +#endif } diff --git a/sys/netinet/sctp_crc32.h b/sys/netinet/sctp_crc32.h index e66815ee517..eb7a1bc7a8e 100644 --- a/sys/netinet/sctp_crc32.h +++ b/sys/netinet/sctp_crc32.h @@ -36,11 +36,12 @@ __FBSDID("$FreeBSD$"); #ifndef __crc32c_h__ #define __crc32c_h__ -#if defined(_KERNEL) || defined(__Userspace__) - +#if defined(_KERNEL) +#if !defined(SCTP_WITH_NO_CSUM) uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); + +#endif void sctp_delayed_cksum(struct mbuf *, uint32_t offset); #endif /* _KERNEL */ - #endif /* __crc32c_h__ */ diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index e429da8793e..6cae72e5e17 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -708,9 +708,10 @@ protocol_error: control->data = NULL; asoc->size_on_all_streams -= control->length; sctp_ucount_decr(asoc->cnt_on_all_streams); - if (control->whoFrom) + if (control->whoFrom) { sctp_free_remote_addr(control->whoFrom); - control->whoFrom = NULL; + control->whoFrom = NULL; + } sctp_free_a_readq(stcb, control); return; } else { @@ -1775,6 +1776,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, if (control == NULL) { goto failed_express_del; } + SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); + if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) { + asoc->highest_tsn_inside_nr_map = tsn; + } sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); @@ -1790,10 +1795,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc, } control = NULL; - SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap); - if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) { - asoc->highest_tsn_inside_nr_map = tsn; - } goto finish_express_del; } failed_express_del: @@ -2475,7 +2476,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap, int *abort_flag) (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */ ) { - if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off)) && + if ((stcb->asoc.sctp_cmt_on_off == 1) && (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) && (stcb->asoc.send_sack == 0) && (stcb->asoc.numduptsns == 0) && @@ -3265,7 +3266,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, } /* CMT DAC algo: finding out if SACK is a mixed SACK */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if (net->saw_newack) num_dests_sacked++; @@ -3298,13 +3300,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (stcb->asoc.peer_supports_prsctp) { if ((PR_SCTP_TTL_ENABLED(tp1->flags)) && tp1->sent < SCTP_DATAGRAM_ACKED) { /* Is it expired? */ - if ( - /* - * TODO sctp_constants.h needs alternative - * time macros when _KERNEL is undefined. - */ - (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) - ) { + if (timevalcmp(&now, &tp1->rec.data.timetodrop, >)) { /* Yes so drop it */ if (tp1->data != NULL) { (void)sctp_release_pr_sctp_chunk(stcb, tp1, @@ -3381,7 +3377,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (tp1->sent < SCTP_DATAGRAM_RESEND) { tp1->sent++; } - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { /* * CMT DAC algorithm: If SACK flag is set to * 0, then lowest_newack test will not pass @@ -3405,7 +3402,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent++; } } - } else if ((tp1->rec.data.doing_fast_retransmit) && (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { + } else if ((tp1->rec.data.doing_fast_retransmit) && + (asoc->sctp_cmt_on_off == 0)) { /* * For those that have done a FR we must take * special consideration if we strike. I.e the @@ -3445,7 +3443,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->sent++; } strike_flag = 1; - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { /* * CMT DAC algorithm: If * SACK flag is set to 0, @@ -3505,7 +3504,8 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (tp1->sent < SCTP_DATAGRAM_RESEND) { tp1->sent++; } - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { /* * CMT DAC algorithm: If SACK flag is set to * 0, then lowest_newack test will not pass @@ -3584,7 +3584,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, SCTP_STAT_INCR(sctps_sendmultfastretrans); } sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + if (asoc->sctp_cmt_on_off == 1) { /* * CMT: Using RTX_SSTHRESH policy for CMT. * If CMT is being used, then pick dest with @@ -3593,7 +3593,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, tp1->no_fr_allowed = 1; alt = tp1->whoTo; /* sa_ignore NO_NULL_CHK */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if (asoc->sctp_cmt_pf > 0) { /* * JRS 5/18/07 - If CMT PF is on, * use the PF version of @@ -4800,7 +4800,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, /*******************************************/ /* cancel ALL T3-send timer if accum moved */ /*******************************************/ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + if (asoc->sctp_cmt_on_off == 1) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { if (net->new_pseudo_cumack) sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, @@ -4840,7 +4840,7 @@ sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup, if (asoc->pr_sctp_cnt != 0) asoc->pr_sctp_cnt--; } - if ((TAILQ_FIRST(&asoc->sent_queue) == NULL) && + if (TAILQ_EMPTY(&asoc->sent_queue) && (asoc->total_flight > 0)) { #ifdef INVARIANTS panic("Warning flight size is postive and should be 0"); @@ -5100,7 +5100,9 @@ done_with_it: * to be done. Setting this_sack_lowest_newack to the cum_ack will * automatically ensure that. */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac) && (cmt_dac_flag == 0)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac) && + (cmt_dac_flag == 0)) { this_sack_lowest_newack = cum_ack; } if ((num_seg > 0) || (num_nr_seg > 0)) { @@ -5811,7 +5813,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb, */ sctp_slide_mapping_arrays(stcb); - if (TAILQ_FIRST(&asoc->reasmqueue)) { + if (!TAILQ_EMPTY(&asoc->reasmqueue)) { /* now lets kick out and check for more fragmented delivery */ /* sa_ignore NO_NULL_CHK */ sctp_deliver_reasm_check(stcb, &stcb->asoc); diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 8b2a9d598db..8dffd4df963 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -232,7 +232,10 @@ sctp_is_there_unsent_data(struct sctp_tcb *stcb) } atomic_subtract_int(&stcb->asoc.stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); - sctp_free_remote_addr(sp->net); + if (sp->net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } if (sp->data) { sctp_m_freem(sp->data); sp->data = NULL; @@ -263,7 +266,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb, /* save off parameters */ asoc->peer_vtag = ntohl(init->initiate_tag); asoc->peers_rwnd = ntohl(init->a_rwnd); - if (TAILQ_FIRST(&asoc->nets)) { + if (!TAILQ_EMPTY(&asoc->nets)) { /* update any ssthresh's that may have a default */ TAILQ_FOREACH(lnet, &asoc->nets, sctp_next) { lnet->ssthresh = asoc->peers_rwnd; @@ -318,8 +321,10 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb, sctp_m_freem(sp->data); sp->data = NULL; } - sctp_free_remote_addr(sp->net); - sp->net = NULL; + if (sp->net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } /* Free the chunk */ sctp_free_a_strmoq(stcb, sp); /* sa_ignore FREED_MEMORY */ @@ -535,7 +540,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, struct sockaddr_storage store; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; - struct sctp_nets *r_net; + struct sctp_nets *r_net, *f_net; struct timeval tv; int req_prim = 0; @@ -581,16 +586,16 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, stcb->asoc.primary_destination = r_net; r_net->dest_state &= ~SCTP_ADDR_WAS_PRIMARY; r_net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; - r_net = TAILQ_FIRST(&stcb->asoc.nets); - if (r_net != stcb->asoc.primary_destination) { + f_net = TAILQ_FIRST(&stcb->asoc.nets); + if (f_net != r_net) { /* * first one on the list is NOT the primary * sctp_cmpaddr() is much more efficent if * the primary is the first on the list, * make it so. */ - TAILQ_REMOVE(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); - TAILQ_INSERT_HEAD(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next); + TAILQ_REMOVE(&stcb->asoc.nets, r_net, sctp_next); + TAILQ_INSERT_HEAD(&stcb->asoc.nets, r_net, sctp_next); } req_prim = 1; } @@ -618,16 +623,16 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, * timer is running, for the destination, stop the timer because a * PF-heartbeat was received. */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && - (net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0) && + ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { if (SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_5); } net->dest_state &= ~SCTP_ADDR_PF; - net->cwnd = net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); + net->cwnd = net->mtu * stcb->asoc.sctp_cmt_pf; SCTPDBG(SCTP_DEBUG_INPUT1, "Destination %p moved from PF to reachable with cwnd %d.\n", net, net->cwnd); } @@ -650,8 +655,8 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp, } if (sctp_is_mobility_feature_on(stcb->sctp_ep, SCTP_MOBILITY_BASE)) { - sctp_move_chunks_from_deleted_prim(stcb, - stcb->asoc.primary_destination); + sctp_move_chunks_from_net(stcb, + stcb->asoc.deleted_primary); } sctp_delete_prim_timer(stcb->sctp_ep, stcb, stcb->asoc.deleted_primary); @@ -2723,6 +2728,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, inp->sctp_mobility_features = (*inp_p)->sctp_mobility_features; inp->sctp_socket = so; inp->sctp_frag_point = (*inp_p)->sctp_frag_point; + inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off; inp->partial_delivery_point = (*inp_p)->partial_delivery_point; inp->sctp_context = (*inp_p)->sctp_context; inp->inp_starting_point_for_iterator = NULL; @@ -4586,8 +4592,6 @@ process_control_chunks: return (NULL); break; case SCTP_SELECTIVE_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK\n"); - SCTP_STAT_INCR(sctps_recvsacks); { struct sctp_sack_chunk *sack; int abort_now = 0; @@ -4597,6 +4601,8 @@ process_control_chunks: int offset_seg, offset_dup; int nonce_sum_flag; + SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SACK\n"); + SCTP_STAT_INCR(sctps_recvsacks); if (stcb == NULL) { SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing SACK chunk\n"); break; @@ -4673,8 +4679,6 @@ process_control_chunks: * nr_sack chunk */ case SCTP_NR_SELECTIVE_ACK: - SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK\n"); - SCTP_STAT_INCR(sctps_recvsacks); { struct sctp_nr_sack_chunk *nr_sack; int abort_now = 0; @@ -4684,19 +4688,16 @@ process_control_chunks: int offset_seg, offset_dup; int nonce_sum_flag; - /* - * EY nr_sacks have not been negotiated but - * the peer end sent an nr_sack, silently - * discard the chunk - */ - if (!(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && - stcb->asoc.peer_supports_nr_sack)) { - goto unknown_chunk; - } + SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_NR_SACK\n"); + SCTP_STAT_INCR(sctps_recvsacks); if (stcb == NULL) { SCTPDBG(SCTP_DEBUG_INDATA1, "No stcb when processing NR-SACK chunk\n"); break; } + if ((stcb->asoc.sctp_nr_sack_on_off == 0) || + (stcb->asoc.peer_supports_nr_sack == 0)) { + goto unknown_chunk; + } if (chk_length < sizeof(struct sctp_nr_sack_chunk)) { SCTPDBG(SCTP_DEBUG_INDATA1, "Bad size on NR-SACK chunk, too small\n"); break; @@ -5721,14 +5722,17 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) struct ip *ip; struct sctphdr *sh; struct sctp_inpcb *inp = NULL; - - uint32_t check, calc_check; struct sctp_nets *net; struct sctp_tcb *stcb = NULL; struct sctp_chunkhdr *ch; int refcount_up = 0; int length, mlen, offset; +#if !defined(SCTP_WITH_NO_CSUM) + uint32_t check, calc_check; + +#endif + if (SCTP_GET_PKT_VRFID(i_pak, vrf_id)) { SCTP_RELEASE_PKT(i_pak); return; @@ -5803,18 +5807,14 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) m->m_pkthdr.len, if_name(m->m_pkthdr.rcvif), m->m_pkthdr.csum_flags); +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_recvnocrc); +#else if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { SCTP_STAT_INCR(sctps_recvhwcrc); goto sctp_skip_csum_4; } check = sh->checksum; /* save incoming checksum */ - if ((check == 0) && (SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback)) && - ((ip->ip_src.s_addr == ip->ip_dst.s_addr) || - (SCTP_IS_IT_LOOPBACK(m))) - ) { - SCTP_STAT_INCR(sctps_recvnocrc); - goto sctp_skip_csum_4; - } sh->checksum = 0; /* prepare for calc */ calc_check = sctp_calculate_cksum(m, iphlen); sh->checksum = check; @@ -5844,6 +5844,7 @@ sctp_input_with_port(struct mbuf *i_pak, int off, uint16_t port) goto bad; } sctp_skip_csum_4: +#endif /* destination port of 0 is illegal, based on RFC2960. */ if (sh->dest_port == 0) { SCTP_STAT_INCR(sctps_hdrops); diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h index cec568d52c6..883d6dd8ac4 100644 --- a/sys/netinet/sctp_os_bsd.h +++ b/sys/netinet/sctp_os_bsd.h @@ -433,20 +433,21 @@ typedef struct rtentry sctp_rtentry_t; */ #define SCTP_IP_OUTPUT(result, o_pak, ro, stcb, vrf_id) \ { \ - int o_flgs = 0; \ - if (stcb && stcb->sctp_ep && stcb->sctp_ep->sctp_socket) { \ - o_flgs = IP_RAWOUTPUT | (stcb->sctp_ep->sctp_socket->so_options & SO_DONTROUTE); \ - } else { \ - o_flgs = IP_RAWOUTPUT; \ - } \ + int o_flgs = IP_RAWOUTPUT; \ + struct sctp_tcb *local_stcb = stcb; \ + if (local_stcb && \ + local_stcb->sctp_ep && \ + local_stcb->sctp_ep->sctp_socket) \ + o_flgs |= local_stcb->sctp_ep->sctp_socket->so_options & SO_DONTROUTE; \ result = ip_output(o_pak, NULL, ro, o_flgs, 0, NULL); \ } #define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, stcb, vrf_id) \ { \ - if (stcb && stcb->sctp_ep) \ + struct sctp_tcb *local_stcb = stcb; \ + if (local_stcb && local_stcb->sctp_ep) \ result = ip6_output(o_pak, \ - ((struct in6pcb *)(stcb->sctp_ep))->in6p_outputopts, \ + ((struct in6pcb *)(local_stcb->sctp_ep))->in6p_outputopts, \ (ro), 0, 0, ifp, NULL); \ else \ result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \ diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 7038067bcd1..fb39917eb11 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3686,7 +3686,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, * Stop any running T3 * timers here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0)) { net->dest_state &= ~SCTP_ADDR_PF; SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination %p moved from PF to unreachable.\n", net); @@ -3740,6 +3741,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && (stcb) && (stcb->asoc.loopback_scope))) { @@ -3748,17 +3752,16 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else { SCTP_STAT_INCR(sctps_sendnocrc); } +#endif SCTP_ENABLE_UDP_CSUM(o_pak); } else { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - m->m_pkthdr.csum_flags = CSUM_SCTP; - m->m_pkthdr.csum_data = 0; - SCTP_STAT_INCR(sctps_sendhwcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + m->m_pkthdr.csum_flags = CSUM_SCTP; + m->m_pkthdr.csum_data = 0; + SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -3800,9 +3803,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, mtu -= sizeof(struct udphdr); } if (mtu && (stcb->asoc.smallest_mtu > mtu)) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("sctp_mtu_size_reset called after ip_output mtu-change:%d\n", mtu); -#endif sctp_mtu_size_reset(inp, &stcb->asoc, mtu); net->mtu = mtu; } @@ -4050,6 +4050,9 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, #endif SCTP_ATTACH_CHAIN(o_pak, m, packet_length); if (port) { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && (stcb) && (stcb->asoc.loopback_scope))) { @@ -4058,10 +4061,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else { SCTP_STAT_INCR(sctps_sendnocrc); } +#endif if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), packet_length - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } } else { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && (stcb) && (stcb->asoc.loopback_scope))) { @@ -4071,6 +4078,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else { SCTP_STAT_INCR(sctps_sendnocrc); } +#endif } /* send it out. table id is taken from stcb */ #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) @@ -4123,10 +4131,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, ro->ro_rt); if (mtu && (stcb->asoc.smallest_mtu > mtu)) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("sctp_mtu_size_reset called after ip6_output mtu-change:%d\n", - mtu); -#endif sctp_mtu_size_reset(inp, &stcb->asoc, mtu); net->mtu = mtu; if (net->port) { @@ -4136,10 +4140,6 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } else if (ifp) { if (ND_IFINFO(ifp)->linkmtu && (stcb->asoc.smallest_mtu > ND_IFINFO(ifp)->linkmtu)) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("sctp_mtu_size_reset called via ifp ND_IFINFO() linkmtu:%d\n", - ND_IFINFO(ifp)->linkmtu); -#endif sctp_mtu_size_reset(inp, &stcb->asoc, ND_IFINFO(ifp)->linkmtu); @@ -4323,11 +4323,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) { pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; } - /* - * EY if the initiator supports nr_sacks, need to report that to - * responder in INIT chunk - */ - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { + if (stcb->asoc.sctp_nr_sack_on_off == 1) { pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; } p_len = sizeof(*pr_supported) + num_ext; @@ -5447,10 +5443,6 @@ do_a_abort: pr_supported->chunk_types[num_ext++] = SCTP_STREAM_RESET; if (!SCTP_BASE_SYSCTL(sctp_auth_disable)) pr_supported->chunk_types[num_ext++] = SCTP_AUTHENTICATION; - /* - * EY if the sysctl variable is set, tell the assoc. initiator that - * we do nr_sack - */ if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) pr_supported->chunk_types[num_ext++] = SCTP_NR_SELECTIVE_ACK; p_len = sizeof(*pr_supported) + num_ext; @@ -5736,7 +5728,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb, while (chk) { nchk = TAILQ_NEXT(chk, sctp_next); /* Here we must move to the sent queue and mark */ - if (PR_SCTP_TTL_ENABLED(chk->flags)) { + if (PR_SCTP_BUF_ENABLED(chk->flags)) { if (chk->rec.data.timetodrop.tv_sec >= (long)srcv->sinfo_timetolive) { if (chk->data) { /* @@ -5908,10 +5900,10 @@ sctp_msg_append(struct sctp_tcb *stcb, sp->strseq = 0; if (sp->sinfo_flags & SCTP_ADDR_OVER) { sp->net = net; + atomic_add_int(&sp->net->ref_count, 1); } else { - sp->net = stcb->asoc.primary_destination; + sp->net = NULL; } - atomic_add_int(&sp->net->ref_count, 1); (void)SCTP_GETTIME_TIMEVAL(&sp->ts); sp->stream = srcv->sinfo_stream; sp->msg_is_complete = 1; @@ -6510,7 +6502,6 @@ sctp_toss_old_asconf(struct sctp_tcb *stcb) static void sctp_clean_up_datalist(struct sctp_tcb *stcb, - struct sctp_association *asoc, struct sctp_tmit_chunk **data_list, int bundle_at, @@ -6521,7 +6512,9 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, for (i = 0; i < bundle_at; i++) { /* off of the send queue */ - if (i) { + TAILQ_REMOVE(&asoc->send_queue, data_list[i], sctp_next); + asoc->send_queue_cnt--; + if (i > 0) { /* * Any chunk NOT 0 you zap the time chunk 0 gets * zapped or set based on if a RTO measurment is @@ -6532,9 +6525,10 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, /* record time */ data_list[i]->sent_rcv_time = net->last_sent_time; data_list[i]->rec.data.fast_retran_tsn = data_list[i]->rec.data.TSN_seq; - TAILQ_REMOVE(&asoc->send_queue, - data_list[i], - sctp_next); + if (data_list[i]->whoTo == NULL) { + data_list[i]->whoTo = net; + atomic_add_int(&net->ref_count, 1); + } /* on to the sent queue */ tp1 = TAILQ_LAST(&asoc->sent_queue, sctpchunk_listhead); if ((tp1) && (compare_with_wrap(tp1->rec.data.TSN_seq, @@ -6562,7 +6556,6 @@ sctp_clean_up_datalist(struct sctp_tcb *stcb, all_done: /* This does not lower until the cum-ack passes it */ asoc->sent_queue_cnt++; - asoc->send_queue_cnt--; if ((asoc->peers_rwnd <= 0) && (asoc->total_flight == 0) && (bundle_at == 1)) { @@ -6700,7 +6693,7 @@ sctp_can_we_split_this(struct sctp_tcb *stcb, } static uint32_t -sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, +sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_stream_out *strq, uint32_t goal_mtu, uint32_t frag_point, @@ -6769,7 +6762,10 @@ one_more_time: } atomic_subtract_int(&asoc->stream_queue_cnt, 1); TAILQ_REMOVE(&strq->outqueue, sp, next); - sctp_free_remote_addr(sp->net); + if (sp->net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } if (sp->data) { sctp_m_freem(sp->data); sp->data = NULL; @@ -7086,8 +7082,11 @@ dont_do_it: chk->rec.data.timetodrop = sp->ts; chk->flags = sp->act_flags; - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); + if (sp->net) { + chk->whoTo = sp->net; + atomic_add_int(&chk->whoTo->ref_count, 1); + } else + chk->whoTo = NULL; if (sp->holds_key_ref) { chk->auth_keyid = sp->auth_keyid; @@ -7172,7 +7171,10 @@ dont_do_it: send_lock_up = 1; } TAILQ_REMOVE(&strq->outqueue, sp, next); - sctp_free_remote_addr(sp->net); + if (sp->net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } if (sp->data) { sctp_m_freem(sp->data); sp->data = NULL; @@ -7245,30 +7247,29 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, goal_mtu &= 0xfffffffc; if (asoc->locked_on_sending) { /* We are stuck on one stream until the message completes. */ - strqn = strq = asoc->locked_on_sending; + strq = asoc->locked_on_sending; locked = 1; } else { - strqn = strq = sctp_select_a_stream(stcb, asoc); + strq = sctp_select_a_stream(stcb, asoc); locked = 0; } - + strqn = strq; while ((goal_mtu > 0) && strq) { sp = TAILQ_FIRST(&strq->outqueue); - /* - * If CMT is off, we must validate that the stream in - * question has the first item pointed towards are network - * destionation requested by the caller. Note that if we - * turn out to be locked to a stream (assigning TSN's then - * we must stop, since we cannot look for another stream - * with data to send to that destination). In CMT's case, by - * skipping this check, we will send one data packet towards - * the requested net. - */ if (sp == NULL) { break; } - if ((sp->net != net) && (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { - /* none for this network */ + /** + * Honor the users' choice if given. If not given, + * pull it only to the primary path in case of not using + * CMT. + */ + if (((sp->net != NULL) && + (sp->net != net)) || + ((sp->net == NULL) && + (asoc->sctp_cmt_on_off == 0) && + (asoc->primary_destination != net))) { + /* Do not pull to this network */ if (locked) { break; } else { @@ -7285,7 +7286,7 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, } giveup = 0; bail = 0; - moved_how_much = sctp_move_to_outqueue(stcb, net, strq, goal_mtu, frag_point, &locked, + moved_how_much = sctp_move_to_outqueue(stcb, strq, goal_mtu, frag_point, &locked, &giveup, eeor_mode, &bail); if (moved_how_much) asoc->last_out_stream = strq; @@ -7326,11 +7327,11 @@ sctp_fill_outqueue(struct sctp_tcb *stcb, *quit_now = 1; if (total_moved == 0) { - if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) && + if ((stcb->asoc.sctp_cmt_on_off == 0) && (net == stcb->asoc.primary_destination)) { /* ran dry for primary network net */ SCTP_STAT_INCR(sctps_primary_randry); - } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + } else if (stcb->asoc.sctp_cmt_on_off == 1) { /* ran dry with CMT on */ SCTP_STAT_INCR(sctps_cmt_randry); } @@ -7349,42 +7350,32 @@ sctp_fix_ecn_echo(struct sctp_association *asoc) } } -static void -sctp_move_to_an_alt(struct sctp_tcb *stcb, - struct sctp_association *asoc, - struct sctp_nets *net) +void +sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net) { + struct sctp_association *asoc; + struct sctp_stream_out *outs; struct sctp_tmit_chunk *chk; - struct sctp_nets *a_net; + struct sctp_stream_queue_pending *sp; - SCTP_TCB_LOCK_ASSERT(stcb); - /* - * JRS 5/14/07 - If CMT PF is turned on, find an alternate - * destination using the PF algorithm for finding alternate - * destinations. - */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { - a_net = sctp_find_alternate_net(stcb, net, 2); - } else { - a_net = sctp_find_alternate_net(stcb, net, 0); + if (net == NULL) { + return; } - if ((a_net != net) && - ((a_net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE)) { - /* - * We only proceed if a valid alternate is found that is not - * this one and is reachable. Here we must move all chunks - * queued in the send queue off of the destination address - * to our alternate. - */ - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->whoTo == net) { - /* Move the chunk to our alternate */ - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = a_net; - atomic_add_int(&a_net->ref_count, 1); + asoc = &stcb->asoc; + TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { + TAILQ_FOREACH(sp, &outs->outqueue, next) { + if (sp->net == net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; } } } + TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { + if (chk->whoTo == net) { + sctp_free_remote_addr(chk->whoTo); + chk->whoTo = NULL; + } + } } int @@ -7416,7 +7407,7 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, /* temp arrays for unlinking */ struct sctp_tmit_chunk *data_list[SCTP_MAX_DATA_BUNDLING]; int no_fragmentflg, error; - unsigned int max_rwnd_per_dest; + unsigned int max_rwnd_per_dest, max_send_per_dest; int one_chunk, hbflag, skip_data_for_this_net; int asconf, cookie, no_out_cnt; int bundle_at, ctl_cnt, no_data_chunks, eeor_mode; @@ -7478,6 +7469,10 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, } } max_rwnd_per_dest = ((asoc->peers_rwnd + asoc->total_flight) / asoc->numnets); + if (stcb->sctp_socket) + max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; + else + max_send_per_dest = 0; if ((no_data_chunks == 0) && (!TAILQ_EMPTY(&asoc->out_wheel))) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* @@ -7492,14 +7487,17 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, * copy by reference (we hope). */ net->window_probe = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || + (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 1, SCTP_CWND_LOG_FILL_OUTQ_CALLED); } continue; } - if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) && (net->ref_count < 2)) { + if ((asoc->sctp_cmt_on_off == 0) && + (asoc->primary_destination != net) && + (net->ref_count < 2)) { /* nothing can be in queue for this guy */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 2, @@ -7528,13 +7526,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, } /* now service each destination and send out what we can for it */ /* Nothing to send? */ - if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && - (TAILQ_FIRST(&asoc->asconf_send_queue) == NULL) && - (TAILQ_FIRST(&asoc->send_queue) == NULL)) { + if (TAILQ_EMPTY(&asoc->control_send_queue) && + TAILQ_EMPTY(&asoc->asconf_send_queue) && + TAILQ_EMPTY(&asoc->send_queue)) { *reason_code = 8; return (0); } - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + if (asoc->sctp_cmt_on_off == 1) { /* get the last start point */ start_at = asoc->last_net_cmt_send_started; if (start_at == NULL) { @@ -7560,15 +7558,17 @@ again_one_more_time: break; } tsns_sent = 0xa; - if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0) && (net->ref_count < 2)) { + if ((asoc->sctp_cmt_on_off == 0) && + (asoc->primary_destination != net) && + (net->ref_count < 2)) { /* * Ref-count of 1 so we cannot have data or control * queued to this address. Skip it (non-CMT). */ continue; } - if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && - (TAILQ_FIRST(&asoc->asconf_send_queue) == NULL) && + if (TAILQ_EMPTY(&asoc->control_send_queue) && + TAILQ_EMPTY(&asoc->asconf_send_queue) && (net->flight_size >= net->cwnd)) { /* * Nothing on control or asconf and flight is full, @@ -7772,7 +7772,7 @@ again_one_more_time: * unreachable * during this send */ - sctp_move_to_an_alt(stcb, asoc, net); + sctp_move_chunks_from_net(stcb, net); } *reason_code = 7; continue; @@ -7995,7 +7995,7 @@ again_one_more_time: * unreachable * during this send */ - sctp_move_to_an_alt(stcb, asoc, net); + sctp_move_chunks_from_net(stcb, net); } *reason_code = 7; continue; @@ -8034,18 +8034,31 @@ again_one_more_time: } } /* JRI: if dest is in PF state, do not send data to it */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && (net->dest_state & SCTP_ADDR_PF)) { goto no_data_fill; } if (net->flight_size >= net->cwnd) { goto no_data_fill; } - if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off)) && + if ((asoc->sctp_cmt_on_off == 1) && + (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_RECV_BUFFER_SPLITTING) && (net->flight_size > max_rwnd_per_dest)) { goto no_data_fill; } + /* + * We need a specific accounting for the usage of the send + * buffer. We also need to check the number of messages per + * net. For now, this is better than nothing and it disabled + * by default... + */ + if ((asoc->sctp_cmt_on_off == 1) && + (SCTP_BASE_SYSCTL(sctp_buffer_splitting) & SCTP_SEND_BUFFER_SPLITTING) && + (max_send_per_dest > 0) && + (net->flight_size > max_send_per_dest)) { + goto no_data_fill; + } /*********************/ /* Data transmission */ /*********************/ @@ -8096,19 +8109,9 @@ again_one_more_time: break; } nchk = TAILQ_NEXT(chk, sctp_next); - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { - if (chk->whoTo != net) { - /* - * For CMT, steal the data - * to this network if its - * not set here. - */ - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); - } - } else if (chk->whoTo != net) { - /* No, not sent to this net */ + if ((chk->whoTo != NULL) && + (chk->whoTo != net)) { + /* Don't send the chunk on this net */ continue; } if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { @@ -8271,8 +8274,8 @@ no_data_fill: * restart it. */ sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + } else if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && pf_hbflag && ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) && (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) { @@ -8324,7 +8327,7 @@ no_data_fill: * Destination went unreachable * during this send */ - sctp_move_to_an_alt(stcb, asoc, net); + sctp_move_chunks_from_net(stcb, net); } *reason_code = 6; /*- @@ -9578,9 +9581,9 @@ sctp_chunk_output(struct sctp_inpcb *inp, * out wheel to this alternate address. */ if (net->ref_count > 1) - sctp_move_to_an_alt(stcb, asoc, net); - } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && - SCTP_BASE_SYSCTL(sctp_cmt_pf) && + sctp_move_chunks_from_net(stcb, net); + } else if ((asoc->sctp_cmt_on_off == 1) && + (asoc->sctp_cmt_pf > 0) && ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { /* * JRS 5/14/07 - If CMT PF is on and the current @@ -9588,7 +9591,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, * to an alternate desination. */ if (net->ref_count > 1) - sctp_move_to_an_alt(stcb, asoc, net); + sctp_move_chunks_from_net(stcb, net); } else { /*- * if ((asoc->sat_network) || (net->addr_is_local)) @@ -9834,9 +9837,12 @@ sctp_fill_in_rest: at = TAILQ_FIRST(&asoc->sent_queue); for (i = 0; i < cnt_of_skipped; i++) { tp1 = TAILQ_NEXT(at, sctp_next); + if (tp1 == NULL) { + break; + } at = tp1; } - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { + if (at && SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) { sctp_misc_ints(SCTP_FWD_TSN_CHECK, 0xff, cnt_of_skipped, at->rec.data.TSN_seq, asoc->advanced_peer_ack_point); @@ -9846,7 +9852,8 @@ sctp_fill_in_rest: * last now points to last one I can report, update * peer ack point */ - advance_peer_ack_point = last->rec.data.TSN_seq; + if (last) + advance_peer_ack_point = last->rec.data.TSN_seq; space_needed = sizeof(struct sctp_forward_tsn_chunk) + cnt_of_skipped * sizeof(struct sctp_strseq); } @@ -9879,6 +9886,8 @@ sctp_fill_in_rest: at = TAILQ_FIRST(&asoc->sent_queue); for (i = 0; i < cnt_of_skipped; i++) { tp1 = TAILQ_NEXT(at, sctp_next); + if (tp1 == NULL) + break; if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) { /* We don't report these */ i--; @@ -9926,8 +9935,8 @@ sctp_send_sack(struct sctp_tcb *stcb) uint8_t flags; uint8_t type; - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && - stcb->asoc.peer_supports_nr_sack) { + if ((stcb->asoc.sctp_nr_sack_on_off == 1) && + (stcb->asoc.peer_supports_nr_sack == 1)) { type = SCTP_NR_SELECTIVE_ACK; } else { type = SCTP_SELECTIVE_ACK; @@ -10071,7 +10080,8 @@ sctp_send_sack(struct sctp_tcb *stcb) else flags = 0; - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { + if ((asoc->sctp_cmt_on_off == 1) && + SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) { /*- * CMT DAC algorithm: If 2 (i.e., 0x10) packets have been * received, then set high bit to 1, else 0. Reset @@ -10553,7 +10563,8 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, udp->uh_sport = htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)); udp->uh_dport = port; udp->uh_ulen = htons(sizeof(struct sctp_shutdown_complete_msg) + sizeof(struct udphdr)); - udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); + if (iph_out) + udp->uh_sum = in_pseudo(iph_out->ip_src.s_addr, iph_out->ip_dst.s_addr, udp->uh_ulen + htons(IPPROTO_UDP)); offset_out += sizeof(struct udphdr); comp_cp = (struct sctp_shutdown_complete_msg *)((caddr_t)comp_cp + sizeof(struct udphdr)); } @@ -10574,7 +10585,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (iph_out != NULL) { sctp_route_t ro; int ret; - struct sctp_tcb *stcb = NULL; mlen = SCTP_BUF_LEN(mout); bzero(&ro, sizeof ro); @@ -10585,17 +10595,25 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, sctp_packet_log(mout, mlen); #endif if (port) { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else comp_cp->sh.checksum = sctp_calculate_cksum(mout, offset_out); SCTP_STAT_INCR(sctps_sendswcrc); +#endif SCTP_ENABLE_UDP_CSUM(mout); } else { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else mout->m_pkthdr.csum_flags = CSUM_SCTP; mout->m_pkthdr.csum_data = 0; SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } SCTP_ATTACH_CHAIN(o_pak, mout, mlen); /* out it goes */ - SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); + SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -10605,7 +10623,6 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, if (ip6_out != NULL) { struct route_in6 ro; int ret; - struct sctp_tcb *stcb = NULL; struct ifnet *ifp = NULL; bzero(&ro, sizeof(ro)); @@ -10616,29 +10633,25 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, #endif SCTP_ATTACH_CHAIN(o_pak, mout, mlen); if (port) { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - comp_cp->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + comp_cp->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); +#endif if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), mlen - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } } else { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - mout->m_pkthdr.csum_flags = CSUM_SCTP; - mout->m_pkthdr.csum_data = 0; - SCTP_STAT_INCR(sctps_sendhwcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; + SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } - SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); + SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -10839,7 +10852,8 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net) * heartbeat is being sent is in PF state, do NOT do threshold * management. */ - if ((SCTP_BASE_SYSCTL(sctp_cmt_pf) == 0) || ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) { + if ((stcb->asoc.sctp_cmt_pf == 0) || + ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) { /* ok we have a destination that needs a beat */ /* lets do the theshold management Qiaobing style */ if (sctp_threshold_management(stcb->sctp_ep, stcb, net, @@ -11003,9 +11017,12 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, switch (ch->chunk_type) { case SCTP_PACKET_DROPPED: case SCTP_ABORT_ASSOCIATION: - /*- - * we don't respond with an PKT-DROP to an ABORT - * or PKT-DROP + case SCTP_INITIATION_ACK: + /** + * We don't respond with an PKT-DROP to an ABORT + * or PKT-DROP. We also do not respond to an + * INIT-ACK, because we can't know if the initiation + * tag is correct or not. */ sctp_free_a_chunk(stcb, chk); return; @@ -11631,7 +11648,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, } if (iph_out != NULL) { sctp_route_t ro; - struct sctp_tcb *stcb = NULL; int ret; /* zap the stack pointer to the route */ @@ -11651,15 +11667,23 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else abm->sh.checksum = sctp_calculate_cksum(mout, iphlen_out); SCTP_STAT_INCR(sctps_sendswcrc); +#endif SCTP_ENABLE_UDP_CSUM(o_pak); } else { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else mout->m_pkthdr.csum_flags = CSUM_SCTP; mout->m_pkthdr.csum_data = 0; SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } - SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); + SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -11669,7 +11693,6 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, if (ip6_out != NULL) { struct route_in6 ro; int ret; - struct sctp_tcb *stcb = NULL; struct ifnet *ifp = NULL; /* zap the stack pointer to the route */ @@ -11686,29 +11709,25 @@ sctp_send_abort(struct mbuf *m, int iphlen, struct sctphdr *sh, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - abm->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + abm->sh.checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); +#endif if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } } else { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - mout->m_pkthdr.csum_flags = CSUM_SCTP; - mout->m_pkthdr.csum_data = 0; - SCTP_STAT_INCR(sctps_sendhwcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; + SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } - SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); + SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -11871,7 +11890,6 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, } if (iph_out != NULL) { sctp_route_t ro; - struct sctp_tcb *stcb = NULL; int ret; /* zap the stack pointer to the route */ @@ -11889,15 +11907,23 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else sh_out->checksum = sctp_calculate_cksum(mout, iphlen_out); SCTP_STAT_INCR(sctps_sendswcrc); +#endif SCTP_ENABLE_UDP_CSUM(o_pak); } else { +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else mout->m_pkthdr.csum_flags = CSUM_SCTP; mout->m_pkthdr.csum_data = 0; SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } - SCTP_IP_OUTPUT(ret, o_pak, &ro, stcb, vrf_id); + SCTP_IP_OUTPUT(ret, o_pak, &ro, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -11907,7 +11933,6 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, if (ip6_out != NULL) { struct route_in6 ro; int ret; - struct sctp_tcb *stcb = NULL; struct ifnet *ifp = NULL; /* zap the stack pointer to the route */ @@ -11922,29 +11947,25 @@ sctp_send_operr_to(struct mbuf *m, int iphlen, struct mbuf *scm, uint32_t vtag, #endif SCTP_ATTACH_CHAIN(o_pak, mout, len); if (port) { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - sh_out->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); - SCTP_STAT_INCR(sctps_sendswcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + sh_out->checksum = sctp_calculate_cksum(mout, sizeof(struct ip6_hdr) + sizeof(struct udphdr)); + SCTP_STAT_INCR(sctps_sendswcrc); +#endif if ((udp->uh_sum = in6_cksum(o_pak, IPPROTO_UDP, sizeof(struct ip6_hdr), len - sizeof(struct ip6_hdr))) == 0) { udp->uh_sum = 0xffff; } } else { - if (!(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) && - (stcb) && - (stcb->asoc.loopback_scope))) { - mout->m_pkthdr.csum_flags = CSUM_SCTP; - mout->m_pkthdr.csum_data = 0; - SCTP_STAT_INCR(sctps_sendhwcrc); - } else { - SCTP_STAT_INCR(sctps_sendnocrc); - } +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_sendnocrc); +#else + mout->m_pkthdr.csum_flags = CSUM_SCTP; + mout->m_pkthdr.csum_data = 0; + SCTP_STAT_INCR(sctps_sendhwcrc); +#endif } - SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, stcb, vrf_id); + SCTP_IP6_OUTPUT(ret, o_pak, &ro, &ifp, NULL, vrf_id); /* Free the route if we got one back */ if (ro.ro_rt) @@ -12079,10 +12100,10 @@ skip_copy: } else { if (sp->sinfo_flags & SCTP_ADDR_OVER) { sp->net = net; + atomic_add_int(&sp->net->ref_count, 1); } else { - sp->net = asoc->primary_destination; + sp->net = NULL; } - atomic_add_int(&sp->net->ref_count, 1); sctp_set_prsctp_policy(sp); } out_now: @@ -12100,17 +12121,15 @@ sctp_sosend(struct socket *so, struct thread *p ) { - struct sctp_inpcb *inp; int error, use_rcvinfo = 0; struct sctp_sndrcvinfo srcv; struct sockaddr *addr_to_use; -#ifdef INET6 +#if defined(INET) && defined(INET6) struct sockaddr_in sin; #endif - inp = (struct sctp_inpcb *)so->so_pcb; if (control) { /* process cmsg snd/rcv info (maybe a assoc-id) */ if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&srcv, control, @@ -12120,7 +12139,7 @@ sctp_sosend(struct socket *so, } } addr_to_use = addr; -#if defined(INET6) && !defined(__Userspace__) /* TODO port in6_sin6_2_sin */ +#if defined(INET) && defined(INET6) if ((addr) && (addr->sa_family == AF_INET6)) { struct sockaddr_in6 *sin6; @@ -12134,7 +12153,7 @@ sctp_sosend(struct socket *so, error = sctp_lower_sosend(so, addr_to_use, uio, top, control, flags, - use_rcvinfo, &srcv + use_rcvinfo ? &srcv : NULL ,p ); return (error); @@ -12148,7 +12167,6 @@ sctp_lower_sosend(struct socket *so, struct mbuf *i_pak, struct mbuf *control, int flags, - int use_rcvinfo, struct sctp_sndrcvinfo *srcv , struct thread *p @@ -12159,7 +12177,7 @@ sctp_lower_sosend(struct socket *so, struct mbuf *top = NULL; int queue_only = 0, queue_only_for_init = 0; int free_cnt_applied = 0; - int un_sent = 0; + int un_sent; int now_filled = 0; unsigned int inqueue_bytes = 0; struct sctp_block_entry be; @@ -12176,8 +12194,10 @@ sctp_lower_sosend(struct socket *so, int got_all_of_the_send = 0; int hold_tcblock = 0; int non_blocking = 0; - int temp_flags = 0; uint32_t local_add_more, local_soresv = 0; + uint16_t port; + uint16_t sinfo_flags; + sctp_assoc_t sinfo_assoc_id; error = 0; net = NULL; @@ -12212,25 +12232,6 @@ sctp_lower_sosend(struct socket *so, SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %d\n", addr, sndlen); - /*- - * Pre-screen address, if one is given the sin-len - * must be set correctly! - */ - if (addr) { - if ((addr->sa_family == AF_INET) && - (addr->sa_len != sizeof(struct sockaddr_in))) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } else if ((addr->sa_family == AF_INET6) && - (addr->sa_len != sizeof(struct sockaddr_in6))) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - } - hold_tcblock = 0; - if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && (inp->sctp_socket->so_qlimit)) { /* The listener can NOT send */ @@ -12238,22 +12239,67 @@ sctp_lower_sosend(struct socket *so, error = ENOTCONN; goto out_unlocked; } - if ((use_rcvinfo) && srcv) { - if (INVALID_SINFO_FLAG(srcv->sinfo_flags) || - PR_SCTP_INVALID_POLICY(srcv->sinfo_flags)) { + /** + * Pre-screen address, if one is given the sin-len + * must be set correctly! + */ + if (addr) { + union sctp_sockstore *raddr = (union sctp_sockstore *)addr; + + switch (raddr->sa.sa_family) { +#if defined(INET) + case AF_INET: + if (raddr->sin.sin_len != sizeof(struct sockaddr_in)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; + } + port = raddr->sin.sin_port; + break; +#endif +#if defined(INET6) + case AF_INET6: + if (raddr->sin6.sin6_len != sizeof(struct sockaddr_in6)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; + } + port = raddr->sin6.sin6_port; + break; +#endif + default: + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EAFNOSUPPORT); + error = EAFNOSUPPORT; + goto out_unlocked; + } + } else + port = 0; + + if (srcv) { + sinfo_flags = srcv->sinfo_flags; + sinfo_assoc_id = srcv->sinfo_assoc_id; + if (INVALID_SINFO_FLAG(sinfo_flags) || + PR_SCTP_INVALID_POLICY(sinfo_flags)) { SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); error = EINVAL; goto out_unlocked; } if (srcv->sinfo_flags) SCTP_STAT_INCR(sctps_sends_with_flags); - - if (srcv->sinfo_flags & SCTP_SENDALL) { - /* its a sendall */ - error = sctp_sendall(inp, uio, top, srcv); - top = NULL; - goto out_unlocked; - } + } else { + sinfo_flags = inp->def_send.sinfo_flags; + sinfo_assoc_id = inp->def_send.sinfo_assoc_id; + } + if (sinfo_flags & SCTP_SENDALL) { + /* its a sendall */ + error = sctp_sendall(inp, uio, top, srcv); + top = NULL; + goto out_unlocked; + } + if ((sinfo_flags & SCTP_ADDR_OVER) && (addr == NULL)) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; } /* now we must find the assoc */ if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || @@ -12269,80 +12315,8 @@ sctp_lower_sosend(struct socket *so, SCTP_TCB_LOCK(stcb); hold_tcblock = 1; SCTP_INP_RUNLOCK(inp); - if (addr) { - /* Must locate the net structure if addr given */ - net = sctp_findnet(stcb, addr); - if (net) { - /* validate port was 0 or correct */ - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if ((sin->sin_port != 0) && - (sin->sin_port != stcb->rport)) { - net = NULL; - } - } - temp_flags |= SCTP_ADDR_OVER; - } else - net = stcb->asoc.primary_destination; - if (addr && (net == NULL)) { - /* Could not find address, was it legal */ - if (addr->sa_family == AF_INET) { - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *)addr; - if (sin->sin_addr.s_addr == 0) { - if ((sin->sin_port == 0) || - (sin->sin_port == stcb->rport)) { - net = stcb->asoc.primary_destination; - } - } - } else { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *)addr; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - if ((sin6->sin6_port == 0) || - (sin6->sin6_port == stcb->rport)) { - net = stcb->asoc.primary_destination; - } - } - } - } - if (net == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - } else if (use_rcvinfo && srcv && srcv->sinfo_assoc_id) { - stcb = sctp_findassociation_ep_asocid(inp, srcv->sinfo_assoc_id, 0); - if (stcb) { - if (addr) - /* - * Must locate the net structure if addr - * given - */ - net = sctp_findnet(stcb, addr); - else - net = stcb->asoc.primary_destination; - if ((srcv->sinfo_flags & SCTP_ADDR_OVER) && - ((net == NULL) || (addr == NULL))) { - struct sockaddr_in *sin; - - if (addr == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - sin = (struct sockaddr_in *)addr; - /* Validate port is 0 or correct */ - if ((sin->sin_port != 0) && - (sin->sin_port != stcb->rport)) { - net = NULL; - } - } - } - hold_tcblock = 0; + } else if (sinfo_assoc_id) { + stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 0); } else if (addr) { /*- * Since we did not use findep we must @@ -12415,10 +12389,8 @@ sctp_lower_sosend(struct socket *so, */ uint32_t vrf_id; - if ((use_rcvinfo) && (srcv) && - ((srcv->sinfo_flags & SCTP_ABORT) || - ((srcv->sinfo_flags & SCTP_EOF) && - (sndlen == 0)))) { + if ((sinfo_flags & SCTP_ABORT) || + ((sinfo_flags & SCTP_EOF) && (sndlen == 0))) { /*- * User asks to abort a non-existant assoc, * or EOF a non-existant assoc with no data @@ -12547,17 +12519,29 @@ sctp_lower_sosend(struct socket *so, * structure may now have an update and thus we may need to * change it BEFORE we append the message. */ - net = stcb->asoc.primary_destination; - asoc = &stcb->asoc; } + } else + asoc = &stcb->asoc; + if (srcv == NULL) + srcv = (struct sctp_sndrcvinfo *)&asoc->def_send; + if (srcv->sinfo_flags & SCTP_ADDR_OVER) { + if (addr) + net = sctp_findnet(stcb, addr); + else + net = NULL; + if ((net == NULL) || + ((port != 0) && (port != stcb->rport))) { + SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; + } + } else { + net = stcb->asoc.primary_destination; } - if ((SCTP_SO_IS_NBIO(so) - || (flags & MSG_NBIO) - )) { - non_blocking = 1; - } - asoc = &stcb->asoc; atomic_add_int(&stcb->total_sends, 1); + /* Keep the stcb from being freed under our feet */ + atomic_add_int(&asoc->refcnt, 1); + free_cnt_applied = 1; if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) { if (sndlen > asoc->smallest_mtu) { @@ -12566,6 +12550,11 @@ sctp_lower_sosend(struct socket *so, goto out_unlocked; } } + if ((SCTP_SO_IS_NBIO(so) + || (flags & MSG_NBIO) + )) { + non_blocking = 1; + } /* would we block? */ if (non_blocking) { if (hold_tcblock == 0) { @@ -12589,17 +12578,6 @@ sctp_lower_sosend(struct socket *so, atomic_add_int(&stcb->asoc.sb_send_resv, sndlen); } local_soresv = sndlen; - /* Keep the stcb from being freed under our feet */ - if (free_cnt_applied) { -#ifdef INVARIANTS - panic("refcnt already incremented"); -#else - printf("refcnt:1 already incremented?\n"); -#endif - } else { - atomic_add_int(&stcb->asoc.refcnt, 1); - free_cnt_applied = 1; - } if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); error = ECONNRESET; @@ -12621,10 +12599,6 @@ sctp_lower_sosend(struct socket *so, (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)) { queue_only = 1; } - if ((use_rcvinfo == 0) || (srcv == NULL)) { - /* Grab the default stuff from the asoc */ - srcv = (struct sctp_sndrcvinfo *)&stcb->asoc.def_send; - } /* we are now done with all control */ if (control) { sctp_m_freem(control); @@ -12634,8 +12608,7 @@ sctp_lower_sosend(struct socket *so, (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED) || (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_ACK_SENT) || (asoc->state & SCTP_STATE_SHUTDOWN_PENDING)) { - if ((use_rcvinfo) && - (srcv->sinfo_flags & SCTP_ABORT)) { + if (srcv->sinfo_flags & SCTP_ABORT) { ; } else { SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET); @@ -12647,35 +12620,6 @@ sctp_lower_sosend(struct socket *so, if (p) { p->td_ru.ru_msgsnd++; } - if (stcb) { - if (((srcv->sinfo_flags | temp_flags) & SCTP_ADDR_OVER) == 0) { - net = stcb->asoc.primary_destination; - } - } - if (net == NULL) { - SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); - error = EINVAL; - goto out_unlocked; - } - if ((net->flight_size > net->cwnd) && (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { - /*- - * CMT: Added check for CMT above. net above is the primary - * dest. If CMT is ON, sender should always attempt to send - * with the output routine sctp_fill_outqueue() that loops - * through all destination addresses. Therefore, if CMT is - * ON, queue_only is NOT set to 1 here, so that - * sctp_chunk_output() can be called below. - */ - queue_only = 1; - } else if (asoc->ifp_had_enobuf) { - SCTP_STAT_INCR(sctps_ifnomemqueued); - if (net->flight_size > (net->mtu * 2)) - queue_only = 1; - asoc->ifp_had_enobuf = 0; - } else { - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); - } /* Are we aborting? */ if (srcv->sinfo_flags & SCTP_ABORT) { struct mbuf *mm; @@ -12879,7 +12823,6 @@ sctp_lower_sosend(struct socket *so, } inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); } - inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * sizeof(struct sctp_data_chunk)); if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) { max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes; } else { @@ -12908,9 +12851,7 @@ skip_preblock: if (top == NULL) { struct sctp_stream_queue_pending *sp; struct sctp_stream_out *strm; - uint32_t sndout, initial_out; - - initial_out = uio->uio_resid; + uint32_t sndout; SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && @@ -13074,29 +13015,34 @@ skip_preblock: /* Non-blocking io in place out */ goto skip_out_eof; } + /* What about the INIT, send it maybe */ + if (queue_only_for_init) { + if (hold_tcblock == 0) { + SCTP_TCB_LOCK(stcb); + hold_tcblock = 1; + } + if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + /* a collision took us forward? */ + queue_only = 0; + } else { + sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); + SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT); + queue_only = 1; + } + } if ((net->flight_size > net->cwnd) && - (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { + (asoc->sctp_cmt_on_off == 0)) { + SCTP_STAT_INCR(sctps_send_cwnd_avoid); queue_only = 1; } else if (asoc->ifp_had_enobuf) { SCTP_STAT_INCR(sctps_ifnomemqueued); - if (net->flight_size > (net->mtu * 2)) { + if (net->flight_size > (2 * net->mtu)) { queue_only = 1; - } else { - queue_only = 0; } asoc->ifp_had_enobuf = 0; - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); - } else { - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); - if (net->flight_size > net->cwnd) { - queue_only = 1; - SCTP_STAT_INCR(sctps_send_cwnd_avoid); - } else { - queue_only = 0; - } } + un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + + (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && (stcb->asoc.total_flight > 0) && (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && @@ -13120,7 +13066,6 @@ skip_preblock: SCTP_STAT_INCR(sctps_naglesent); nagle_applies = 0; } - /* What about the INIT, send it maybe */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, @@ -13129,22 +13074,8 @@ skip_preblock: stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count); } - if (queue_only_for_init) { - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { - /* a collision took us forward? */ - queue_only_for_init = 0; - queue_only = 0; - } else { - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT); - queue_only_for_init = 0; - queue_only = 1; - } - } + if (queue_only_for_init) + queue_only_for_init = 0; if ((queue_only == 0) && (nagle_applies == 0)) { /*- * need to start chunk output @@ -13237,7 +13168,7 @@ skip_preblock: if (uio->uio_resid == 0) { got_all_of_the_send = 1; } - } else if (top) { + } else { /* We send in a 0, since we do NOT have any locks */ error = sctp_msg_append(stcb, net, top, srcv, 0); top = NULL; @@ -13348,29 +13279,33 @@ skip_out_eof: if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) { some_on_control = 1; } + if (queue_only_for_init) { + if (hold_tcblock == 0) { + SCTP_TCB_LOCK(stcb); + hold_tcblock = 1; + } + if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { + /* a collision took us forward? */ + queue_only = 0; + } else { + sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); + SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); + queue_only = 1; + } + } if ((net->flight_size > net->cwnd) && - (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { + (stcb->asoc.sctp_cmt_on_off == 0)) { + SCTP_STAT_INCR(sctps_send_cwnd_avoid); queue_only = 1; } else if (asoc->ifp_had_enobuf) { SCTP_STAT_INCR(sctps_ifnomemqueued); - if (net->flight_size > (net->mtu * 2)) { + if (net->flight_size > (2 * net->mtu)) { queue_only = 1; - } else { - queue_only = 0; } asoc->ifp_had_enobuf = 0; - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); - } else { - un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + - (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); - if (net->flight_size > net->cwnd) { - queue_only = 1; - SCTP_STAT_INCR(sctps_send_cwnd_avoid); - } else { - queue_only = 0; - } } + un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) + + (stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk))); if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) && (stcb->asoc.total_flight > 0) && (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) && @@ -13393,22 +13328,15 @@ skip_out_eof: SCTP_STAT_INCR(sctps_naglesent); nagle_applies = 0; } - if (queue_only_for_init) { - if (hold_tcblock == 0) { - SCTP_TCB_LOCK(stcb); - hold_tcblock = 1; - } - if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) { - /* a collision took us forward? */ - queue_only_for_init = 0; - queue_only = 0; - } else { - sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); - SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); - queue_only_for_init = 0; - queue_only = 1; - } + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) { + sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only, + nagle_applies, un_sent); + sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size, + stcb->asoc.total_flight, + stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count); } + if (queue_only_for_init) + queue_only_for_init = 0; if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) { /* we can attempt to send too. */ if (hold_tcblock == 0) { diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h index 6488b1cf739..d655c3aa218 100644 --- a/sys/netinet/sctp_output.h +++ b/sys/netinet/sctp_output.h @@ -129,6 +129,8 @@ void sctp_toss_old_asconf(struct sctp_tcb *); void sctp_fix_ecn_echo(struct sctp_association *); +void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net); + int sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *, struct mbuf *, struct thread *, int); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index ad8bc520433..6e32439bc23 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -517,7 +517,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index, sizeof(struct sctp_ifn), SCTP_M_IFN); if (sctp_ifnp == NULL) { #ifdef INVARIANTS - panic("No memory for IFN:%u", sctp_ifnp->ifn_index); + panic("No memory for IFN"); #endif return (NULL); } @@ -2385,6 +2385,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) inp->sctp_associd_counter = 1; inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; + inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); /* init the small hash table we use to track asocid <-> tcb */ inp->sctp_asocidhash = SCTP_HASH_INIT(SCTP_STACK_VTAG_HASH_SIZE, &inp->hashasocidmark); if (inp->sctp_asocidhash == NULL) { @@ -3915,9 +3916,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, } else { net->mtu = 0; } -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("We have found an interface mtu of %d\n", net->mtu); -#endif if (net->mtu == 0) { /* Huh ?? */ net->mtu = SCTP_DEFAULT_MTU; @@ -3925,9 +3923,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, uint32_t rmtu; rmtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._l_addr.sa, net->ro.ro_rt); -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("The route mtu is %d\n", rmtu); -#endif if (rmtu == 0) { /* * Start things off to match mtu of @@ -3945,9 +3940,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, } } if (from == SCTP_ALLOC_ASOC) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("New assoc sets mtu to :%d\n", net->mtu); -#endif stcb->asoc.smallest_mtu = net->mtu; } } else { @@ -3965,10 +3957,6 @@ sctp_add_remote_addr(struct sctp_tcb *stcb, struct sockaddr *newaddr, net->mtu -= sizeof(struct udphdr); } if (stcb->asoc.smallest_mtu > net->mtu) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("new address mtu:%d smaller than smallest:%d\n", - net->mtu, stcb->asoc.smallest_mtu); -#endif stcb->asoc.smallest_mtu = net->mtu; } /* JRS - Use the congestion control given in the CC module */ @@ -4834,7 +4822,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Still an open socket - report */ sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, - (void *)sp, 0); + (void *)sp, SCTP_SO_LOCKED); } if (sp->data) { sctp_m_freem(sp->data); @@ -4842,7 +4830,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sp->tail_mbuf = NULL; } } - sctp_free_remote_addr(sp->net); + if (sp->net) { + sctp_free_remote_addr(sp->net); + sp->net = NULL; + } sctp_free_spbufspace(stcb, asoc, sp); if (sp->holds_key_ref) sctp_auth_key_release(stcb, sp->auth_keyid); @@ -4903,7 +4894,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if (so) { /* Still a socket? */ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, - SCTP_NOTIFY_DATAGRAM_UNSENT, chk, 0); + SCTP_NOTIFY_DATAGRAM_UNSENT, chk, SCTP_SO_LOCKED); } if (chk->data) { sctp_m_freem(chk->data); @@ -4913,7 +4904,10 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if (chk->holds_key_ref) sctp_auth_key_release(stcb, chk->auth_keyid); ccnt++; - sctp_free_remote_addr(chk->whoTo); + if (chk->whoTo) { + sctp_free_remote_addr(chk->whoTo); + chk->whoTo = NULL; + } SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); SCTP_DECR_CHK_COUNT(); /* sa_ignore FREED_MEMORY */ @@ -4935,7 +4929,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre if (so) { /* Still a socket? */ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, - SCTP_NOTIFY_DATAGRAM_SENT, chk, 0); + SCTP_NOTIFY_DATAGRAM_SENT, chk, SCTP_SO_LOCKED); } if (chk->data) { sctp_m_freem(chk->data); @@ -5901,7 +5895,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } #endif default: - sa = NULL; + return (-1); break; } } else { @@ -5987,7 +5981,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, } p4 = (struct sctp_ipv4addr_param *)phdr; sin.sin_addr.s_addr = p4->addr; - if (IN_MULTICAST(sin.sin_addr.s_addr)) { + if (IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) { /* Skip multi-cast addresses */ goto next_param; } @@ -6241,10 +6235,7 @@ sctp_load_addresses_from_init(struct sctp_tcb *stcb, struct mbuf *m, stcb->asoc.peer_supports_pktdrop = 1; break; case SCTP_NR_SELECTIVE_ACK: - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) - stcb->asoc.peer_supports_nr_sack = 1; - else - stcb->asoc.peer_supports_nr_sack = 0; + stcb->asoc.peer_supports_nr_sack = 1; break; case SCTP_STREAM_RESET: stcb->asoc.peer_supports_strreset = 1; diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h index 318b0125814..23ebc4f1756 100644 --- a/sys/netinet/sctp_pcb.h +++ b/sys/netinet/sctp_pcb.h @@ -389,6 +389,7 @@ struct sctp_inpcb { uint32_t sctp_frag_point; uint32_t partial_delivery_point; uint32_t sctp_context; + uint32_t sctp_cmt_on_off; struct sctp_nonpad_sndrcvinfo def_send; /*- * These three are here for the sosend_dgram diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index 6f899b406ca..69d04c0be31 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -112,6 +112,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) n_inp->sctp_features = inp->sctp_features; n_inp->sctp_mobility_features = inp->sctp_mobility_features; n_inp->sctp_frag_point = inp->sctp_frag_point; + n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; n_inp->partial_delivery_point = inp->partial_delivery_point; n_inp->sctp_context = inp->sctp_context; n_inp->inp_starting_point_for_iterator = NULL; @@ -183,6 +184,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) (SCTP_PCB_COPY_FLAGS & inp->sctp_flags)); n_inp->sctp_features = inp->sctp_features; n_inp->sctp_frag_point = inp->sctp_frag_point; + n_inp->sctp_cmt_on_off = inp->sctp_cmt_on_off; n_inp->partial_delivery_point = inp->partial_delivery_point; n_inp->sctp_context = inp->sctp_context; n_inp->inp_starting_point_for_iterator = NULL; diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 9ba7dd40be3..9e0c56ee31f 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -54,7 +54,9 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_ecn_enable) = SCTPCTL_ECN_ENABLE_DEFAULT; SCTP_BASE_SYSCTL(sctp_ecn_nonce) = SCTPCTL_ECN_NONCE_DEFAULT; SCTP_BASE_SYSCTL(sctp_strict_sacks) = SCTPCTL_STRICT_SACKS_DEFAULT; +#if !defined(SCTP_WITH_NO_CSUM) SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback) = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT; +#endif SCTP_BASE_SYSCTL(sctp_strict_init) = SCTPCTL_STRICT_INIT_DEFAULT; SCTP_BASE_SYSCTL(sctp_peer_chunk_oh) = SCTPCTL_PEER_CHKOH_DEFAULT; SCTP_BASE_SYSCTL(sctp_max_burst_default) = SCTPCTL_MAXBURST_DEFAULT; @@ -107,6 +109,8 @@ sctp_init_sysctls() SCTP_BASE_SYSCTL(sctp_mobility_base) = SCTPCTL_MOBILITY_BASE_DEFAULT; SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff) = SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT; SCTP_BASE_SYSCTL(sctp_vtag_time_wait) = SCTPCTL_TIME_WAIT_DEFAULT; + SCTP_BASE_SYSCTL(sctp_buffer_splitting) = SCTPCTL_BUFFER_SPLITTING_DEFAULT; + SCTP_BASE_SYSCTL(sctp_initial_cwnd) = SCTPCTL_INITIAL_CWND_DEFAULT; #if defined(SCTP_LOCAL_TRACE_BUF) memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log)); #endif @@ -198,8 +202,6 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s ipv6_addr_legal = 0; } - error = 0; - /* neither Mac OS X nor FreeBSD support mulitple routing functions */ if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) { SCTP_INP_RUNLOCK(inp); @@ -568,7 +570,9 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_ecn_enable), SCTPCTL_ECN_ENABLE_MIN, SCTPCTL_ECN_ENABLE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_ecn_nonce), SCTPCTL_ECN_NONCE_MIN, SCTPCTL_ECN_NONCE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_sacks), SCTPCTL_STRICT_SACKS_MIN, SCTPCTL_STRICT_SACKS_MAX); +#if !defined(SCTP_WITH_NO_CSUM) RANGECHK(SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX); +#endif RANGECHK(SCTP_BASE_SYSCTL(sctp_strict_init), SCTPCTL_STRICT_INIT_MIN, SCTPCTL_STRICT_INIT_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_peer_chunk_oh), SCTPCTL_PEER_CHKOH_MIN, SCTPCTL_PEER_CHKOH_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_max_burst_default), SCTPCTL_MAXBURST_MIN, SCTPCTL_MAXBURST_MAX); @@ -618,7 +622,8 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS) RANGECHK(SCTP_BASE_SYSCTL(sctp_default_cc_module), SCTPCTL_DEFAULT_CC_MODULE_MIN, SCTPCTL_DEFAULT_CC_MODULE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_default_frag_interleave), SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_vtag_time_wait), SCTPCTL_TIME_WAIT_MIN, SCTPCTL_TIME_WAIT_MAX); - + RANGECHK(SCTP_BASE_SYSCTL(sctp_buffer_splitting), SCTPCTL_BUFFER_SPLITTING_MIN, SCTPCTL_BUFFER_SPLITTING_MAX); + RANGECHK(SCTP_BASE_SYSCTL(sctp_initial_cwnd), SCTPCTL_INITIAL_CWND_MIN, SCTPCTL_INITIAL_CWND_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_base), SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX); RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable), SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX); @@ -829,9 +834,11 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_sacks, CTLTYPE_INT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_strict_sacks), 0, sysctl_sctp_check, "IU", SCTPCTL_STRICT_SACKS_DESC); +#if !defined(SCTP_WITH_NO_CSUM) SYSCTL_PROC(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLTYPE_INT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_no_csum_on_loopback), 0, sysctl_sctp_check, "IU", SCTPCTL_LOOPBACK_NOCSUM_DESC); +#endif SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_init, CTLTYPE_INT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_strict_init), 0, sysctl_sctp_check, "IU", @@ -1063,6 +1070,14 @@ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, vtag_time_wait, CTLTYPE_INT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_vtag_time_wait), 0, sysctl_sctp_check, "IU", SCTPCTL_TIME_WAIT_DESC); +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, buffer_splitting, CTLTYPE_INT | CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_buffer_splitting), 0, sysctl_sctp_check, "IU", + SCTPCTL_BUFFER_SPLITTING_DESC); + +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, initial_cwnd, CTLTYPE_INT | CTLFLAG_RW, + &SCTP_BASE_SYSCTL(sctp_initial_cwnd), 0, sysctl_sctp_check, "IU", + SCTPCTL_INITIAL_CWND_DESC); + #ifdef SCTP_DEBUG SYSCTL_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_INT | CTLFLAG_RW, &SCTP_BASE_SYSCTL(sctp_debug_on), 0, sysctl_sctp_check, "IU", diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h index 477ee36f759..9dbc9ed23c8 100644 --- a/sys/netinet/sctp_sysctl.h +++ b/sys/netinet/sctp_sysctl.h @@ -45,7 +45,9 @@ struct sctp_sysctl { uint32_t sctp_ecn_enable; uint32_t sctp_ecn_nonce; uint32_t sctp_strict_sacks; +#if !defined(SCTP_WITH_NO_CSUM) uint32_t sctp_no_csum_on_loopback; +#endif uint32_t sctp_strict_init; uint32_t sctp_peer_chunk_oh; uint32_t sctp_max_burst_default; @@ -105,6 +107,8 @@ struct sctp_sysctl { uint32_t sctp_udp_tunneling_port; uint32_t sctp_enable_sack_immediately; uint32_t sctp_vtag_time_wait; + uint32_t sctp_buffer_splitting; + uint32_t sctp_initial_cwnd; #if defined(SCTP_DEBUG) uint32_t sctp_debug_on; #endif @@ -476,19 +480,29 @@ struct sctp_sysctl { #define SCTPCTL_SACK_IMMEDIATELY_ENABLE_MAX 1 #define SCTPCTL_SACK_IMMEDIATELY_ENABLE_DEFAULT SCTPCTL_SACK_IMMEDIATELY_ENABLE_MIN -/* Enable sending of the SACK-IMMEDIATELY bit */ +/* Enable sending of the NAT-FRIENDLY message */ #define SCTPCTL_NAT_FRIENDLY_INITS_DESC "Enable sending of the nat-friendly SCTP option on INITs." #define SCTPCTL_NAT_FRIENDLY_INITS_MIN 0 #define SCTPCTL_NAT_FRIENDLY_INITS_MAX 1 #define SCTPCTL_NAT_FRIENDLY_INITS_DEFAULT SCTPCTL_NAT_FRIENDLY_INITS_MIN - -/* Vtag tiem wait bits */ -#define SCTPCTL_TIME_WAIT_DESC "Vtag time wait time 0 disables." +/* Vtag time wait in seconds */ +#define SCTPCTL_TIME_WAIT_DESC "Vtag time wait time in seconds, 0 disables it." #define SCTPCTL_TIME_WAIT_MIN 0 #define SCTPCTL_TIME_WAIT_MAX 0xffffffff #define SCTPCTL_TIME_WAIT_DEFAULT SCTP_TIME_WAIT +/* Enable Send/Receive buffer splitting */ +#define SCTPCTL_BUFFER_SPLITTING_DESC "Enable send/receive buffer splitting." +#define SCTPCTL_BUFFER_SPLITTING_MIN 0 +#define SCTPCTL_BUFFER_SPLITTING_MAX 0x3 +#define SCTPCTL_BUFFER_SPLITTING_DEFAULT SCTPCTL_BUFFER_SPLITTING_MIN + +/* Initial congestion window in MTU */ +#define SCTPCTL_INITIAL_CWND_DESC "Initial congestion window in MTUs" +#define SCTPCTL_INITIAL_CWND_MIN 1 +#define SCTPCTL_INITIAL_CWND_MAX 0xffffffff +#define SCTPCTL_INITIAL_CWND_DEFAULT 3 #if defined(SCTP_DEBUG) /* debug: Configure debug output */ diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index 292127275dd..949dd2fff85 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -215,7 +215,8 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * not in PF state. */ /* Stop any running T3 timers here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0)) { net->dest_state &= ~SCTP_ADDR_PF; SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", net); @@ -419,7 +420,7 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, return (net); } min_errors_net->dest_state &= ~SCTP_ADDR_PF; - min_errors_net->cwnd = min_errors_net->mtu * SCTP_BASE_SYSCTL(sctp_cmt_pf); + min_errors_net->cwnd = min_errors_net->mtu * stcb->asoc.sctp_cmt_pf; if (SCTP_OS_TIMER_PENDING(&min_errors_net->rxt_timer.timer)) { sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, min_errors_net, @@ -481,6 +482,9 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, if (mnet == NULL) { mnet = TAILQ_FIRST(&stcb->asoc.nets); + if (mnet == NULL) { + return (NULL); + } } do { alt = TAILQ_NEXT(mnet, sctp_next); @@ -490,6 +494,9 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, break; } alt = TAILQ_FIRST(&stcb->asoc.nets); + if (alt == NULL) { + return (NULL); + } } if (alt->ro.ro_rt == NULL) { if (alt->ro._s_addr) { @@ -516,6 +523,9 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, once = 0; mnet = net; do { + if (mnet == NULL) { + return (TAILQ_FIRST(&stcb->asoc.nets)); + } alt = TAILQ_NEXT(mnet, sctp_next); if (alt == NULL) { once++; @@ -762,9 +772,7 @@ start_again: } if (stcb->asoc.peer_supports_prsctp && PR_SCTP_TTL_ENABLED(chk->flags)) { /* Is it expired? */ - if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) || - ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) && - (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) { + if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) { /* Yes so drop it */ if (chk->data) { (void)sctp_release_pr_sctp_chunk(stcb, @@ -843,7 +851,7 @@ start_again: /* * CMT: Do not allow FRs on retransmitted TSNs. */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 1) { + if (stcb->asoc.sctp_cmt_on_off == 1) { chk->no_fr_allowed = 1; } #ifdef THIS_SHOULD_NOT_BE_DONE @@ -959,46 +967,6 @@ start_again: return (0); } -static void -sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb, - struct sctp_nets *net, - struct sctp_nets *alt) -{ - struct sctp_association *asoc; - struct sctp_stream_out *outs; - struct sctp_tmit_chunk *chk; - struct sctp_stream_queue_pending *sp; - - if (net == alt) - /* nothing to do */ - return; - - asoc = &stcb->asoc; - - /* - * now through all the streams checking for chunks sent to our bad - * network. - */ - TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) { - /* now clean up any chunks here */ - TAILQ_FOREACH(sp, &outs->outqueue, next) { - if (sp->net == net) { - sctp_free_remote_addr(sp->net); - sp->net = alt; - atomic_add_int(&alt->ref_count, 1); - } - } - } - /* Now check the pending queue */ - TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->whoTo == net) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = alt; - atomic_add_int(&alt->ref_count, 1); - } - } - -} int sctp_t3rxt_timer(struct sctp_inpcb *inp, @@ -1038,7 +1006,8 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, * addition, find an alternate destination with PF-based * find_alt_net(). */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0)) { if ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF) { net->dest_state |= SCTP_ADDR_PF; net->last_active = sctp_get_tick_count(); @@ -1046,7 +1015,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, net); } alt = sctp_find_alternate_net(stcb, net, 2); - } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { + } else if (stcb->asoc.sctp_cmt_on_off == 1) { /* * CMT: Using RTX_SSTHRESH policy for CMT. If CMT is being * used, then pick dest with largest ssthresh for any @@ -1130,7 +1099,7 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, } if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) { /* Move all pending over too */ - sctp_move_all_chunks_to_alt(stcb, net, alt); + sctp_move_chunks_from_net(stcb, net); /* * Get the address that failed, to force a new src address @@ -1162,7 +1131,9 @@ sctp_t3rxt_timer(struct sctp_inpcb *inp, net->dest_state |= SCTP_ADDR_WAS_PRIMARY; } } - } else if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf) && (net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) { + } else if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0) && + ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { /* * JRS 5/14/07 - If the destination hasn't failed completely * but is in PF state, a PF-heartbeat needs to be sent @@ -1243,7 +1214,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp, alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) { - sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt); + sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination); stcb->asoc.primary_destination = alt; } } @@ -1383,7 +1354,7 @@ sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * If the address went un-reachable, we need to move to * alternates for ALL chk's in queue */ - sctp_move_all_chunks_to_alt(stcb, net, alt); + sctp_move_chunks_from_net(stcb, net); } /* mark the retran info */ if (strrst->sent != SCTP_DATAGRAM_RESEND) @@ -1474,8 +1445,7 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, * If the address went un-reachable, we need to move * to the alternate for ALL chunks in queue */ - sctp_move_all_chunks_to_alt(stcb, net, alt); - net = alt; + sctp_move_chunks_from_net(stcb, net); } /* mark the retran info */ if (asconf->sent != SCTP_DATAGRAM_RESEND) diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index e3fbc3e6d50..1cd54654ca6 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -982,6 +982,23 @@ union sctp_sockstore { struct sockaddr sa; }; + +/***********************************/ +/* And something for us old timers */ +/***********************************/ + +#ifndef ntohll +#include +#define ntohll(x) be64toh(x) +#endif + +#ifndef htonll +#include +#define htonll(x) htobe64(x) +#endif +/***********************************/ + + struct xsctp_inpcb { uint32_t last; uint32_t flags; @@ -1079,7 +1096,6 @@ sctp_lower_sosend(struct socket *so, struct mbuf *i_pak, struct mbuf *control, int flags, - int use_rcvinfo, struct sctp_sndrcvinfo *srcv ,struct thread *p ); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 46cfa3dcf8c..627d1eecdb4 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -111,10 +111,6 @@ sctp_pathmtu_adjustment(struct sctp_inpcb *inp, /* Adjust that too */ stcb->asoc.smallest_mtu = nxtsz; /* now off to subtract IP_DF flag if needed */ -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("sctp_pathmtu_adjust called inp:%p stcb:%p net:%p nxtsz:%d\n", - inp, stcb, net, nxtsz); -#endif overhead = IP_HDR_SIZE; if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); @@ -215,10 +211,6 @@ sctp_notify_mbuf(struct sctp_inpcb *inp, } /* now what about the ep? */ if (stcb->asoc.smallest_mtu > nxtsz) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("notify_mbuf (ICMP) calls sctp_pathmtu_adjust mtu:%d\n", - nxtsz); -#endif sctp_pathmtu_adjustment(inp, stcb, net, nxtsz); } if (tmr_stopped) @@ -300,7 +292,8 @@ sctp_notify(struct sctp_inpcb *inp, * PF state. */ /* Stop any running T3 timers here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0)) { net->dest_state &= ~SCTP_ADDR_PF; SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", net); @@ -1736,42 +1729,14 @@ flags_out: struct sctp_assoc_value *av; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - av->assoc_value = stcb->asoc.sctp_cmt_on_off; - SCTP_TCB_UNLOCK(stcb); - - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + if (stcb) { + av->assoc_value = stcb->asoc.sctp_cmt_on_off; + SCTP_TCB_UNLOCK(stcb); } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - } - *optsize = sizeof(*av); - } - break; - /* EY - set socket option for nr_sacks */ - case SCTP_NR_SACK_ON_OFF: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - av->assoc_value = stcb->asoc.sctp_nr_sack_on_off; - SCTP_TCB_UNLOCK(stcb); - - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; + SCTP_INP_RLOCK(inp); + av->assoc_value = inp->sctp_cmt_on_off; + SCTP_INP_RUNLOCK(inp); } *optsize = sizeof(*av); } @@ -2846,44 +2811,28 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, } break; case SCTP_CMT_ON_OFF: - { + if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { struct sctp_assoc_value *av; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.sctp_cmt_on_off = (uint8_t) av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } + SCTP_FIND_STCB(inp, stcb, av->assoc_id); + if (stcb) { + if (av->assoc_value != 0) + stcb->asoc.sctp_cmt_on_off = 1; + else + stcb->asoc.sctp_cmt_on_off = 0; + SCTP_TCB_UNLOCK(stcb); } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; - } - } - break; - /* EY nr_sack_on_off socket option */ - case SCTP_NR_SACK_ON_OFF: - { - struct sctp_assoc_value *av; - - SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); - if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)) { - SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (stcb) { - stcb->asoc.sctp_nr_sack_on_off = (uint8_t) av->assoc_value; - SCTP_TCB_UNLOCK(stcb); - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); - error = ENOTCONN; - } - } else { - SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); - error = ENOPROTOOPT; + SCTP_INP_WLOCK(inp); + if (av->assoc_value != 0) + inp->sctp_cmt_on_off = 1; + else + inp->sctp_cmt_on_off = 0; + SCTP_INP_WUNLOCK(inp); } + } else { + SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); + error = ENOPROTOOPT; } break; /* JRS - Set socket option for pluggable congestion control */ @@ -3849,10 +3798,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { net->mtu = paddrp->spp_pathmtu + ovh; if (net->mtu < stcb->asoc.smallest_mtu) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", - net->mtu); -#endif sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); } } @@ -3897,10 +3842,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { net->mtu = paddrp->spp_pathmtu + ovh; if (net->mtu < stcb->asoc.smallest_mtu) { -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("SCTP_PMTU_DISABLE calls sctp_pathmtu_adjustment:%d\n", - net->mtu); -#endif sctp_pathmtu_adjustment(inp, stcb, net, net->mtu); } } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index e390fb1cde2..de9401f0dcc 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -340,7 +340,7 @@ sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; } sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); - if (inp->sctp_socket) { + if (inp && (inp->sctp_socket)) { sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); @@ -893,10 +893,8 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->max_burst = m->sctp_ep.max_burst; asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); asoc->cookie_life = m->sctp_ep.def_cookie_life; - asoc->sctp_cmt_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_on_off); - /* EY Init nr_sack variable */ + asoc->sctp_cmt_on_off = m->sctp_cmt_on_off; asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off); - /* JRS 5/21/07 - Init CMT PF variables */ asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf); asoc->sctp_frag_point = m->sctp_frag_point; #ifdef INET @@ -1006,10 +1004,6 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket); asoc->smallest_mtu = m->sctp_frag_point; -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("smallest_mtu init'd with asoc to :%d\n", - asoc->smallest_mtu); -#endif asoc->minrto = m->sctp_ep.sctp_minrto; asoc->maxrto = m->sctp_ep.sctp_maxrto; @@ -2490,10 +2484,6 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp, struct sctp_tmit_chunk *chk; unsigned int eff_mtu, ovh; -#ifdef SCTP_PRINT_FOR_B_AND_M - SCTP_PRINTF("sctp_mtu_size_reset(%p, asoc:%p mtu:%d\n", - inp, asoc, mtu); -#endif asoc->smallest_mtu = mtu; if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { ovh = SCTP_MIN_OVERHEAD; @@ -2502,7 +2492,6 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp, } eff_mtu = mtu - ovh; TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { - if (chk->send_size > eff_mtu) { chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; } @@ -3765,9 +3754,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked sp->data = NULL; } } - if (sp->net) + if (sp->net) { sctp_free_remote_addr(sp->net); - sp->net = NULL; + sp->net = NULL; + } /* Free the chunk */ sctp_free_a_strmoq(stcb, sp); /* sa_ignore FREED_MEMORY */ @@ -4820,7 +4810,10 @@ next_on_sent: chk->rec.data.payloadtype = sp->ppid; chk->rec.data.context = sp->context; chk->flags = sp->act_flags; - chk->whoTo = sp->net; + if (sp->net) + chk->whoTo = sp->net; + else + chk->whoTo = stcb->asoc.primary_destination; atomic_add_int(&chk->whoTo->ref_count, 1); chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); stcb->asoc.pr_sctp_cnt++; @@ -5134,7 +5127,7 @@ sctp_sorecvmsg(struct socket *so, int my_len = 0; int cp_len = 0, error = 0; struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; - struct mbuf *m = NULL, *embuf = NULL; + struct mbuf *m = NULL; struct sctp_tcb *stcb = NULL; int wakeup_read_socket = 0; int freecnt_applied = 0; @@ -5706,7 +5699,9 @@ get_more_data: if ((SCTP_BUF_NEXT(m) == NULL) && (control->end_added)) { out_flags |= MSG_EOR; - if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) + if ((control->do_not_ref_stcb == 0) && + (control->stcb != NULL) && + ((control->spec_flags & M_NOTIFICATION) == 0)) control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; } if (control->spec_flags & M_NOTIFICATION) { @@ -5728,7 +5723,6 @@ get_more_data: sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); } - embuf = m; copied_so_far += cp_len; freed_so_far += cp_len; freed_so_far += MSIZE; @@ -5780,7 +5774,6 @@ get_more_data: atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); } copied_so_far += cp_len; - embuf = m; freed_so_far += cp_len; freed_so_far += MSIZE; if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { diff --git a/sys/netinet/siftr.c b/sys/netinet/siftr.c index 34f363636cc..176d0d0a30f 100644 --- a/sys/netinet/siftr.c +++ b/sys/netinet/siftr.c @@ -55,7 +55,7 @@ * SIFTR should be directed to him via email: lastewart@swin.edu.au * * Initial release date: June 2007 - * Most recent update: June 2010 + * Most recent update: September 2010 ******************************************************/ #include @@ -105,7 +105,7 @@ __FBSDID("$FreeBSD$"); */ #define V_MAJOR 1 #define V_BACKBREAK 2 -#define V_BACKCOMPAT 3 +#define V_BACKCOMPAT 4 #define MODVERSION __CONCAT(V_MAJOR, __CONCAT(V_BACKBREAK, V_BACKCOMPAT)) #define MODVERSION_STR __XSTRING(V_MAJOR) "." __XSTRING(V_BACKBREAK) "." \ __XSTRING(V_BACKCOMPAT) @@ -193,7 +193,7 @@ struct pkt_node { u_long snd_wnd; /* Receive Window (bytes). */ u_long rcv_wnd; - /* Bandwidth Controlled Window (bytes). */ + /* Unused (was: Bandwidth Controlled Window (bytes)). */ u_long snd_bwnd; /* Slow Start Threshold (bytes). */ u_long snd_ssthresh; @@ -226,6 +226,8 @@ struct pkt_node { u_int rcv_buf_cc; /* Number of bytes inflight that we are waiting on ACKs for. */ u_int sent_inflight_bytes; + /* Number of segments currently in the reassembly queue. */ + int t_segqlen; /* Link to next pkt_node in the list. */ STAILQ_ENTRY(pkt_node) nodes; }; @@ -442,7 +444,7 @@ siftr_process_pkt(struct pkt_node * pkt_node) MAX_LOG_MSG_LEN, "%c,0x%08x,%zd.%06ld,%x:%x:%x:%x:%x:%x:%x:%x,%u,%x:%x:%x:" "%x:%x:%x:%x:%x,%u,%ld,%ld,%ld,%ld,%ld,%u,%u,%u,%u,%u,%u," - "%u,%d,%u,%u,%u,%u,%u\n", + "%u,%d,%u,%u,%u,%u,%u,%u\n", direction[pkt_node->direction], pkt_node->hash, pkt_node->tval.tv_sec, @@ -482,7 +484,8 @@ siftr_process_pkt(struct pkt_node * pkt_node) pkt_node->snd_buf_cc, pkt_node->rcv_buf_hiwater, pkt_node->rcv_buf_cc, - pkt_node->sent_inflight_bytes); + pkt_node->sent_inflight_bytes, + pkt_node->t_segqlen); } else { /* IPv4 packet */ pkt_node->ip_laddr[0] = FIRST_OCTET(pkt_node->ip_laddr[3]); pkt_node->ip_laddr[1] = SECOND_OCTET(pkt_node->ip_laddr[3]); @@ -498,7 +501,7 @@ siftr_process_pkt(struct pkt_node * pkt_node) log_buf->ae_bytesused = snprintf(log_buf->ae_data, MAX_LOG_MSG_LEN, "%c,0x%08x,%jd.%06ld,%u.%u.%u.%u,%u,%u.%u.%u.%u,%u,%ld,%ld," - "%ld,%ld,%ld,%u,%u,%u,%u,%u,%u,%u,%d,%u,%u,%u,%u,%u\n", + "%ld,%ld,%ld,%u,%u,%u,%u,%u,%u,%u,%d,%u,%u,%u,%u,%u,%u\n", direction[pkt_node->direction], pkt_node->hash, (intmax_t)pkt_node->tval.tv_sec, @@ -530,7 +533,8 @@ siftr_process_pkt(struct pkt_node * pkt_node) pkt_node->snd_buf_cc, pkt_node->rcv_buf_hiwater, pkt_node->rcv_buf_cc, - pkt_node->sent_inflight_bytes); + pkt_node->sent_inflight_bytes, + pkt_node->t_segqlen); #ifdef SIFTR_IPV6 } #endif @@ -775,7 +779,7 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp, pn->snd_cwnd = tp->snd_cwnd; pn->snd_wnd = tp->snd_wnd; pn->rcv_wnd = tp->rcv_wnd; - pn->snd_bwnd = tp->snd_bwnd; + pn->snd_bwnd = 0; /* Unused, kept for compat. */ pn->snd_ssthresh = tp->snd_ssthresh; pn->snd_scale = tp->snd_scale; pn->rcv_scale = tp->rcv_scale; @@ -790,6 +794,7 @@ siftr_siftdata(struct pkt_node *pn, struct inpcb *inp, struct tcpcb *tp, pn->rcv_buf_hiwater = inp->inp_socket->so_rcv.sb_hiwat; pn->rcv_buf_cc = inp->inp_socket->so_rcv.sb_cc; pn->sent_inflight_bytes = tp->snd_max - tp->snd_una; + pn->t_segqlen = tp->t_segqlen; /* We've finished accessing the tcb so release the lock. */ if (inp_locally_locked) diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h index 2929d0d2a92..62a89f7adda 100644 --- a/sys/netinet/tcp.h +++ b/sys/netinet/tcp.h @@ -103,29 +103,37 @@ struct tcphdr { /* - * Default maximum segment size for TCP. - * With an IP MTU of 576, this is 536, - * but 512 is probably more convenient. - * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + * The default maximum segment size (MSS) to be used for new TCP connections + * when path MTU discovery is not enabled. + * + * RFC879 derives the default MSS from the largest datagram size hosts are + * minimally required to handle directly or through IP reassembly minus the + * size of the IP and TCP header. With IPv6 the minimum MTU is specified + * in RFC2460. + * + * For IPv4 the MSS is 576 - sizeof(struct tcpiphdr) + * For IPv6 the MSS is IPV6_MMTU - sizeof(struct ip6_hdr) - sizeof(struct tcphdr) + * + * We use explicit numerical definition here to avoid header pollution. */ -#define TCP_MSS 512 -/* - * TCP_MINMSS is defined to be 216 which is fine for the smallest - * link MTU (256 bytes, AX.25 packet radio) in the Internet. - * However it is very unlikely to come across such low MTU interfaces - * these days (anno dato 2003). - * See tcp_subr.c tcp_minmss SYSCTL declaration for more comments. - * Setting this to "0" disables the minmss check. - */ -#define TCP_MINMSS 216 +#define TCP_MSS 536 +#define TCP6_MSS 1220 /* - * Default maximum segment size for TCP6. - * With an IP6 MSS of 1280, this is 1220, - * but 1024 is probably more convenient. (xxx kazu in doubt) - * This should be defined as MIN(1024, IP6_MSS - sizeof (struct tcpip6hdr)) + * Limit the lowest MSS we accept for path MTU discovery and the TCP SYN MSS + * option. Allowing low values of MSS can consume significant resources and + * be used to mount a resource exhaustion attack. + * Connections requesting lower MSS values will be rounded up to this value + * and the IP_DF flag will be cleared to allow fragmentation along the path. + * + * See tcp_subr.c tcp_minmss SYSCTL declaration for more comments. Setting + * it to "0" disables the minmss check. + * + * The default value is fine for TCP across the Internet's smallest official + * link MTU (256 bytes for AX.25 packet radio). However, a connection is very + * unlikely to come across such low MTU interfaces these days (anno domini 2003). */ -#define TCP6_MSS 1024 +#define TCP_MINMSS 216 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ #define TTCP_CLIENT_SND_WND 4096 /* dflt send window for T/TCP client */ @@ -213,7 +221,7 @@ struct tcp_info { /* FreeBSD extensions to tcp_info. */ u_int32_t tcpi_snd_wnd; /* Advertised send window. */ - u_int32_t tcpi_snd_bwnd; /* Bandwidth send window. */ + u_int32_t tcpi_snd_bwnd; /* No longer used. */ u_int32_t tcpi_snd_nxt; /* Next egress seqno */ u_int32_t tcpi_rcv_nxt; /* Next ingress seqno */ u_int32_t tcpi_toe_tid; /* HWTID for TOE endpoints */ diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index cbba9cd4ed0..22a2ea4a89c 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -571,7 +571,7 @@ findpcb: */ if ((tcp_log_in_vain == 1 && (thflags & TH_SYN)) || tcp_log_in_vain == 2) { - if ((s = tcp_log_addrs(NULL, th, (void *)ip, ip6))) + if ((s = tcp_log_vain(NULL, th, (void *)ip, ip6))) log(LOG_INFO, "%s; %s: Connection attempt " "to closed port\n", s, __func__); } @@ -1321,7 +1321,6 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tcp_xmit_timer(tp, ticks - tp->t_rtttime); } - tcp_xmit_bandwidth_limit(tp, th->th_ack); acked = th->th_ack - tp->snd_una; TCPSTAT_INC(tcps_rcvackpack); TCPSTAT_ADD(tcps_rcvackbyte, acked); @@ -1441,7 +1440,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, if (V_tcp_do_autorcvbuf && to.to_tsecr && (so->so_rcv.sb_flags & SB_AUTOSIZE)) { - if (to.to_tsecr > tp->rfbuf_ts && + if (TSTMP_GT(to.to_tsecr, tp->rfbuf_ts) && to.to_tsecr - tp->rfbuf_ts < hz) { if (tp->rfbuf_cnt > (so->so_rcv.sb_hiwat / 8 * 7) && @@ -2278,7 +2277,6 @@ process_ACK: tp->t_rttlow = ticks - tp->t_rtttime; tcp_xmit_timer(tp, ticks - tp->t_rtttime); } - tcp_xmit_bandwidth_limit(tp, th->th_ack); /* * If all outstanding data is acked, stop retransmit @@ -3328,8 +3326,6 @@ tcp_mss(struct tcpcb *tp, int offer) tp->snd_ssthresh = max(2 * mss, metrics.rmx_ssthresh); TCPSTAT_INC(tcps_usedssthresh); } - if (metrics.rmx_bandwidth) - tp->snd_bandwidth = metrics.rmx_bandwidth; /* * Set the slow-start flight size depending on whether this diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index be8ea534ee0..b5bc3d98552 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -140,7 +140,7 @@ tcp_output(struct tcpcb *tp) { struct socket *so = tp->t_inpcb->inp_socket; long len, recwin, sendwin; - int off, flags, error; + int off, flags, error, rw; struct mbuf *m; struct ip *ip = NULL; struct ipovly *ipov = NULL; @@ -176,23 +176,34 @@ tcp_output(struct tcpcb *tp) idle = (tp->t_flags & TF_LASTIDLE) || (tp->snd_max == tp->snd_una); if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) { /* - * We have been idle for "a while" and no acks are - * expected to clock out any data we send -- - * slow start to get ack "clock" running again. + * If we've been idle for more than one retransmit + * timeout the old congestion window is no longer + * current and we have to reduce it to the restart + * window before we can transmit again. * - * Set the slow-start flight size depending on whether - * this is a local network or not. + * The restart window is the initial window or the last + * CWND, whichever is smaller. + * + * This is done to prevent us from flooding the path with + * a full CWND at wirespeed, overloading router and switch + * buffers along the way. + * + * See RFC5681 Section 4.1. "Restarting Idle Connections". */ - int ss = V_ss_fltsz; + if (V_tcp_do_rfc3390) + rw = min(4 * tp->t_maxseg, + max(2 * tp->t_maxseg, 4380)); #ifdef INET6 - if (isipv6) { - if (in6_localaddr(&tp->t_inpcb->in6p_faddr)) - ss = V_ss_fltsz_local; - } else -#endif /* INET6 */ - if (in_localaddr(tp->t_inpcb->inp_faddr)) - ss = V_ss_fltsz_local; - tp->snd_cwnd = tp->t_maxseg * ss; + else if ((isipv6 ? in6_localaddr(&tp->t_inpcb->in6p_faddr) : + in_localaddr(tp->t_inpcb->inp_faddr))) +#else + else if (in_localaddr(tp->t_inpcb->inp_faddr)) +#endif + rw = V_ss_fltsz_local * tp->t_maxseg; + else + rw = V_ss_fltsz * tp->t_maxseg; + + tp->snd_cwnd = min(rw, tp->snd_cwnd); } tp->t_flags &= ~TF_LASTIDLE; if (idle) { @@ -214,7 +225,6 @@ again: tso = 0; off = tp->snd_nxt - tp->snd_una; sendwin = min(tp->snd_wnd, tp->snd_cwnd); - sendwin = min(sendwin, tp->snd_bwnd); flags = tcp_outflags[tp->t_state]; /* @@ -455,9 +465,8 @@ after_sack_rexmit: } /* - * Truncate to the maximum segment length or enable TCP Segmentation - * Offloading (if supported by hardware) and ensure that FIN is removed - * if the length no longer contains the last data byte. + * Decide if we can use TCP Segmentation Offloading (if supported by + * hardware). * * TSO may only be used if we are in a pure bulk sending state. The * presence of TCP-MD5, SACK retransmits, SACK advertizements and @@ -465,10 +474,6 @@ after_sack_rexmit: * (except for the sequence number) for all generated packets. This * makes it impossible to transmit any options which vary per generated * segment or packet. - * - * The length of TSO bursts is limited to TCP_MAXWIN. That limit and - * removal of FIN (if not already catched here) are handled later after - * the exact length of the TCP options are known. */ #ifdef IPSEC /* @@ -477,22 +482,15 @@ after_sack_rexmit: */ ipsec_optlen = ipsec_hdrsiz_tcp(tp); #endif - if (len > tp->t_maxseg) { - if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && - ((tp->t_flags & TF_SIGNATURE) == 0) && - tp->rcv_numsacks == 0 && sack_rxmit == 0 && - tp->t_inpcb->inp_options == NULL && - tp->t_inpcb->in6p_options == NULL + if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg && + ((tp->t_flags & TF_SIGNATURE) == 0) && + tp->rcv_numsacks == 0 && sack_rxmit == 0 && #ifdef IPSEC - && ipsec_optlen == 0 + ipsec_optlen == 0 && #endif - ) { - tso = 1; - } else { - len = tp->t_maxseg; - sendalot = 1; - } - } + tp->t_inpcb->inp_options == NULL && + tp->t_inpcb->in6p_options == NULL) + tso = 1; if (sack_rxmit) { if (SEQ_LT(p->rxmit + len, tp->snd_una + so->so_snd.sb_cc)) @@ -722,28 +720,53 @@ send: * bump the packet length beyond the t_maxopd length. * Clear the FIN bit because we cut off the tail of * the segment. - * - * When doing TSO limit a burst to TCP_MAXWIN minus the - * IP, TCP and Options length to keep ip->ip_len from - * overflowing. Prevent the last segment from being - * fractional thus making them all equal sized and set - * the flag to continue sending. TSO is disabled when - * IP options or IPSEC are present. */ if (len + optlen + ipoptlen > tp->t_maxopd) { flags &= ~TH_FIN; + if (tso) { - if (len > TCP_MAXWIN - hdrlen - optlen) { - len = TCP_MAXWIN - hdrlen - optlen; - len = len - (len % (tp->t_maxopd - optlen)); + KASSERT(ipoptlen == 0, + ("%s: TSO can't do IP options", __func__)); + + /* + * Limit a burst to IP_MAXPACKET minus IP, + * TCP and options length to keep ip->ip_len + * from overflowing. + */ + if (len > IP_MAXPACKET - hdrlen) { + len = IP_MAXPACKET - hdrlen; sendalot = 1; - } else if (tp->t_flags & TF_NEEDFIN) + } + + /* + * Prevent the last segment from being + * fractional unless the send sockbuf can + * be emptied. + */ + if (sendalot && off + len < so->so_snd.sb_cc) { + len -= len % (tp->t_maxopd - optlen); sendalot = 1; + } + + /* + * Send the FIN in a separate segment + * after the bulk sending is done. + * We don't trust the TSO implementations + * to clear the FIN flag on all but the + * last segment. + */ + if (tp->t_flags & TF_NEEDFIN) + sendalot = 1; + } else { len = tp->t_maxopd - optlen - ipoptlen; sendalot = 1; } - } + } else + tso = 0; + + KASSERT(len + hdrlen + ipoptlen <= IP_MAXPACKET, + ("%s: len > IP_MAXPACKET", __func__)); /*#ifdef DIAGNOSTIC*/ #ifdef INET6 @@ -1058,6 +1081,9 @@ send: m->m_pkthdr.tso_segsz = tp->t_maxopd - optlen; } + KASSERT(len + hdrlen + ipoptlen == m_length(m, NULL), + ("%s: mbuf chain shorter than expected", __func__)); + /* * In transmit state, time the transmission and arrange for * the retransmit. In persist state, just set snd_max. diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index bfb53d3a742..9efacdcdbbc 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -74,32 +74,33 @@ __FBSDID("$FreeBSD$"); #include #endif /* TCPDEBUG */ +static int tcp_reass_sysctl_maxseg(SYSCTL_HANDLER_ARGS); +static int tcp_reass_sysctl_qsize(SYSCTL_HANDLER_ARGS); + SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0, "TCP Segment Reassembly Queue"); static VNET_DEFINE(int, tcp_reass_maxseg) = 0; #define V_tcp_reass_maxseg VNET(tcp_reass_maxseg) -SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN, - &VNET_NAME(tcp_reass_maxseg), 0, +SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RDTUN, + &VNET_NAME(tcp_reass_maxseg), 0, &tcp_reass_sysctl_maxseg, "I", "Global maximum number of TCP Segments in Reassembly Queue"); -VNET_DEFINE(int, tcp_reass_qsize) = 0; -SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD, - &VNET_NAME(tcp_reass_qsize), 0, +static VNET_DEFINE(int, tcp_reass_qsize) = 0; +#define V_tcp_reass_qsize VNET(tcp_reass_qsize) +SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD, + &VNET_NAME(tcp_reass_qsize), 0, &tcp_reass_sysctl_qsize, "I", "Global number of TCP Segments currently in Reassembly Queue"); -static VNET_DEFINE(int, tcp_reass_maxqlen) = 48; -#define V_tcp_reass_maxqlen VNET(tcp_reass_maxqlen) -SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, maxqlen, CTLFLAG_RW, - &VNET_NAME(tcp_reass_maxqlen), 0, - "Maximum number of TCP Segments per individual Reassembly Queue"); - static VNET_DEFINE(int, tcp_reass_overflows) = 0; #define V_tcp_reass_overflows VNET(tcp_reass_overflows) SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD, &VNET_NAME(tcp_reass_overflows), 0, "Global number of TCP Segment Reassembly Queue Overflows"); +static VNET_DEFINE(uma_zone_t, tcp_reass_zone); +#define V_tcp_reass_zone VNET(tcp_reass_zone) + /* Initialize TCP reassembly queue */ static void tcp_reass_zone_change(void *tag) @@ -109,8 +110,6 @@ tcp_reass_zone_change(void *tag) uma_zone_set_max(V_tcp_reass_zone, V_tcp_reass_maxseg); } -VNET_DEFINE(uma_zone_t, tcp_reass_zone); - void tcp_reass_init(void) { @@ -134,6 +133,39 @@ tcp_reass_destroy(void) } #endif +void +tcp_reass_flush(struct tcpcb *tp) +{ + struct tseg_qent *qe; + + INP_WLOCK_ASSERT(tp->t_inpcb); + + while ((qe = LIST_FIRST(&tp->t_segq)) != NULL) { + LIST_REMOVE(qe, tqe_q); + m_freem(qe->tqe_m); + uma_zfree(V_tcp_reass_zone, qe); + tp->t_segqlen--; + } + + KASSERT((tp->t_segqlen == 0), + ("TCP reass queue %p segment count is %d instead of 0 after flush.", + tp, tp->t_segqlen)); +} + +static int +tcp_reass_sysctl_maxseg(SYSCTL_HANDLER_ARGS) +{ + V_tcp_reass_maxseg = uma_zone_get_max(V_tcp_reass_zone); + return (sysctl_handle_int(oidp, arg1, arg2, req)); +} + +static int +tcp_reass_sysctl_qsize(SYSCTL_HANDLER_ARGS) +{ + V_tcp_reass_qsize = uma_zone_get_cur(V_tcp_reass_zone); + return (sysctl_handle_int(oidp, arg1, arg2, req)); +} + int tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) { @@ -159,15 +191,23 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) goto present; /* - * Limit the number of segments in the reassembly queue to prevent - * holding on to too many segments (and thus running out of mbufs). - * Make sure to let the missing segment through which caused this - * queue. Always keep one global queue entry spare to be able to - * process the missing segment. + * Limit the number of segments that can be queued to reduce the + * potential for mbuf exhaustion. For best performance, we want to be + * able to queue a full window's worth of segments. The size of the + * socket receive buffer determines our advertised window and grows + * automatically when socket buffer autotuning is enabled. Use it as the + * basis for our queue limit. + * Always let the missing segment through which caused this queue. + * NB: Access to the socket buffer is left intentionally unlocked as we + * can tolerate stale information here. + * + * XXXLAS: Using sbspace(so->so_rcv) instead of so->so_rcv.sb_hiwat + * should work but causes packets to be dropped when they shouldn't. + * Investigate why and re-evaluate the below limit after the behaviour + * is understood. */ if (th->th_seq != tp->rcv_nxt && - (V_tcp_reass_qsize + 1 >= V_tcp_reass_maxseg || - tp->t_segqlen >= V_tcp_reass_maxqlen)) { + tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) { V_tcp_reass_overflows++; TCPSTAT_INC(tcps_rcvmemdrop); m_freem(m); @@ -187,7 +227,6 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) return (0); } tp->t_segqlen++; - V_tcp_reass_qsize++; /* * Find a segment which begins after this one does. @@ -214,7 +253,6 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) m_freem(m); uma_zfree(V_tcp_reass_zone, te); tp->t_segqlen--; - V_tcp_reass_qsize--; /* * Try to present any queued data * at the left window edge to the user. @@ -251,7 +289,6 @@ tcp_reass(struct tcpcb *tp, struct tcphdr *th, int *tlenp, struct mbuf *m) m_freem(q->tqe_m); uma_zfree(V_tcp_reass_zone, q); tp->t_segqlen--; - V_tcp_reass_qsize--; q = nq; } @@ -288,7 +325,6 @@ present: sbappendstream_locked(&so->so_rcv, q->tqe_m); uma_zfree(V_tcp_reass_zone, q); tp->t_segqlen--; - V_tcp_reass_qsize--; q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index da478b3116b..dc4395dc613 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -160,14 +160,6 @@ SYSCTL_VNET_PROC(_net_inet_tcp, TCPCTL_V6MSSDFLT, v6mssdflt, "Default TCP Maximum Segment Size for IPv6"); #endif -static int -vnet_sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS) -{ - - VNET_SYSCTL_ARG(req, arg1); - return (sysctl_msec_to_ticks(oidp, arg1, arg2, req)); -} - /* * Minimum MSS we accept and use. This prevents DoS attacks where * we are forced to a ridiculous low MSS like 20 and send hundreds @@ -213,50 +205,6 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, isn_reseed_interval, CTLFLAG_RW, &VNET_NAME(tcp_isn_reseed_interval), 0, "Seconds between reseeding of ISN secret"); -/* - * TCP bandwidth limiting sysctls. Note that the default lower bound of - * 1024 exists only for debugging. A good production default would be - * something like 6100. - */ -SYSCTL_NODE(_net_inet_tcp, OID_AUTO, inflight, CTLFLAG_RW, 0, - "TCP inflight data limiting"); - -static VNET_DEFINE(int, tcp_inflight_enable) = 0; -#define V_tcp_inflight_enable VNET(tcp_inflight_enable) -SYSCTL_VNET_INT(_net_inet_tcp_inflight, OID_AUTO, enable, CTLFLAG_RW, - &VNET_NAME(tcp_inflight_enable), 0, - "Enable automatic TCP inflight data limiting"); - -static int tcp_inflight_debug = 0; -SYSCTL_INT(_net_inet_tcp_inflight, OID_AUTO, debug, CTLFLAG_RW, - &tcp_inflight_debug, 0, - "Debug TCP inflight calculations"); - -static VNET_DEFINE(int, tcp_inflight_rttthresh); -#define V_tcp_inflight_rttthresh VNET(tcp_inflight_rttthresh) -SYSCTL_VNET_PROC(_net_inet_tcp_inflight, OID_AUTO, rttthresh, - CTLTYPE_INT|CTLFLAG_RW, &VNET_NAME(tcp_inflight_rttthresh), 0, - vnet_sysctl_msec_to_ticks, "I", - "RTT threshold below which inflight will deactivate itself"); - -static VNET_DEFINE(int, tcp_inflight_min) = 6144; -#define V_tcp_inflight_min VNET(tcp_inflight_min) -SYSCTL_VNET_INT(_net_inet_tcp_inflight, OID_AUTO, min, CTLFLAG_RW, - &VNET_NAME(tcp_inflight_min), 0, - "Lower-bound for TCP inflight window"); - -static VNET_DEFINE(int, tcp_inflight_max) = TCP_MAXWIN << TCP_MAX_WINSHIFT; -#define V_tcp_inflight_max VNET(tcp_inflight_max) -SYSCTL_VNET_INT(_net_inet_tcp_inflight, OID_AUTO, max, CTLFLAG_RW, - &VNET_NAME(tcp_inflight_max), 0, - "Upper-bound for TCP inflight window"); - -static VNET_DEFINE(int, tcp_inflight_stab) = 20; -#define V_tcp_inflight_stab VNET(tcp_inflight_stab) -SYSCTL_VNET_INT(_net_inet_tcp_inflight, OID_AUTO, stab, CTLFLAG_RW, - &VNET_NAME(tcp_inflight_stab), 0, - "Inflight Algorithm Stabilization 20 = 2 packets"); - #ifdef TCP_SORECEIVE_STREAM static int tcp_soreceive_stream = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, soreceive_stream, CTLFLAG_RDTUN, @@ -268,6 +216,8 @@ VNET_DEFINE(uma_zone_t, sack_hole_zone); static struct inpcb *tcp_notify(struct inpcb *, int); static void tcp_isn_tick(void *); +static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, + void *ip4hdr, const void *ip6hdr); /* * Target size of TCP PCB hash tables. Must be a power of two. @@ -336,8 +286,6 @@ tcp_init(void) in_pcbinfo_init(&V_tcbinfo, "tcp", &V_tcb, hashsize, hashsize, "tcp_inpcb", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE); - V_tcp_inflight_rttthresh = TCPTV_INFLIGHT_RTTTHRESH; - /* * These have to be type stable for the benefit of the timers. */ @@ -726,10 +674,8 @@ tcp_newtcpcb(struct inpcb *inp) tp->t_rttmin = tcp_rexmit_min; tp->t_rxtcur = TCPTV_RTOBASE; tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->snd_bwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->t_rcvtime = ticks; - tp->t_bw_rtttime = ticks; /* * IPv4 TTL initialization is necessary for an IPv6 socket as well, * because the socket may be bound to an IPv6 wildcard address, @@ -768,7 +714,6 @@ tcp_drop(struct tcpcb *tp, int errno) void tcp_discardcb(struct tcpcb *tp) { - struct tseg_qent *q; struct inpcb *inp = tp->t_inpcb; struct socket *so = inp->inp_socket; #ifdef INET6 @@ -847,8 +792,6 @@ tcp_discardcb(struct tcpcb *tp) metrics.rmx_rtt = tp->t_srtt; metrics.rmx_rttvar = tp->t_rttvar; - /* XXX: This wraps if the pipe is more than 4 Gbit per second */ - metrics.rmx_bandwidth = tp->snd_bandwidth; metrics.rmx_cwnd = tp->snd_cwnd; metrics.rmx_sendpipe = 0; metrics.rmx_recvpipe = 0; @@ -857,13 +800,7 @@ tcp_discardcb(struct tcpcb *tp) } /* free the reassembly queue, if any */ - while ((q = LIST_FIRST(&tp->t_segq)) != NULL) { - LIST_REMOVE(q, tqe_q); - m_freem(q->tqe_m); - uma_zfree(V_tcp_reass_zone, q); - tp->t_segqlen--; - V_tcp_reass_qsize--; - } + tcp_reass_flush(tp); /* Disconnect offload device, if any. */ tcp_offload_detach(tp); @@ -921,7 +858,6 @@ tcp_drain(void) CURVNET_SET(vnet_iter); struct inpcb *inpb; struct tcpcb *tcpb; - struct tseg_qent *te; /* * Walk the tcpbs, if existing, and flush the reassembly queue, @@ -937,14 +873,7 @@ tcp_drain(void) continue; INP_WLOCK(inpb); if ((tcpb = intotcpcb(inpb)) != NULL) { - while ((te = LIST_FIRST(&tcpb->t_segq)) - != NULL) { - LIST_REMOVE(te, tqe_q); - m_freem(te->tqe_m); - uma_zfree(V_tcp_reass_zone, te); - tcpb->t_segqlen--; - V_tcp_reass_qsize--; - } + tcp_reass_flush(tcpb); tcp_clean_sackreport(tcpb); } INP_WUNLOCK(inpb); @@ -1020,10 +949,9 @@ tcp_pcblist(SYSCTL_HANDLER_ARGS) * resource-intensive to repeat twice on every request. */ if (req->oldptr == NULL) { - m = syncache_pcbcount(); - n = V_tcbinfo.ipi_count; - req->oldidx = 2 * (sizeof xig) - + ((m + n) + n/8) * sizeof(struct xtcpcb); + n = V_tcbinfo.ipi_count + syncache_pcbcount(); + n += imax(n / 8, 10); + req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xtcpcb); return (0); } @@ -1772,154 +1700,6 @@ ipsec_hdrsiz_tcp(struct tcpcb *tp) } #endif /* IPSEC */ -/* - * TCP BANDWIDTH DELAY PRODUCT WINDOW LIMITING - * - * This code attempts to calculate the bandwidth-delay product as a - * means of determining the optimal window size to maximize bandwidth, - * minimize RTT, and avoid the over-allocation of buffers on interfaces and - * routers. This code also does a fairly good job keeping RTTs in check - * across slow links like modems. We implement an algorithm which is very - * similar (but not meant to be) TCP/Vegas. The code operates on the - * transmitter side of a TCP connection and so only effects the transmit - * side of the connection. - * - * BACKGROUND: TCP makes no provision for the management of buffer space - * at the end points or at the intermediate routers and switches. A TCP - * stream, whether using NewReno or not, will eventually buffer as - * many packets as it is able and the only reason this typically works is - * due to the fairly small default buffers made available for a connection - * (typicaly 16K or 32K). As machines use larger windows and/or window - * scaling it is now fairly easy for even a single TCP connection to blow-out - * all available buffer space not only on the local interface, but on - * intermediate routers and switches as well. NewReno makes a misguided - * attempt to 'solve' this problem by waiting for an actual failure to occur, - * then backing off, then steadily increasing the window again until another - * failure occurs, ad-infinitum. This results in terrible oscillation that - * is only made worse as network loads increase and the idea of intentionally - * blowing out network buffers is, frankly, a terrible way to manage network - * resources. - * - * It is far better to limit the transmit window prior to the failure - * condition being achieved. There are two general ways to do this: First - * you can 'scan' through different transmit window sizes and locate the - * point where the RTT stops increasing, indicating that you have filled the - * pipe, then scan backwards until you note that RTT stops decreasing, then - * repeat ad-infinitum. This method works in principle but has severe - * implementation issues due to RTT variances, timer granularity, and - * instability in the algorithm which can lead to many false positives and - * create oscillations as well as interact badly with other TCP streams - * implementing the same algorithm. - * - * The second method is to limit the window to the bandwidth delay product - * of the link. This is the method we implement. RTT variances and our - * own manipulation of the congestion window, bwnd, can potentially - * destabilize the algorithm. For this reason we have to stabilize the - * elements used to calculate the window. We do this by using the minimum - * observed RTT, the long term average of the observed bandwidth, and - * by adding two segments worth of slop. It isn't perfect but it is able - * to react to changing conditions and gives us a very stable basis on - * which to extend the algorithm. - */ -void -tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq) -{ - u_long bw; - u_long bwnd; - int save_ticks; - - INP_WLOCK_ASSERT(tp->t_inpcb); - - /* - * If inflight_enable is disabled in the middle of a tcp connection, - * make sure snd_bwnd is effectively disabled. - */ - if (V_tcp_inflight_enable == 0 || - tp->t_rttlow < V_tcp_inflight_rttthresh) { - tp->snd_bwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; - tp->snd_bandwidth = 0; - return; - } - - /* - * Figure out the bandwidth. Due to the tick granularity this - * is a very rough number and it MUST be averaged over a fairly - * long period of time. XXX we need to take into account a link - * that is not using all available bandwidth, but for now our - * slop will ramp us up if this case occurs and the bandwidth later - * increases. - * - * Note: if ticks rollover 'bw' may wind up negative. We must - * effectively reset t_bw_rtttime for this case. - */ - save_ticks = ticks; - if ((u_int)(save_ticks - tp->t_bw_rtttime) < 1) - return; - - bw = (int64_t)(ack_seq - tp->t_bw_rtseq) * hz / - (save_ticks - tp->t_bw_rtttime); - tp->t_bw_rtttime = save_ticks; - tp->t_bw_rtseq = ack_seq; - if (tp->t_bw_rtttime == 0 || (int)bw < 0) - return; - bw = ((int64_t)tp->snd_bandwidth * 15 + bw) >> 4; - - tp->snd_bandwidth = bw; - - /* - * Calculate the semi-static bandwidth delay product, plus two maximal - * segments. The additional slop puts us squarely in the sweet - * spot and also handles the bandwidth run-up case and stabilization. - * Without the slop we could be locking ourselves into a lower - * bandwidth. - * - * Situations Handled: - * (1) Prevents over-queueing of packets on LANs, especially on - * high speed LANs, allowing larger TCP buffers to be - * specified, and also does a good job preventing - * over-queueing of packets over choke points like modems - * (at least for the transmit side). - * - * (2) Is able to handle changing network loads (bandwidth - * drops so bwnd drops, bandwidth increases so bwnd - * increases). - * - * (3) Theoretically should stabilize in the face of multiple - * connections implementing the same algorithm (this may need - * a little work). - * - * (4) Stability value (defaults to 20 = 2 maximal packets) can - * be adjusted with a sysctl but typically only needs to be - * on very slow connections. A value no smaller then 5 - * should be used, but only reduce this default if you have - * no other choice. - */ -#define USERTT ((tp->t_srtt + tp->t_rttbest) / 2) - bwnd = (int64_t)bw * USERTT / (hz << TCP_RTT_SHIFT) + V_tcp_inflight_stab * tp->t_maxseg / 10; -#undef USERTT - - if (tcp_inflight_debug > 0) { - static int ltime; - if ((u_int)(ticks - ltime) >= hz / tcp_inflight_debug) { - ltime = ticks; - printf("%p bw %ld rttbest %d srtt %d bwnd %ld\n", - tp, - bw, - tp->t_rttbest, - tp->t_srtt, - bwnd - ); - } - } - if ((long)bwnd < V_tcp_inflight_min) - bwnd = V_tcp_inflight_min; - if (bwnd > V_tcp_inflight_max) - bwnd = V_tcp_inflight_max; - if ((long)bwnd < tp->t_maxseg * 2) - bwnd = tp->t_maxseg * 2; - tp->snd_bwnd = bwnd; -} - #ifdef TCP_SIGNATURE /* * Callback function invoked by m_apply() to digest TCP segment data @@ -2232,10 +2012,34 @@ SYSCTL_PROC(_net_inet_tcp, TCPCTL_DROP, drop, * Due to header inclusion and ordering limitations the struct ip * and ip6_hdr pointers have to be passed as void pointers. */ +char * +tcp_log_vain(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, + const void *ip6hdr) +{ + + /* Is logging enabled? */ + if (tcp_log_in_vain == 0) + return (NULL); + + return (tcp_log_addr(inc, th, ip4hdr, ip6hdr)); +} + char * tcp_log_addrs(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, const void *ip6hdr) { + + /* Is logging enabled? */ + if (tcp_log_debug == 0) + return (NULL); + + return (tcp_log_addr(inc, th, ip4hdr, ip6hdr)); +} + +static char * +tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, + const void *ip6hdr) +{ char *s, *sp; size_t size; struct ip *ip; @@ -2258,10 +2062,6 @@ tcp_log_addrs(struct in_conninfo *inc, struct tcphdr *th, void *ip4hdr, 2 * INET_ADDRSTRLEN; #endif /* INET6 */ - /* Is logging enabled? */ - if (tcp_log_debug == 0 && tcp_log_in_vain == 0) - return (NULL); - s = malloc(size, M_TCPLOG, M_ZERO|M_NOWAIT); if (s == NULL) return (NULL); diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h index 1ab0b7b2938..4bfcdf65c15 100644 --- a/sys/netinet/tcp_timer.h +++ b/sys/netinet/tcp_timer.h @@ -86,9 +86,6 @@ #define TCPTV_KEEPINTVL ( 75*hz) /* default probe interval */ #define TCPTV_KEEPCNT 8 /* max probes before drop */ -#define TCPTV_INFLIGHT_RTTTHRESH (10*hz/1000) /* below which inflight - disengages, in msec */ - #define TCPTV_FINWAIT2_TIMEOUT (60*hz) /* FIN_WAIT_2 timeout if no receiver */ /* diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 2e61c3125c4..f35890bee19 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1105,7 +1105,6 @@ tcp_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) tp->t_state = TCPS_SYN_SENT; tcp_timer_activate(tp, TT_KEEP, tcp_keepinit); tp->iss = tcp_new_isn(tp); - tp->t_bw_rtseq = tp->iss; tcp_sendseqinit(tp); return 0; @@ -1168,7 +1167,6 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td) tp->t_state = TCPS_SYN_SENT; tcp_timer_activate(tp, TT_KEEP, tcp_keepinit); tp->iss = tcp_new_isn(tp); - tp->t_bw_rtseq = tp->iss; tcp_sendseqinit(tp); return 0; @@ -1214,7 +1212,7 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti) ti->tcpi_rcv_space = tp->rcv_wnd; ti->tcpi_rcv_nxt = tp->rcv_nxt; ti->tcpi_snd_wnd = tp->snd_wnd; - ti->tcpi_snd_bwnd = tp->snd_bwnd; + ti->tcpi_snd_bwnd = 0; /* Unused, kept for compat. */ ti->tcpi_snd_nxt = tp->snd_nxt; ti->tcpi_snd_mss = tp->t_maxseg; ti->tcpi_rcv_mss = tp->t_maxseg; @@ -1795,26 +1793,24 @@ db_print_tcpcb(struct tcpcb *tp, const char *name, int indent) tp->rcv_adv, tp->rcv_wnd, tp->rcv_up); db_print_indent(indent); - db_printf("snd_wnd: %lu snd_cwnd: %lu snd_bwnd: %lu\n", - tp->snd_wnd, tp->snd_cwnd, tp->snd_bwnd); + db_printf("snd_wnd: %lu snd_cwnd: %lu\n", + tp->snd_wnd, tp->snd_cwnd); db_print_indent(indent); - db_printf("snd_ssthresh: %lu snd_bandwidth: %lu snd_recover: " - "0x%08x\n", tp->snd_ssthresh, tp->snd_bandwidth, - tp->snd_recover); + db_printf("snd_ssthresh: %lu snd_recover: " + "0x%08x\n", tp->snd_ssthresh, tp->snd_recover); db_print_indent(indent); db_printf("t_maxopd: %u t_rcvtime: %u t_startime: %u\n", tp->t_maxopd, tp->t_rcvtime, tp->t_starttime); db_print_indent(indent); - db_printf("t_rttime: %u t_rtsq: 0x%08x t_bw_rtttime: %u\n", - tp->t_rtttime, tp->t_rtseq, tp->t_bw_rtttime); + db_printf("t_rttime: %u t_rtsq: 0x%08x\n", + tp->t_rtttime, tp->t_rtseq); db_print_indent(indent); - db_printf("t_bw_rtseq: 0x%08x t_rxtcur: %d t_maxseg: %u " - "t_srtt: %d\n", tp->t_bw_rtseq, tp->t_rxtcur, tp->t_maxseg, - tp->t_srtt); + db_printf("t_rxtcur: %d t_maxseg: %u t_srtt: %d\n", + tp->t_rxtcur, tp->t_maxseg, tp->t_srtt); db_print_indent(indent); db_printf("t_rttvar: %d t_rxtshift: %d t_rttmin: %u " diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 5811439dcd6..0b286812f1f 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -44,10 +44,6 @@ VNET_DECLARE(int, tcp_do_rfc1323); #define V_tcp_do_rfc1323 VNET(tcp_do_rfc1323) -VNET_DECLARE(int, tcp_reass_qsize); -VNET_DECLARE(struct uma_zone *, tcp_reass_zone); -#define V_tcp_reass_qsize VNET(tcp_reass_qsize) -#define V_tcp_reass_zone VNET(tcp_reass_zone) #endif /* _KERNEL */ /* TCP segment queue entry */ @@ -135,12 +131,12 @@ struct tcpcb { u_long snd_wnd; /* send window */ u_long snd_cwnd; /* congestion-controlled window */ - u_long snd_bwnd; /* bandwidth-controlled window */ + u_long snd_spare1; /* unused */ u_long snd_ssthresh; /* snd_cwnd size threshold for * for slow start exponential to * linear switch */ - u_long snd_bandwidth; /* calculated bandwidth or 0 */ + u_long snd_spare2; /* unused */ tcp_seq snd_recover; /* for use in NewReno Fast Recovery */ u_int t_maxopd; /* mss plus options */ @@ -150,8 +146,8 @@ struct tcpcb { u_int t_rtttime; /* RTT measurement start time */ tcp_seq t_rtseq; /* sequence number being timed */ - u_int t_bw_rtttime; /* used for bandwidth calculation */ - tcp_seq t_bw_rtseq; /* used for bandwidth calculation */ + u_int t_bw_spare1; /* unused */ + tcp_seq t_bw_spare2; /* unused */ int t_rxtcur; /* current retransmit value (ticks) */ u_int t_maxseg; /* maximum segment size */ @@ -565,6 +561,7 @@ extern int tcp_log_in_vain; VNET_DECLARE(int, tcp_mssdflt); /* XXX */ VNET_DECLARE(int, tcp_minmss); VNET_DECLARE(int, tcp_delack_enabled); +VNET_DECLARE(int, tcp_do_rfc3390); VNET_DECLARE(int, tcp_do_newreno); VNET_DECLARE(int, path_mtu_discovery); VNET_DECLARE(int, ss_fltsz); @@ -575,6 +572,7 @@ VNET_DECLARE(int, ss_fltsz_local); #define V_tcp_mssdflt VNET(tcp_mssdflt) #define V_tcp_minmss VNET(tcp_minmss) #define V_tcp_delack_enabled VNET(tcp_delack_enabled) +#define V_tcp_do_rfc3390 VNET(tcp_do_rfc3390) #define V_tcp_do_newreno VNET(tcp_do_newreno) #define V_path_mtu_discovery VNET(path_mtu_discovery) #define V_ss_fltsz VNET(ss_fltsz) @@ -611,8 +609,11 @@ void tcp_destroy(void); void tcp_fini(void *); char *tcp_log_addrs(struct in_conninfo *, struct tcphdr *, void *, const void *); +char *tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *, + const void *); int tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *); void tcp_reass_init(void); +void tcp_reass_flush(struct tcpcb *); #ifdef VIMAGE void tcp_reass_destroy(void); #endif @@ -650,7 +651,6 @@ void tcpip_fillheaders(struct inpcb *, void *, void *); void tcp_timer_activate(struct tcpcb *, int, u_int); int tcp_timer_active(struct tcpcb *, int); void tcp_trace(short, short, struct tcpcb *, void *, struct tcphdr *, int); -void tcp_xmit_bandwidth_limit(struct tcpcb *tp, tcp_seq ack_seq); /* * All tcp_hc_* functions are IPv4 and IPv6 (via in_conninfo) */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 45410387c17..adb11c4ea80 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -707,8 +707,8 @@ udp_pcblist(SYSCTL_HANDLER_ARGS) */ if (req->oldptr == 0) { n = V_udbinfo.ipi_count; - req->oldidx = 2 * (sizeof xig) - + (n + n/8) * sizeof(struct xinpcb); + n += imax(n / 8, 10); + req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xinpcb); return (0); } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 87df9c369c8..952b38acf85 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -105,6 +105,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef IPSEC #include @@ -414,6 +415,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) int icmp6len = m->m_pkthdr.len - *offp; int code, sum, noff; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; + int ip6len, error; ifp = m->m_pkthdr.rcvif; @@ -428,6 +430,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) */ ip6 = mtod(m, struct ip6_hdr *); + ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); if (icmp6len < sizeof(struct icmp6_hdr)) { ICMP6STAT_INC(icp6s_tooshort); goto freeit; @@ -766,11 +769,33 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) goto badlen; if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { /* give up local */ - nd6_rs_input(m, off, icmp6len); + + /* Send incoming SeND packet to user space. */ + if (send_sendso_input_hook != NULL) { + IP6_EXTHDR_CHECK(m, off, + icmp6len, IPPROTO_DONE); + error = send_sendso_input_hook(m, ifp, + SND_IN, ip6len); + /* -1 == no app on SEND socket */ + if (error == 0) + return (IPPROTO_DONE); + nd6_rs_input(m, off, icmp6len); + } else + nd6_rs_input(m, off, icmp6len); m = NULL; goto freeit; } - nd6_rs_input(n, off, icmp6len); + if (send_sendso_input_hook != NULL) { + IP6_EXTHDR_CHECK(n, off, + icmp6len, IPPROTO_DONE); + error = send_sendso_input_hook(n, ifp, + SND_IN, ip6len); + if (error == 0) + goto freeit; + /* -1 == no app on SEND socket */ + nd6_rs_input(n, off, icmp6len); + } else + nd6_rs_input(n, off, icmp6len); /* m stays. */ break; @@ -781,12 +806,27 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (icmp6len < sizeof(struct nd_router_advert)) goto badlen; if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { - /* give up local */ - nd6_ra_input(m, off, icmp6len); + + /* Send incoming SeND-protected/ND packet to user space. */ + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(m, ifp, + SND_IN, ip6len); + if (error == 0) + return (IPPROTO_DONE); + nd6_ra_input(m, off, icmp6len); + } else + nd6_ra_input(m, off, icmp6len); m = NULL; goto freeit; } - nd6_ra_input(n, off, icmp6len); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(n, ifp, + SND_IN, ip6len); + if (error == 0) + goto freeit; + nd6_ra_input(n, off, icmp6len); + } else + nd6_ra_input(n, off, icmp6len); /* m stays. */ break; @@ -797,12 +837,25 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (icmp6len < sizeof(struct nd_neighbor_solicit)) goto badlen; if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { - /* give up local */ - nd6_ns_input(m, off, icmp6len); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(m, ifp, + SND_IN, ip6len); + if (error == 0) + return (IPPROTO_DONE); + nd6_ns_input(m, off, icmp6len); + } else + nd6_ns_input(m, off, icmp6len); m = NULL; goto freeit; } - nd6_ns_input(n, off, icmp6len); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(n, ifp, + SND_IN, ip6len); + if (error == 0) + goto freeit; + nd6_ns_input(n, off, icmp6len); + } else + nd6_ns_input(n, off, icmp6len); /* m stays. */ break; @@ -813,12 +866,27 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (icmp6len < sizeof(struct nd_neighbor_advert)) goto badlen; if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { - /* give up local */ - nd6_na_input(m, off, icmp6len); + + /* Send incoming SeND-protected/ND packet to user space. */ + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(m, ifp, + SND_IN, ip6len); + if (error == 0) + return (IPPROTO_DONE); + nd6_na_input(m, off, icmp6len); + } else + nd6_na_input(m, off, icmp6len); m = NULL; goto freeit; } - nd6_na_input(n, off, icmp6len); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(n, ifp, + SND_IN, ip6len); + if (error == 0) + goto freeit; + nd6_na_input(n, off, icmp6len); + } else + nd6_na_input(n, off, icmp6len); /* m stays. */ break; @@ -829,12 +897,25 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) if (icmp6len < sizeof(struct nd_redirect)) goto badlen; if ((n = m_copym(m, 0, M_COPYALL, M_DONTWAIT)) == NULL) { - /* give up local */ - icmp6_redirect_input(m, off); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(m, ifp, + SND_IN, ip6len); + if (error == 0) + return (IPPROTO_DONE); + icmp6_redirect_input(m, off); + } else + icmp6_redirect_input(m, off); m = NULL; goto freeit; } - icmp6_redirect_input(n, off); + if (send_sendso_input_hook != NULL) { + error = send_sendso_input_hook(n, ifp, + SND_IN, ip6len); + if (error == 0) + goto freeit; + icmp6_redirect_input(n, off); + } else + icmp6_redirect_input(n, off); /* m stays. */ break; @@ -2476,6 +2557,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) struct in6_addr *router_ll6; struct ip6_hdr *sip6; /* m0 as struct ip6_hdr */ struct mbuf *m = NULL; /* newly allocated one */ + struct m_tag *mtag; struct ip6_hdr *ip6; /* m as struct ip6_hdr */ struct nd_redirect *nd_rd; struct llentry *ln = NULL; @@ -2735,6 +2817,15 @@ noredhdropt:; nd_rd->nd_rd_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), ntohs(ip6->ip6_plen)); + if (send_sendso_input_hook != NULL) { + mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, sizeof(unsigned short), + M_NOWAIT); + if (mtag == NULL) + goto fail; + *(unsigned short *)(mtag + 1) = nd_rd->nd_rd_type; + m_tag_prepend(m, mtag); + } + /* send the packet to outside... */ ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); if (outif) { diff --git a/sys/netinet6/in6_cksum.c b/sys/netinet6/in6_cksum.c index b15dd147dcb..2ba6d1e1f09 100644 --- a/sys/netinet6/in6_cksum.c +++ b/sys/netinet6/in6_cksum.c @@ -78,7 +78,7 @@ __FBSDID("$FreeBSD$"); */ #define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) -#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} +#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; (void)ADDCARRY(sum);} /* * m MUST contain a continuous IP6 header. diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c index 8927a176df9..2a1364673b3 100644 --- a/sys/netinet6/in6_rmx.c +++ b/sys/netinet6/in6_rmx.c @@ -193,11 +193,13 @@ in6_matroute(void *v_arg, struct radix_node_head *head) struct radix_node *rn = rn_match(v_arg, head); struct rtentry *rt = (struct rtentry *)rn; - if (rt && rt->rt_refcnt == 0) { /* this is first reference */ + if (rt) { + RT_LOCK(rt); if (rt->rt_flags & RTPRF_OURS) { rt->rt_flags &= ~RTPRF_OURS; rt->rt_rmx.rmx_expire = 0; } + RT_UNLOCK(rt); } return rn; } diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index ec822502b60..7e650a24621 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -227,6 +227,64 @@ ip6_init(void) netisr_register(&ip6_nh); } +/* + * The protocol to be inserted into ip6_protox[] must be already registered + * in inet6sw[], either statically or through pf_proto_register(). + */ +int +ip6proto_register(short ip6proto) +{ + struct ip6protosw *pr; + + /* Sanity checks. */ + if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) + return (EPROTONOSUPPORT); + + /* + * The protocol slot must not be occupied by another protocol + * already. An index pointing to IPPROTO_RAW is unused. + */ + pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); + if (pr == NULL) + return (EPFNOSUPPORT); + if (ip6_protox[ip6proto] != pr - inet6sw) /* IPPROTO_RAW */ + return (EEXIST); + + /* + * Find the protocol position in inet6sw[] and set the index. + */ + for (pr = (struct ip6protosw *)inet6domain.dom_protosw; + pr < (struct ip6protosw *)inet6domain.dom_protoswNPROTOSW; pr++) { + if (pr->pr_domain->dom_family == PF_INET6 && + pr->pr_protocol && pr->pr_protocol == ip6proto) { + ip6_protox[pr->pr_protocol] = pr - inet6sw; + return (0); + } + } + return (EPROTONOSUPPORT); +} + +int +ip6proto_unregister(short ip6proto) +{ + struct ip6protosw *pr; + + /* Sanity checks. */ + if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) + return (EPROTONOSUPPORT); + + /* Check if the protocol was indeed registered. */ + pr = (struct ip6protosw *)pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); + if (pr == NULL) + return (EPFNOSUPPORT); + if (ip6_protox[ip6proto] == pr - inet6sw) /* IPPROTO_RAW */ + return (ENOENT); + + /* Reset the protocol slot to IPPROTO_RAW. */ + ip6_protox[ip6proto] = pr - inet6sw; + return (0); +} + #ifdef VIMAGE void ip6_destroy() diff --git a/sys/netinet6/ip6_ipsec.c b/sys/netinet6/ip6_ipsec.c index 48d91628c29..96b09ef8b4c 100644 --- a/sys/netinet6/ip6_ipsec.c +++ b/sys/netinet6/ip6_ipsec.c @@ -366,7 +366,7 @@ ip6_ipsec_mtu(struct mbuf *m) if (sp->req != NULL && sp->req->sav != NULL && sp->req->sav->sah != NULL) { - ro = &sp->req->sav->sah->sa_route; + ro = &sp->req->sav->sah->route_cache.sa_route; if (ro->ro_rt && ro->ro_rt->rt_ifp) { mtu = ro->ro_rt->rt_rmx.rmx_mtu ? diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 2c30b278e77..58853acdcd3 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1823,6 +1823,7 @@ do { \ case IPV6_PORTRANGE: case IPV6_RECVTCLASS: case IPV6_AUTOFLOWLABEL: + case IPV6_BINDANY: switch (optname) { case IPV6_RECVHOPOPTS: diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 3e91a79d0b9..51ae1f74957 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -368,6 +368,9 @@ void ip6_init __P((void)); #ifdef VIMAGE void ip6_destroy __P((void)); #endif +int ip6proto_register(short); +int ip6proto_unregister(short); + void ip6_input __P((struct mbuf *)); struct in6_ifaddr *ip6_getdstifaddr __P((struct mbuf *)); void ip6_freepcbopts __P((struct ip6_pktopts *)); diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index e9081c404c3..c9d9be05869 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -121,6 +122,8 @@ VNET_DEFINE(int, nd6_recalc_reachtm_interval) = ND6_RECALC_REACHTM_INTERVAL; static struct sockaddr_in6 all1_sa; +int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int); + static int nd6_is_new_addr_neighbor __P((struct sockaddr_in6 *, struct ifnet *)); static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); @@ -1758,9 +1761,12 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct mbuf **chain) { struct mbuf *m = m0; + struct m_tag *mtag; struct llentry *ln = lle; + struct ip6_hdr *ip6; int error = 0; int flags = 0; + int ip6len; #ifdef INVARIANTS if (lle != NULL) { @@ -1935,6 +1941,28 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, #ifdef MAC mac_netinet6_nd6_send(ifp, m); #endif + + /* + * If called from nd6_ns_output() (NS), nd6_na_output() (NA), + * icmp6_redirect_output() (REDIRECT) or from rip6_output() (RS, RA + * as handled by rtsol and rtadvd), mbufs will be tagged for SeND + * to be diverted to user space. When re-injected into the kernel, + * send_output() will directly dispatch them to the outgoing interface. + */ + if (send_sendso_input_hook != NULL) { + mtag = m_tag_find(m, PACKET_TAG_ND_OUTGOING, NULL); + if (mtag != NULL) { + ip6 = mtod(m, struct ip6_hdr *); + ip6len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); + /* Use the SEND socket */ + error = send_sendso_input_hook(m, ifp, SND_OUT, + ip6len); + /* -1 == no app on SEND socket */ + if (error == 0 || error != -1) + return (error); + } + } + /* * We were passed in a pointer to an lle with the lock held * this means that we can't call if_output as we will diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 130189d079b..957e9652843 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #define SDL(s) ((struct sockaddr_dl *)s) @@ -379,6 +380,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, const struct in6_addr *taddr6, struct llentry *ln, int dad) { struct mbuf *m; + struct m_tag *mtag; struct ip6_hdr *ip6; struct nd_neighbor_solicit *nd_ns; struct in6_addr *src, src_in; @@ -557,6 +559,15 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6, nd_ns->nd_ns_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len); + if (send_sendso_input_hook != NULL) { + mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, + sizeof(unsigned short), M_NOWAIT); + if (mtag == NULL) + goto bad; + *(unsigned short *)(mtag + 1) = nd_ns->nd_ns_type; + m_tag_prepend(m, mtag); + } + ip6_output(m, NULL, &ro, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL, NULL); icmp6_ifstat_inc(ifp, ifs6_out_msg); icmp6_ifstat_inc(ifp, ifs6_out_neighborsolicit); @@ -604,6 +615,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) struct llentry *ln = NULL; union nd_opts ndopts; struct mbuf *chain = NULL; + struct m_tag *mtag; struct sockaddr_in6 sin6; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; @@ -873,6 +885,15 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * we assume ifp is not a loopback here, so just set * the 2nd argument as the 1st one. */ + + if (send_sendso_input_hook != NULL) { + mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, + sizeof(unsigned short), M_NOWAIT); + if (mtag == NULL) + goto bad; + m_tag_prepend(m, mtag); + } + nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln, &chain); } } @@ -917,6 +938,7 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, struct sockaddr *sdl0) { struct mbuf *m; + struct m_tag *mtag; struct ip6_hdr *ip6; struct nd_neighbor_advert *nd_na; struct ip6_moptions im6o; @@ -1055,6 +1077,15 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0, nd_na->nd_na_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len); + if (send_sendso_input_hook != NULL) { + mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, + sizeof(unsigned short), M_NOWAIT); + if (mtag == NULL) + goto bad; + *(unsigned short *)(mtag + 1) = nd_na->nd_na_type; + m_tag_prepend(m, mtag); + } + ip6_output(m, NULL, &ro, 0, &im6o, NULL, NULL); icmp6_ifstat_inc(ifp, ifs6_out_msg); icmp6_ifstat_inc(ifp, ifs6_out_neighboradvert); diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 0e18fb4a830..6c10fc5479b 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -99,6 +100,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef IPSEC #include @@ -390,6 +392,7 @@ rip6_output(m, va_alist) #endif { struct mbuf *control; + struct m_tag *mtag; struct socket *so; struct sockaddr_in6 *dstsock; struct in6_addr *dst; @@ -401,6 +404,7 @@ rip6_output(m, va_alist) struct ifnet *oifp = NULL; int type = 0, code = 0; /* for ICMPv6 output statistics only */ int scope_ambiguous = 0; + int use_defzone = 0; struct in6_addr in6a; va_list ap; @@ -430,9 +434,12 @@ rip6_output(m, va_alist) * XXX: we may still need to determine the zone later. */ if (!(so->so_state & SS_ISCONNECTED)) { - if (dstsock->sin6_scope_id == 0 && !V_ip6_use_defzone) + if (!optp || !optp->ip6po_pktinfo || + !optp->ip6po_pktinfo->ipi6_ifindex) + use_defzone = V_ip6_use_defzone; + if (dstsock->sin6_scope_id == 0 && !use_defzone) scope_ambiguous = 1; - if ((error = sa6_embedscope(dstsock, V_ip6_use_defzone)) != 0) + if ((error = sa6_embedscope(dstsock, use_defzone)) != 0) goto bad; } @@ -529,6 +536,23 @@ rip6_output(m, va_alist) *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen); } + /* + * Send RA/RS messages to user land for protection, before sending + * them to rtadvd/rtsol. + */ + if ((send_sendso_input_hook != NULL) && + so->so_proto->pr_protocol == IPPROTO_ICMPV6) { + switch (type) { + case ND_ROUTER_ADVERT: + case ND_ROUTER_SOLICIT: + mtag = m_tag_get(PACKET_TAG_ND_OUTGOING, + sizeof(unsigned short), M_NOWAIT); + if (mtag == NULL) + goto bad; + m_tag_prepend(m, mtag); + } + } + error = ip6_output(m, optp, NULL, 0, in6p->in6p_moptions, &oifp, in6p); if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) { if (oifp) diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 02e28802320..cc3af664f9e 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -72,14 +72,22 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) struct sctp_inpcb *in6p = NULL; struct sctp_nets *net; int refcount_up = 0; - uint32_t check, calc_check; uint32_t vrf_id = 0; + +#ifdef IPSEC struct inpcb *in6p_ip; + +#endif struct sctp_chunkhdr *ch; int length, offset, iphlen; uint8_t ecn_bits; struct sctp_tcb *stcb = NULL; int pkt_len = 0; + +#if !defined(SCTP_WITH_NO_CSUM) + uint32_t check, calc_check; + +#endif int off = *offp; uint16_t port = 0; @@ -133,6 +141,9 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) m->m_pkthdr.len, if_name(m->m_pkthdr.rcvif), m->m_pkthdr.csum_flags); +#if defined(SCTP_WITH_NO_CSUM) + SCTP_STAT_INCR(sctps_recvnocrc); +#else if (m->m_pkthdr.csum_flags & CSUM_SCTP_VALID) { SCTP_STAT_INCR(sctps_recvhwcrc); goto sctp_skip_csum; @@ -171,6 +182,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto) sh->checksum = calc_check; sctp_skip_csum: +#endif net = NULL; /* * Locate pcb and tcb for datagram sctp_findassociation_addr() wants @@ -216,11 +228,11 @@ sctp_skip_csum: } else if (stcb == NULL) { refcount_up = 1; } - in6p_ip = (struct inpcb *)in6p; #ifdef IPSEC /* * Check AH/ESP integrity. */ + in6p_ip = (struct inpcb *)in6p; if (in6p_ip && (ipsec6_in_reject(m, in6p_ip))) { /* XXX */ MODULE_GLOBAL(ipsec6stat).in_polvio++; @@ -414,7 +426,8 @@ sctp6_notify(struct sctp_inpcb *inp, * PF state. */ /* Stop any running T3 timers here? */ - if (SCTP_BASE_SYSCTL(sctp_cmt_on_off) && SCTP_BASE_SYSCTL(sctp_cmt_pf)) { + if ((stcb->asoc.sctp_cmt_on_off == 1) && + (stcb->asoc.sctp_cmt_pf > 0)) { net->dest_state &= ~SCTP_ADDR_PF; SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n", net); @@ -804,7 +817,6 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct thread *p) { struct sctp_inpcb *inp; - struct inpcb *in_inp; struct in6pcb *inp6; #ifdef INET @@ -823,7 +835,6 @@ sctp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL); return EINVAL; } - in_inp = (struct inpcb *)inp; inp6 = (struct in6pcb *)inp; /* * For the TCP model we may get a NULL addr, if we are a connected @@ -1069,6 +1080,8 @@ sctp6_getaddr(struct socket *so, struct sockaddr **addr) * Do the malloc first in case it blocks. */ SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); + if (sin6 == NULL) + return ENOMEM; sin6->sin6_family = AF_INET6; sin6->sin6_len = sizeof(*sin6); @@ -1173,6 +1186,8 @@ sctp6_peeraddr(struct socket *so, struct sockaddr **addr) return (ENOTCONN); } SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); + if (sin6 == NULL) + return (ENOMEM); sin6->sin6_family = AF_INET6; sin6->sin6_len = sizeof(*sin6); diff --git a/sys/netinet6/send.c b/sys/netinet6/send.c new file mode 100644 index 00000000000..71d88d07a8a --- /dev/null +++ b/sys/netinet6/send.c @@ -0,0 +1,367 @@ +/*- + * Copyright (c) 2009-2010 Ana Kukec + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +MALLOC_DEFINE(M_SEND, "send", "Secure Neighbour Discovery"); + +/* + * The socket used to communicate with the SeND daemon. + */ +static VNET_DEFINE(struct socket *, send_so); +#define V_send_so VNET(send_so) + +u_long send_sendspace = 8 * (1024 + sizeof(struct sockaddr_send)); +u_long send_recvspace = 9216; + +struct mtx send_mtx; +#define SEND_LOCK_INIT() mtx_init(&send_mtx, "send_mtx", NULL, MTX_DEF) +#define SEND_LOCK() mtx_lock(&send_mtx) +#define SEND_UNLOCK() mtx_unlock(&send_mtx) +#define SEND_LOCK_DESTROY() mtx_destroy(&send_mtx) + +static int +send_attach(struct socket *so, int proto, struct thread *td) +{ + int error; + + SEND_LOCK(); + if (V_send_so != NULL) { + SEND_UNLOCK(); + return (EEXIST); + } + + error = priv_check(td, PRIV_NETINET_RAW); + if (error) { + SEND_UNLOCK(); + return(error); + } + + if (proto != IPPROTO_SEND) { + SEND_UNLOCK(); + return (EPROTONOSUPPORT); + } + error = soreserve(so, send_sendspace, send_recvspace); + if (error) { + SEND_UNLOCK(); + return(error); + } + + V_send_so = so; + SEND_UNLOCK(); + + return (0); +} + +static int +send_output(struct mbuf *m, struct ifnet *ifp, int direction) +{ + struct ip6_hdr *ip6; + struct sockaddr_in6 dst; + struct icmp6_hdr *icmp6; + int icmp6len; + + /* + * Receive incoming (SeND-protected) or outgoing traffic + * (SeND-validated) from the SeND user space application. + */ + + switch (direction) { + case SND_IN: + if (m->m_len < (sizeof(struct ip6_hdr) + + sizeof(struct icmp6_hdr))) { + m = m_pullup(m, sizeof(struct ip6_hdr) + + sizeof(struct icmp6_hdr)); + if (!m) + return (ENOBUFS); + } + + /* Before passing off the mbuf record the proper interface. */ + m->m_pkthdr.rcvif = ifp; + + if (m->m_flags & M_PKTHDR) + icmp6len = m->m_pkthdr.len - sizeof(struct ip6_hdr); + else + panic("Doh! not the first mbuf."); + + ip6 = mtod(m, struct ip6_hdr *); + icmp6 = (struct icmp6_hdr *)(ip6 + 1); + + /* + * Output the packet as icmp6.c:icpm6_input() would do. + * The mbuf is always consumed, so we do not have to + * care about that. + */ + switch (icmp6->icmp6_type) { + case ND_NEIGHBOR_SOLICIT: + nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len); + break; + case ND_NEIGHBOR_ADVERT: + nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len); + break; + case ND_REDIRECT: + icmp6_redirect_input(m, sizeof(struct ip6_hdr)); + break; + case ND_ROUTER_SOLICIT: + nd6_rs_input(m, sizeof(struct ip6_hdr), icmp6len); + break; + case ND_ROUTER_ADVERT: + nd6_ra_input(m, sizeof(struct ip6_hdr), icmp6len); + break; + default: + return (ENOSYS); + } + return (0); + + case SND_OUT: + if (m->m_len < sizeof(struct ip6_hdr)) { + m = m_pullup(m, sizeof(struct ip6_hdr)); + if (!m) + return (ENOBUFS); + } + ip6 = mtod(m, struct ip6_hdr *); + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) + m->m_flags |= M_MCAST; + + bzero(&dst, sizeof(dst)); + dst.sin6_family = AF_INET6; + dst.sin6_len = sizeof(dst); + dst.sin6_addr = ip6->ip6_dst; + + /* + * Output the packet as nd6.c:nd6_output_lle() would do. + * The mbuf is always consumed, so we do not have to care + * about that. + * XXX-BZ as we added data, what about fragmenting, + * if now needed? + */ + int error; + error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst, + NULL)); + if (error) + error = ENOENT; + return (error); + + default: + panic("%s: direction %d neither SND_IN nor SND_OUT.", + __func__, direction); + } +} + +/* + * Receive a SeND message from user space to be either send out by the kernel + * or, with SeND ICMPv6 options removed, to be further processed by the icmp6 + * input path. + */ +static int +send_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, + struct mbuf *control, struct thread *td) +{ + struct sockaddr_send *sendsrc; + struct ifnet *ifp; + int error; + + KASSERT(V_send_so == so, ("%s: socket %p not send socket %p", + __func__, so, V_send_so)); + + sendsrc = (struct sockaddr_send *)nam; + ifp = ifnet_byindex_ref(sendsrc->send_ifidx); + if (ifp == NULL) { + error = ENETUNREACH; + goto err; + } + + error = send_output(m, ifp, sendsrc->send_direction); + if_rele(ifp); + m = NULL; + +err: + if (m != NULL) + m_freem(m); + return (error); +} + +static void +send_close(struct socket *so) +{ + + SEND_LOCK(); + if (V_send_so) + V_send_so = NULL; + SEND_UNLOCK(); +} + +/* + * Send a SeND message to user space, that was either received and has to be + * validated or was about to be send out and has to be handled by the SEND + * daemon adding SeND ICMPv6 options. + */ +static int +send_input(struct mbuf *m, struct ifnet *ifp, int direction, int msglen __unused) +{ + struct ip6_hdr *ip6; + struct sockaddr_send sendsrc; + + SEND_LOCK(); + if (V_send_so == NULL) { + SEND_UNLOCK(); + return (-1); + } + + /* + * Make sure to clear any possible internally embedded scope before + * passing the packet to user space for SeND cryptographic signature + * validation to succeed. + */ + ip6 = mtod(m, struct ip6_hdr *); + in6_clearscope(&ip6->ip6_src); + in6_clearscope(&ip6->ip6_dst); + + bzero(&sendsrc, sizeof(sendsrc)); + sendsrc.send_len = sizeof(sendsrc); + sendsrc.send_family = AF_INET6; + sendsrc.send_direction = direction; + sendsrc.send_ifidx = ifp->if_index; + + /* + * Send incoming or outgoing traffic to user space either to be + * protected (outgoing) or validated (incoming) according to rfc3971. + */ + SOCKBUF_LOCK(&V_send_so->so_rcv); + if (sbappendaddr_locked(&V_send_so->so_rcv, + (struct sockaddr *)&sendsrc, m, NULL) == 0) { + SOCKBUF_UNLOCK(&V_send_so->so_rcv); + /* XXX stats. */ + m_freem(m); + } else { + sorwakeup_locked(V_send_so); + } + + SEND_UNLOCK(); + return (0); +} + +struct pr_usrreqs send_usrreqs = { + .pru_attach = send_attach, + .pru_send = send_send, + .pru_detach = send_close +}; +struct protosw send_protosw = { + .pr_type = SOCK_RAW, + .pr_flags = PR_ATOMIC|PR_ADDR, + .pr_protocol = IPPROTO_SEND, + .pr_usrreqs = &send_usrreqs +}; + +static int +send_modevent(module_t mod, int type, void *unused) +{ +#ifdef __notyet__ + VNET_ITERATOR_DECL(vnet_iter); +#endif + int error; + + switch (type) { + case MOD_LOAD: + SEND_LOCK_INIT(); + + error = pf_proto_register(PF_INET6, &send_protosw); + if (error != 0) { + printf("%s:%d: MOD_LOAD pf_proto_register(): %d\n", + __func__, __LINE__, error); + SEND_LOCK_DESTROY(); + break; + } + send_sendso_input_hook = send_input; + break; + case MOD_UNLOAD: + /* Do not allow unloading w/o locking. */ + return (EBUSY); +#ifdef __notyet__ + VNET_LIST_RLOCK_NOSLEEP(); + SEND_LOCK(); + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + if (V_send_so != NULL) { + CURVNET_RESTORE(); + SEND_UNLOCK(); + VNET_LIST_RUNLOCK_NOSLEEP(); + return (EBUSY); + } + CURVNET_RESTORE(); + } + SEND_UNLOCK(); + VNET_LIST_RUNLOCK_NOSLEEP(); + error = pf_proto_unregister(PF_INET6, IPPROTO_SEND, SOCK_RAW); + if (error == 0) + SEND_LOCK_DESTROY(); + send_sendso_input_hook = NULL; + break; +#endif + default: + error = 0; + break; + } + + return (error); +} + +static moduledata_t sendmod = { + "send", + send_modevent, + 0 +}; + +DECLARE_MODULE(send, sendmod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); diff --git a/sys/netinet6/send.h b/sys/netinet6/send.h new file mode 100644 index 00000000000..36ba571a554 --- /dev/null +++ b/sys/netinet6/send.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2009-2010 Ana Kukec + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _NETINET6_SEND_H_ +#define _NETINET6_SEND_H_ + +#define SND_OUT 0 /* Outgoing traffic */ +#define SND_IN 1 /* Incoming traffic. */ + +struct sockaddr_send { + unsigned char send_len; /* total length */ + sa_family_t send_family; /* address family */ + int send_direction; + int send_ifidx; + char send_zero[8]; +}; + +extern int (*send_sendso_input_hook)(struct mbuf *, struct ifnet *, int, int); + +#endif /* _NETINET6_SEND_H_ */ diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index 8e8a1e394fd..0907f457551 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -758,7 +758,7 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int struct ipsecrequest *isr; struct secasindex saidx; int error; - struct sockaddr_in6* dst6; + struct sockaddr_in6 *dst6; struct mbuf *m; IPSEC_ASSERT(state != NULL, ("null state")); @@ -829,7 +829,8 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int } ip6 = mtod(m, struct ip6_hdr *); - state->ro = &isr->sav->sah->sa_route; + state->ro = + (struct route *)&isr->sav->sah->route_cache.sin6_route; state->dst = (struct sockaddr *)&state->ro->ro_dst; dst6 = (struct sockaddr_in6 *)state->dst; if (state->ro->ro_rt @@ -853,10 +854,8 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int } /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { + if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst6 = (struct sockaddr_in6 *)state->dst; - } } m = ipsec6_splithdr(m); diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index d00489db907..e57eb4432bb 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -2758,9 +2758,9 @@ key_delsah(sah) /* remove from tree of SA index */ if (__LIST_CHAINED(sah)) LIST_REMOVE(sah, chain); - if (sah->sa_route.ro_rt) { - RTFREE(sah->sa_route.ro_rt); - sah->sa_route.ro_rt = (struct rtentry *)NULL; + if (sah->route_cache.sa_route.ro_rt) { + RTFREE(sah->route_cache.sa_route.ro_rt); + sah->route_cache.sa_route.ro_rt = (struct rtentry *)NULL; } free(sah, M_IPSEC_SAH); } @@ -7925,7 +7925,7 @@ key_sa_routechange(dst) SAHTREE_LOCK(); LIST_FOREACH(sah, &V_sahtree, chain) { - ro = &sah->sa_route; + ro = &sah->route_cache.sa_route; if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { RTFREE(ro->ro_rt); diff --git a/sys/netipsec/keydb.h b/sys/netipsec/keydb.h index 07e1f6024e0..7494f5f4f3f 100644 --- a/sys/netipsec/keydb.h +++ b/sys/netipsec/keydb.h @@ -85,6 +85,12 @@ struct seclifetime { u_int64_t usetime; }; +union sa_route_union { + struct route sa_route; + struct route sin_route; /* Duplicate for consistency. */ + struct route_in6 sin6_route; +}; + /* Security Association Data Base */ struct secashead { LIST_ENTRY(secashead) chain; @@ -100,7 +106,7 @@ struct secashead { /* SA chain */ /* The first of this list is newer SA */ - struct route sa_route; /* route cache */ + union sa_route_union route_cache; }; struct xformsw; diff --git a/sys/nfs/nfs_lock.c b/sys/nfs/nfs_lock.c index 89ad6542243..4c220e20615 100644 --- a/sys/nfs/nfs_lock.c +++ b/sys/nfs/nfs_lock.c @@ -62,6 +62,9 @@ __FBSDID("$FreeBSD$"); extern void (*nlminfo_release_p)(struct proc *p); +vop_advlock_t *nfs_advlock_p = nfs_dolock; +vop_reclaim_t *nfs_reclaim_p = NULL; + MALLOC_DEFINE(M_NFSLOCK, "nfsclient_lock", "NFS lock request"); MALLOC_DEFINE(M_NLMINFO, "nfsclient_nlminfo", "NFS lock process structure"); @@ -236,20 +239,19 @@ nfs_dolock(struct vop_advlock_args *ap) int error; struct flock *fl; struct proc *p; + struct nfsmount *nmp; td = curthread; p = td->td_proc; vp = ap->a_vp; fl = ap->a_fl; + nmp = VFSTONFS(vp->v_mount); ASSERT_VOP_LOCKED(vp, "nfs_dolock"); - bcopy(VFSTONFS(vp->v_mount)->nm_nam, &msg.lm_addr, - min(sizeof msg.lm_addr, VFSTONFS(vp->v_mount)->nm_nam->sa_len)); - msg.lm_fh_len = NFS_ISV3(vp) ? VTONFS(vp)->n_fhsize : NFSX_V2FH; - bcopy(VTONFS(vp)->n_fhp, msg.lm_fh, msg.lm_fh_len); - msg.lm_nfsv3 = NFS_ISV3(vp); + nmp->nm_getinfo(vp, msg.lm_fh, &msg.lm_fh_len, &msg.lm_addr, + &msg.lm_nfsv3, NULL); VOP_UNLOCK(vp, 0); /* diff --git a/sys/nfs/nfs_lock.h b/sys/nfs/nfs_lock.h index aa99996cdec..ff5feb223ec 100644 --- a/sys/nfs/nfs_lock.h +++ b/sys/nfs/nfs_lock.h @@ -87,4 +87,6 @@ struct lockd_ans { #ifdef _KERNEL int nfs_dolock(struct vop_advlock_args *ap); +extern vop_advlock_t *nfs_advlock_p; +extern vop_reclaim_t *nfs_reclaim_p; #endif diff --git a/sys/nfs/nfs_mountcommon.h b/sys/nfs/nfs_mountcommon.h new file mode 100644 index 00000000000..c004b9c649f --- /dev/null +++ b/sys/nfs/nfs_mountcommon.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2009 Rick Macklem, University of Guelph + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _NFS_MOUNTCOMMON_H_ +#define _NFS_MOUNTCOMMON_H_ + +/* + * The common fields of the nfsmount structure for the two clients + * used by the nlm. It includes a function pointer that provides + * a mechanism for getting the client specific info for an nfs vnode. + */ +typedef void nfs_getinfofromvp_ftype(struct vnode *, uint8_t *, size_t *, + struct sockaddr_storage *, int *, off_t *); + +struct nfsmount_common { + struct mtx nmcom_mtx; + int nmcom_flag; /* Flags for soft/hard... */ + int nmcom_state; /* Internal state flags */ + struct mount *nmcom_mountp; /* Vfs structure for this filesystem */ + int nmcom_timeo; /* Init timer for NFSMNT_DUMBTIMR */ + int nmcom_retry; /* Max retries */ + char nmcom_hostname[MNAMELEN]; /* server's name */ + nfs_getinfofromvp_ftype *nmcom_getinfo; /* Get info from nfsnode */ +}; + +#endif /* _NFS_MOUNTCOMMON_H_ */ diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h index 6f6e0d33ad5..99b86f85d7a 100644 --- a/sys/nfsclient/nfs.h +++ b/sys/nfsclient/nfs.h @@ -125,6 +125,7 @@ extern struct uma_zone *nfsmount_zone; extern struct nfsstats nfsstats; extern struct mtx nfs_iod_mtx; +extern struct task nfs_nfsiodnew_task; extern int nfs_numasync; extern unsigned int nfs_iodmax; @@ -252,7 +253,8 @@ int nfs_writerpc(struct vnode *, struct uio *, struct ucred *, int *, int nfs_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred, struct thread *td); int nfs_readdirrpc(struct vnode *, struct uio *, struct ucred *); -int nfs_nfsiodnew(int); +void nfs_nfsiodnew(void); +void nfs_nfsiodnew_tq(__unused void *, int); int nfs_asyncio(struct nfsmount *, struct buf *, struct ucred *, struct thread *); int nfs_doio(struct vnode *, struct buf *, struct ucred *, struct thread *); void nfs_doio_directwrite (struct buf *); diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c index 2f40bb2f941..047df94c431 100644 --- a/sys/nfsclient/nfs_bio.c +++ b/sys/nfsclient/nfs_bio.c @@ -1375,13 +1375,9 @@ again: /* * Try to create one if none are free. */ - if (!gotiod) { - iod = nfs_nfsiodnew(1); - if (iod != -1) - gotiod = TRUE; - } - - if (gotiod) { + if (!gotiod) + nfs_nfsiodnew(); + else { /* * Found one, so wake it up and tell it which * mount to process. @@ -1401,7 +1397,7 @@ again: if (!gotiod) { if (nmp->nm_bufqiods > 0) { NFS_DPF(ASYNCIO, - ("nfs_asyncio: %d iods are already processing mount %p\n", + ("nfs_asyncio: %d iods are already processing mount %p\n", nmp->nm_bufqiods, nmp)); gotiod = TRUE; } @@ -1416,9 +1412,9 @@ again: * Ensure that the queue never grows too large. We still want * to asynchronize so we block rather then return EIO. */ - while (nmp->nm_bufqlen >= 2*nfs_numasync) { + while (nmp->nm_bufqlen >= 2 * nfs_numasync) { NFS_DPF(ASYNCIO, - ("nfs_asyncio: waiting for mount %p queue to drain\n", nmp)); + ("nfs_asyncio: waiting for mount %p queue to drain\n", nmp)); nmp->nm_bufqwant = TRUE; error = nfs_msleep(td, &nmp->nm_bufq, &nfs_iod_mtx, slpflag | PRIBIO, @@ -1426,7 +1422,7 @@ again: if (error) { error2 = nfs_sigintr(nmp, td); if (error2) { - mtx_unlock(&nfs_iod_mtx); + mtx_unlock(&nfs_iod_mtx); return (error2); } if (slpflag == NFS_PCATCH) { @@ -1438,17 +1434,13 @@ again: * We might have lost our iod while sleeping, * so check and loop if nescessary. */ - if (nmp->nm_bufqiods == 0) { - NFS_DPF(ASYNCIO, - ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp)); - goto again; - } + goto again; } /* We might have lost our nfsiod */ if (nmp->nm_bufqiods == 0) { NFS_DPF(ASYNCIO, - ("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp)); +("nfs_asyncio: no iods after mount %p queue was drained, looping\n", nmp)); goto again; } diff --git a/sys/nfsclient/nfs_diskless.c b/sys/nfsclient/nfs_diskless.c index 2f91b9d1799..aacecfff961 100644 --- a/sys/nfsclient/nfs_diskless.c +++ b/sys/nfsclient/nfs_diskless.c @@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$"); static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa); static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa); -static int decode_nfshandle(char *ev, u_char *fh); +static int decode_nfshandle(char *ev, u_char *fh, int maxfh); /* * Validate/sanity check a rsize/wsize parameter. @@ -143,20 +143,37 @@ nfs_parse_options(const char *envopts, struct nfs_args *nd) * boot.nfsroot.server IP address of root filesystem server * boot.nfsroot.path path of the root filesystem on server * boot.nfsroot.nfshandle NFS handle for root filesystem on server + * boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only) * boot.nfsroot.options NFS options for the root filesystem */ void nfs_setup_diskless(void) { struct nfs_diskless *nd = &nfs_diskless; + struct nfsv3_diskless *nd3 = &nfsv3_diskless; struct ifnet *ifp; struct ifaddr *ifa; struct sockaddr_dl *sdl, ourdl; struct sockaddr_in myaddr, netmask; char *cp; + int cnt, fhlen, is_nfsv3; + uint32_t len; - if (nfs_diskless_valid) + if (nfs_diskless_valid != 0) return; + + /* get handle size. If this succeeds, it's an NFSv3 setup. */ + if ((cp = getenv("boot.nfsroot.nfshandlelen")) != NULL) { + cnt = sscanf(cp, "%d", &len); + freeenv(cp); + if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) { + printf("nfs_diskless: bad NFS handle len\n"); + return; + } + nd3->root_fhsize = len; + is_nfsv3 = 1; + } else + is_nfsv3 = 0; /* set up interface */ if (inaddr_to_sockaddr("boot.netif.ip", &myaddr)) return; @@ -164,11 +181,21 @@ nfs_setup_diskless(void) printf("nfs_diskless: no netmask\n"); return; } - bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr)); - bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr)); - ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr = - myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; - bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); + if (is_nfsv3 != 0) { + bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr)); + bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr)); + ((struct sockaddr_in *) + &nd3->myif.ifra_broadaddr)->sin_addr.s_addr = + myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; + bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask)); + } else { + bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr)); + bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr)); + ((struct sockaddr_in *) + &nd->myif.ifra_broadaddr)->sin_addr.s_addr = + myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr; + bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask)); + } if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) { printf("nfs_diskless: no hardware address\n"); @@ -196,46 +223,94 @@ nfs_setup_diskless(void) return; /* no matching interface */ match_done: setenv("boot.netif.name", ifp->if_xname); - strlcpy(nd->myif.ifra_name, ifp->if_xname, sizeof(nd->myif.ifra_name)); + if (is_nfsv3 != 0) { + strlcpy(nd3->myif.ifra_name, ifp->if_xname, + sizeof(nd3->myif.ifra_name)); - /* set up gateway */ - inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); + /* set up gateway */ + inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway); - /* set up root mount */ - nd->root_args.rsize = 8192; /* XXX tunable? */ - nd->root_args.wsize = 8192; - nd->root_args.sotype = SOCK_STREAM; - nd->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT); - if (inaddr_to_sockaddr("boot.nfsroot.server", &nd->root_saddr)) { - printf("nfs_diskless: no server\n"); - return; - } - nd->root_saddr.sin_port = htons(NFS_PORT); - if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) { - printf("nfs_diskless: no NFS handle\n"); - return; - } - if ((cp = getenv("boot.nfsroot.path")) != NULL) { - strncpy(nd->root_hostnam, cp, MNAMELEN - 1); - freeenv(cp); - } - if ((cp = getenv("boot.nfsroot.options")) != NULL) { - struct nfs_args args; + /* set up root mount */ + nd3->root_args.rsize = 32768; /* XXX tunable? */ + nd3->root_args.wsize = 32768; + nd3->root_args.sotype = SOCK_STREAM; + nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE | + NFSMNT_RSIZE | NFSMNT_RESVPORT); + if (inaddr_to_sockaddr("boot.nfsroot.server", + &nd3->root_saddr)) { + printf("nfs_diskless: no server\n"); + return; + } + nd3->root_saddr.sin_port = htons(NFS_PORT); + fhlen = decode_nfshandle("boot.nfsroot.nfshandle", + &nd3->root_fh[0], NFSX_V3FHMAX); + if (fhlen == 0) { + printf("nfs_diskless: no NFS handle\n"); + return; + } + if (fhlen != nd3->root_fhsize) { + printf("nfs_diskless: bad NFS handle len=%d\n", fhlen); + return; + } + if ((cp = getenv("boot.nfsroot.path")) != NULL) { + strncpy(nd3->root_hostnam, cp, MNAMELEN - 1); + freeenv(cp); + } + if ((cp = getenv("boot.nfsroot.options")) != NULL) { + nfs_parse_options(cp, &nd3->root_args); + freeenv(cp); + } + + nfs_diskless_valid = 3; + } else { + strlcpy(nd->myif.ifra_name, ifp->if_xname, + sizeof(nd->myif.ifra_name)); + + /* set up gateway */ + inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway); - /* XXX yech, convert between old and current arg format */ - args.flags = nd->root_args.flags; - args.sotype = nd->root_args.sotype; - args.rsize = nd->root_args.rsize; - args.wsize = nd->root_args.wsize; - nfs_parse_options(cp, &args); - nd->root_args.flags = args.flags; - nd->root_args.sotype = args.sotype; - nd->root_args.rsize = args.rsize; - nd->root_args.wsize = args.wsize; - freeenv(cp); + /* set up root mount */ + nd->root_args.rsize = 8192; /* XXX tunable? */ + nd->root_args.wsize = 8192; + nd->root_args.sotype = SOCK_STREAM; + nd->root_args.flags = (NFSMNT_WSIZE | + NFSMNT_RSIZE | NFSMNT_RESVPORT); + if (inaddr_to_sockaddr("boot.nfsroot.server", + &nd->root_saddr)) { + printf("nfs_diskless: no server\n"); + return; + } + nd->root_saddr.sin_port = htons(NFS_PORT); + if (decode_nfshandle("boot.nfsroot.nfshandle", + &nd->root_fh[0], NFSX_V2FH) == 0) { + printf("nfs_diskless: no NFS handle\n"); + return; + } + if ((cp = getenv("boot.nfsroot.path")) != NULL) { + strncpy(nd->root_hostnam, cp, MNAMELEN - 1); + freeenv(cp); + } + if ((cp = getenv("boot.nfsroot.options")) != NULL) { + struct nfs_args args; + + /* + * XXX yech, convert between old and current + * arg format + */ + args.flags = nd->root_args.flags; + args.sotype = nd->root_args.sotype; + args.rsize = nd->root_args.rsize; + args.wsize = nd->root_args.wsize; + nfs_parse_options(cp, &args); + nd->root_args.flags = args.flags; + nd->root_args.sotype = args.sotype; + nd->root_args.rsize = args.rsize; + nd->root_args.wsize = args.wsize; + freeenv(cp); + } + + nfs_diskless_valid = 1; } - - nfs_diskless_valid = 1; } static int @@ -289,7 +364,7 @@ hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa) } static int -decode_nfshandle(char *ev, u_char *fh) +decode_nfshandle(char *ev, u_char *fh, int maxfh) { u_char *cp, *ep; int len, val; @@ -315,7 +390,7 @@ decode_nfshandle(char *ev, u_char *fh) *(fh++) = val; len++; cp += 2; - if (len > NFSX_V2FH) { + if (len > maxfh) { freeenv(ep); return (0); } diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c index d192848f067..fcb987e5767 100644 --- a/sys/nfsclient/nfs_nfsiod.c +++ b/sys/nfsclient/nfs_nfsiod.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -90,6 +91,8 @@ unsigned int nfs_iodmax = 20; /* Minimum number of nfsiod kthreads to keep as spares */ static unsigned int nfs_iodmin = 0; +static int nfs_nfsiodnew_sync(void); + static int sysctl_iodmin(SYSCTL_HANDLER_ARGS) { @@ -113,7 +116,7 @@ sysctl_iodmin(SYSCTL_HANDLER_ARGS) * than the new minimum, create some more. */ for (i = nfs_iodmin - nfs_numasync; i > 0; i--) - nfs_nfsiodnew(0); + nfs_nfsiodnew_sync(); out: mtx_unlock(&nfs_iod_mtx); return (0); @@ -159,42 +162,55 @@ SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0, sizeof (nfs_iodmax), sysctl_iodmax, "IU", "Max number of nfsiod kthreads"); -int -nfs_nfsiodnew(int set_iodwant) +static int +nfs_nfsiodnew_sync(void) { int error, i; - int newiod; - if (nfs_numasync >= nfs_iodmax) - return (-1); - newiod = -1; - for (i = 0; i < nfs_iodmax; i++) + mtx_assert(&nfs_iod_mtx, MA_OWNED); + for (i = 0; i < nfs_iodmax; i++) { if (nfs_asyncdaemon[i] == 0) { - nfs_asyncdaemon[i]++; - newiod = i; + nfs_asyncdaemon[i] = 1; break; } - if (newiod == -1) - return (-1); - if (set_iodwant > 0) - nfs_iodwant[i] = NFSIOD_CREATED_FOR_NFS_ASYNCIO; - mtx_unlock(&nfs_iod_mtx); - error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID, - 0, "nfsiod %d", newiod); - mtx_lock(&nfs_iod_mtx); - if (error) { - if (set_iodwant > 0) - nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE; - return (-1); } - nfs_numasync++; - return (newiod); + if (i == nfs_iodmax) + return (0); + mtx_unlock(&nfs_iod_mtx); + error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, + RFHIGHPID, 0, "nfsiod %d", i); + mtx_lock(&nfs_iod_mtx); + if (error == 0) { + nfs_numasync++; + nfs_iodwant[i] = NFSIOD_AVAILABLE; + } else + nfs_asyncdaemon[i] = 0; + return (error); +} + +void +nfs_nfsiodnew_tq(__unused void *arg, int pending) +{ + + mtx_lock(&nfs_iod_mtx); + while (pending > 0) { + pending--; + nfs_nfsiodnew_sync(); + } + mtx_unlock(&nfs_iod_mtx); +} + +void +nfs_nfsiodnew(void) +{ + + mtx_assert(&nfs_iod_mtx, MA_OWNED); + taskqueue_enqueue(taskqueue_thread, &nfs_nfsiodnew_task); } static void nfsiod_setup(void *dummy) { - int i; int error; TUNABLE_INT_FETCH("vfs.nfs.iodmin", &nfs_iodmin); @@ -203,8 +219,8 @@ nfsiod_setup(void *dummy) if (nfs_iodmin > NFS_MAXASYNCDAEMON) nfs_iodmin = NFS_MAXASYNCDAEMON; - for (i = 0; i < nfs_iodmin; i++) { - error = nfs_nfsiodnew(0); + while (nfs_numasync < nfs_iodmin) { + error = nfs_nfsiodnew_sync(); if (error == -1) panic("nfsiod_setup: nfs_nfsiodnew failed"); } diff --git a/sys/nfsclient/nfs_node.c b/sys/nfsclient/nfs_node.c index 947beed8267..5b87bd73b8b 100644 --- a/sys/nfsclient/nfs_node.c +++ b/sys/nfsclient/nfs_node.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -150,6 +152,7 @@ nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int /* * NFS supports recursive and shared locking. */ + lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); VN_LOCK_AREC(vp); VN_LOCK_ASHARE(vp); if (fhsize > NFS_SMALLFH) { @@ -158,7 +161,6 @@ nfs_nget(struct mount *mntp, nfsfh_t *fhp, int fhsize, struct nfsnode **npp, int np->n_fhp = &np->n_fh; bcopy((caddr_t)fhp, (caddr_t)np->n_fhp, fhsize); np->n_fhsize = fhsize; - lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); error = insmntque(vp, mntp); if (error != 0) { *npp = NULL; diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c index 0ab5fa28c2e..7c9941fdd17 100644 --- a/sys/nfsclient/nfs_subs.c +++ b/sys/nfsclient/nfs_subs.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -117,6 +118,7 @@ int nfs_pbuf_freecnt = -1; /* start out unlimited */ struct nfs_bufq nfs_bufq; static struct mtx nfs_xid_mtx; +struct task nfs_nfsiodnew_task; /* * and the reverse mapping from generic to Version 2 procedure numbers @@ -354,6 +356,7 @@ nfs_init(struct vfsconf *vfsp) */ mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF); mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF); + TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL); nfs_pbuf_freecnt = nswbuf / 2 + 1; @@ -368,9 +371,13 @@ nfs_uninit(struct vfsconf *vfsp) /* * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup * any sleeping nfsiods so they check nfs_iodmax and exit. + * Drain nfsiodnew task before we wait for them to finish. */ mtx_lock(&nfs_iod_mtx); nfs_iodmax = 0; + mtx_unlock(&nfs_iod_mtx); + taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task); + mtx_lock(&nfs_iod_mtx); for (i = 0; i < nfs_numasync; i++) if (nfs_iodwant[i] == NFSIOD_AVAILABLE) wakeup(&nfs_iodwant[i]); diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c index f07bf161707..fd50ca83b2c 100644 --- a/sys/nfsclient/nfs_vfsops.c +++ b/sys/nfsclient/nfs_vfsops.c @@ -115,6 +115,8 @@ static void nfs_decode_args(struct mount *mp, struct nfsmount *nmp, static int mountnfs(struct nfs_args *, struct mount *, struct sockaddr *, char *, struct vnode **, struct ucred *cred, int); +static void nfs_getnlminfo(struct vnode *, uint8_t *, size_t *, + struct sockaddr_storage *, int *, off_t *); static vfs_mount_t nfs_mount; static vfs_cmount_t nfs_cmount; static vfs_unmount_t nfs_unmount; @@ -1202,6 +1204,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, bzero((caddr_t)nmp, sizeof (struct nfsmount)); TAILQ_INIT(&nmp->nm_bufq); mp->mnt_data = nmp; + nmp->nm_getinfo = nfs_getnlminfo; } vfs_getnewfsid(mp); nmp->nm_mountp = mp; @@ -1490,3 +1493,27 @@ nfs_sysctl(struct mount *mp, fsctlop_t op, struct sysctl_req *req) } return (0); } + +/* + * Extract the information needed by the nlm from the nfs vnode. + */ +static void +nfs_getnlminfo(struct vnode *vp, uint8_t *fhp, size_t *fhlenp, + struct sockaddr_storage *sp, int *is_v3p, off_t *sizep) +{ + struct nfsmount *nmp; + struct nfsnode *np = VTONFS(vp); + + nmp = VFSTONFS(vp->v_mount); + if (fhlenp != NULL) + *fhlenp = (size_t)np->n_fhsize; + if (fhp != NULL) + bcopy(np->n_fhp, fhp, np->n_fhsize); + if (sp != NULL) + bcopy(nmp->nm_nam, sp, min(nmp->nm_nam->sa_len, sizeof(*sp))); + if (is_v3p != NULL) + *is_v3p = NFS_ISV3(vp); + if (sizep != NULL) + *sizep = np->n_size; +} + diff --git a/sys/nfsclient/nfs_vnops.c b/sys/nfsclient/nfs_vnops.c index f1e173d178d..cb2a126f092 100644 --- a/sys/nfsclient/nfs_vnops.c +++ b/sys/nfsclient/nfs_vnops.c @@ -215,8 +215,6 @@ struct mtx nfs_iod_mtx; enum nfsiod_state nfs_iodwant[NFS_MAXASYNCDAEMON]; struct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON]; int nfs_numasync = 0; -vop_advlock_t *nfs_advlock_p = nfs_dolock; -vop_reclaim_t *nfs_reclaim_p = NULL; #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) SYSCTL_DECL(_vfs_nfs); @@ -916,7 +914,7 @@ nfs_lookup(struct vop_lookup_args *ap) struct vnode **vpp = ap->a_vpp; struct mount *mp = dvp->v_mount; struct vattr vattr; - time_t dmtime; + struct timespec dmtime; int flags = cnp->cn_flags; struct vnode *newvp; struct nfsmount *nmp; @@ -970,7 +968,7 @@ nfs_lookup(struct vop_lookup_args *ap) mtx_unlock(&newnp->n_mtx); } if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 && - vattr.va_ctime.tv_sec == newnp->n_ctime) { + timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==)) { nfsstats.lookupcache_hits++; if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN)) @@ -997,13 +995,13 @@ nfs_lookup(struct vop_lookup_args *ap) if ((u_int)(ticks - np->n_dmtime_ticks) < (nmp->nm_negnametimeo * hz) && VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 && - vattr.va_mtime.tv_sec == np->n_dmtime) { + timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) { nfsstats.lookupcache_hits++; return (ENOENT); } cache_purge_negative(dvp); mtx_lock(&np->n_mtx); - np->n_dmtime = 0; + timespecclear(&np->n_dmtime); mtx_unlock(&np->n_mtx); } @@ -1018,7 +1016,7 @@ nfs_lookup(struct vop_lookup_args *ap) * the lookup RPC has been performed on the server but before * n_dmtime is set at the end of this function. */ - dmtime = np->n_vattr.va_mtime.tv_sec; + dmtime = np->n_vattr.va_mtime; error = 0; newvp = NULLVP; nfsstats.lookupcache_misses++; @@ -1137,7 +1135,7 @@ nfs_lookup(struct vop_lookup_args *ap) cnp->cn_flags |= SAVENAME; if ((cnp->cn_flags & MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) { - np->n_ctime = np->n_vattr.va_ctime.tv_sec; + np->n_ctime = np->n_vattr.va_ctime; cache_enter(dvp, newvp, cnp); } *vpp = newvp; @@ -1183,8 +1181,8 @@ nfsmout: * lookup. */ mtx_lock(&np->n_mtx); - if (np->n_dmtime <= dmtime) { - if (np->n_dmtime == 0) { + if (timespeccmp(&np->n_dmtime, &dmtime, <=)) { + if (!timespecisset(&np->n_dmtime)) { np->n_dmtime = dmtime; np->n_dmtime_ticks = ticks; } @@ -2657,8 +2655,11 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred) dp->d_type = IFTODT(VTTOIF(np->n_vattr.va_type)); ndp->ni_vp = newvp; - /* Update n_ctime, so subsequent lookup doesn't purge entry */ - np->n_ctime = np->n_vattr.va_ctime.tv_sec; + /* + * Update n_ctime so subsequent lookup + * doesn't purge entry. + */ + np->n_ctime = np->n_vattr.va_ctime; cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp); } } else { diff --git a/sys/nfsclient/nfsmount.h b/sys/nfsclient/nfsmount.h index d47957c0066..515c64e8614 100644 --- a/sys/nfsclient/nfsmount.h +++ b/sys/nfsclient/nfsmount.h @@ -36,6 +36,10 @@ #ifndef _NFSCLIENT_NFSMOUNT_H_ #define _NFSCLIENT_NFSMOUNT_H_ +#include + +#include + #include #include #include @@ -47,10 +51,7 @@ * Holds NFS specific information for mount. */ struct nfsmount { - struct mtx nm_mtx; - int nm_flag; /* Flags for soft/hard... */ - int nm_state; /* Internal state flags */ - struct mount *nm_mountp; /* Vfs structure for this filesystem */ + struct nfsmount_common nm_com; /* Common fields for nlm */ int nm_numgrps; /* Max. size of groupslist */ u_char nm_fh[NFSX_V4FH]; /* File handle of root dir */ int nm_fhsize; /* Size of root file handle */ @@ -58,8 +59,6 @@ struct nfsmount { int nm_soproto; /* and protocol */ int nm_soflags; /* pr_flags for socket protocol */ struct sockaddr *nm_nam; /* Addr of server */ - int nm_timeo; /* Init timer for NFSMNT_DUMBTIMR */ - int nm_retry; /* Max retries */ int nm_deadthresh; /* Threshold of timeouts-->dead server*/ int nm_rsize; /* Max size of read rpc */ int nm_wsize; /* Max size of write rpc */ @@ -79,7 +78,6 @@ struct nfsmount { struct nfs_rpcops *nm_rpcops; int nm_tprintf_initial_delay; /* initial delay */ int nm_tprintf_delay; /* interval for messages */ - char nm_hostname[MNAMELEN]; /* server's name */ int nm_secflavor; /* auth flavor to use for rpc */ struct __rpc_client *nm_client; struct rpc_timers nm_timers[NFS_MAX_TIMER]; /* RTT Timers for rpcs */ @@ -94,6 +92,15 @@ struct nfsmount { time_t nm_last_renewal; }; +#define nm_mtx nm_com.nmcom_mtx +#define nm_flag nm_com.nmcom_flag +#define nm_state nm_com.nmcom_state +#define nm_mountp nm_com.nmcom_mountp +#define nm_timeo nm_com.nmcom_timeo +#define nm_retry nm_com.nmcom_retry +#define nm_hostname nm_com.nmcom_hostname +#define nm_getinfo nm_com.nmcom_getinfo + #if defined(_KERNEL) /* * Convert mount ptr to nfsmount ptr. diff --git a/sys/nfsclient/nfsnode.h b/sys/nfsclient/nfsnode.h index a7adeae05ff..19c1c474ecc 100644 --- a/sys/nfsclient/nfsnode.h +++ b/sys/nfsclient/nfsnode.h @@ -102,10 +102,9 @@ struct nfsnode { time_t n_attrstamp; /* Attr. cache timestamp */ struct nfs_accesscache n_accesscache[NFS_ACCESSCACHESIZE]; struct timespec n_mtime; /* Prev modify time. */ - time_t n_ctime; /* Prev create time. */ - time_t n_dmtime; /* Prev dir modify time. */ + struct timespec n_ctime; /* Prev create time. */ + struct timespec n_dmtime; /* Prev dir modify time. */ int n_dmtime_ticks; /* Tick of -ve cache entry */ - time_t n_expiry; /* Lease expiry time */ nfsfh_t *n_fhp; /* NFS File Handle */ struct vnode *n_vnode; /* associated vnode */ struct vnode *n_dvp; /* parent vnode */ @@ -166,16 +165,13 @@ struct nfsnode { #define NFS_TIMESPEC_COMPARE(T1, T2) (((T1)->tv_sec != (T2)->tv_sec) || ((T1)->tv_nsec != (T2)->tv_nsec)) /* - * NFS iod threads can be in one of these three states once spawned. + * NFS iod threads can be in one of these two states once spawned. * NFSIOD_NOT_AVAILABLE - Cannot be assigned an I/O operation at this time. * NFSIOD_AVAILABLE - Available to be assigned an I/O operation. - * NFSIOD_CREATED_FOR_NFS_ASYNCIO - Newly created for nfs_asyncio() and - * will be used by the thread that called nfs_asyncio(). */ enum nfsiod_state { NFSIOD_NOT_AVAILABLE = 0, NFSIOD_AVAILABLE = 1, - NFSIOD_CREATED_FOR_NFS_ASYNCIO = 2, }; /* @@ -191,9 +187,6 @@ extern struct vop_vector nfs_fifoops; extern struct vop_vector nfs_vnodeops; extern struct buf_ops buf_ops_nfs; -extern vop_advlock_t *nfs_advlock_p; -extern vop_reclaim_t *nfs_reclaim_p; - /* * Prototypes for NFS vnode operations */ diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index d1be5e55333..4a3876fe68b 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -3036,12 +3036,13 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct iovec iv; struct vattr va, at, *vap = &va; struct nfs_fattr *fp; - int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1; + int len, nlen, rem, xfer, tsiz, i, error = 0, error1, getret = 1; int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies; u_quad_t off, toff, verf; u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ int v3 = (nfsd->nd_flag & ND_NFSV3); - int vfslocked; + int usevget = 1, vfslocked; + struct componentname cn; nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); vfslocked = 0; @@ -3186,28 +3187,6 @@ again: goto again; } - /* - * Probe one of the directory entries to see if the filesystem - * supports VGET. - */ - error = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp); - if (error) { - if (error == EOPNOTSUPP) - error = NFSERR_NOTSUPP; - else - error = NFSERR_SERVERFAULT; - vrele(vp); - vp = NULL; - free((caddr_t)cookies, M_TEMP); - free((caddr_t)rbuf, M_TEMP); - nfsm_reply(NFSX_V3POSTOPATTR); - nfsm_srvpostop_attr(getret, &at); - error = 0; - goto nfsmout; - } - vput(nvp); - nvp = NULL; - dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; nfsm_reply(cnt); @@ -3224,35 +3203,62 @@ again: nlen = dp->d_namlen; rem = nfsm_rndup(nlen)-nlen; - /* - * For readdir_and_lookup get the vnode using - * the file number. - */ - if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, - &nvp)) - goto invalid; + if (usevget) { + /* + * For readdir_and_lookup get the vnode using + * the file number. + */ + error = VFS_VGET(vp->v_mount, dp->d_fileno, + LK_SHARED, &nvp); + if (error != 0 && error != EOPNOTSUPP) { + error = 0; + goto invalid; + } else if (error == EOPNOTSUPP) { + /* + * VFS_VGET() not supported? + * Let's switch to VOP_LOOKUP(). + */ + error = 0; + usevget = 0; + cn.cn_nameiop = LOOKUP; + cn.cn_flags = ISLASTCN | NOFOLLOW | \ + LOCKSHARED | LOCKLEAF | MPSAFE; + cn.cn_lkflags = LK_SHARED | LK_RETRY; + cn.cn_cred = cred; + cn.cn_thread = curthread; + } + } + if (!usevget) { + cn.cn_nameptr = dp->d_name; + cn.cn_namelen = dp->d_namlen; + if (dp->d_namlen == 2 && + dp->d_name[0] == '.' && + dp->d_name[1] == '.') { + cn.cn_flags |= ISDOTDOT; + } else { + cn.cn_flags &= ~ISDOTDOT; + } + if (!VOP_ISLOCKED(vp)) + vn_lock(vp, LK_SHARED | LK_RETRY); + if ((vp->v_vflag & VV_ROOT) != 0 && + (cn.cn_flags & ISDOTDOT) != 0) { + vref(vp); + nvp = vp; + } else if (VOP_LOOKUP(vp, &nvp, &cn) != 0) + goto invalid; + } + bzero((caddr_t)nfhp, NFSX_V3FH); - nfhp->fh_fsid = - nvp->v_mount->mnt_stat.f_fsid; - /* - * XXXRW: Assert the mountpoints are the same so that - * we know that acquiring Giant based on the - * directory is the right thing for the child. - */ - KASSERT(nvp->v_mount == vp->v_mount, - ("nfsrv_readdirplus: nvp mount != vp mount")); - if (VOP_VPTOFH(nvp, &nfhp->fh_fid)) { + nfhp->fh_fsid = nvp->v_mount->mnt_stat.f_fsid; + if ((error1 = VOP_VPTOFH(nvp, &nfhp->fh_fid)) == 0) + error1 = VOP_GETATTR(nvp, vap, cred); + if (vp == nvp) + vunref(nvp); + else vput(nvp); - nvp = NULL; - goto invalid; - } - if (VOP_GETATTR(nvp, vap, cred)) { - vput(nvp); - nvp = NULL; - goto invalid; - } - vput(nvp); nvp = NULL; + if (error1 != 0) + goto invalid; /* * If either the dircount or maxcount will be @@ -3336,7 +3342,10 @@ invalid: cookiep++; ncookies--; } - vrele(vp); + if (!usevget && VOP_ISLOCKED(vp)) + vput(vp); + else + vrele(vp); vp = NULL; nfsm_clget; *tl = nfsrv_nfs_false; diff --git a/sys/nlm/nlm_advlock.c b/sys/nlm/nlm_advlock.c index b179595c5d0..b4edb4dd962 100644 --- a/sys/nlm/nlm_advlock.c +++ b/sys/nlm/nlm_advlock.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -196,7 +196,6 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl, { struct thread *td = curthread; struct nfsmount *nmp; - struct nfsnode *np; off_t size; size_t fhlen; union nfsfh fh; @@ -214,6 +213,7 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl, struct nlm_file_svid *ns; int svid; int error; + int is_v3; ASSERT_VOP_LOCKED(vp, "nlm_advlock_1"); @@ -225,18 +225,13 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl, if (op == F_SETLK || op == F_UNLCK) nfs_vinvalbuf(vp, V_SAVE, td, 1); - np = VTONFS(vp); nmp = VFSTONFS(vp->v_mount); - size = np->n_size; - sa = nmp->nm_nam; - memcpy(&ss, sa, sa->sa_len); - sa = (struct sockaddr *) &ss; strcpy(servername, nmp->nm_hostname); - fhlen = np->n_fhsize; - memcpy(&fh.fh_bytes, np->n_fhp, fhlen); + nmp->nm_getinfo(vp, fh.fh_bytes, &fhlen, &ss, &is_v3, &size); + sa = (struct sockaddr *) &ss; timo.tv_sec = nmp->nm_timeo / NFS_HZ; timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * (1000000 / NFS_HZ); - if (NFS_ISV3(vp)) + if (is_v3 != 0) vers = NLM_VERS4; else vers = NLM_VERS; diff --git a/sys/nlm/nlm_prot_impl.c b/sys/nlm/nlm_prot_impl.c index f6b296d6f3c..ea4baca2722 100644 --- a/sys/nlm/nlm_prot_impl.c +++ b/sys/nlm/nlm_prot_impl.c @@ -55,8 +55,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include @@ -1055,13 +1054,13 @@ nlm_find_host_by_addr(const struct sockaddr *addr, int vers) switch (addr->sa_family) { case AF_INET: - __rpc_inet_ntop(AF_INET, + inet_ntop(AF_INET, &((const struct sockaddr_in *) addr)->sin_addr, tmp, sizeof tmp); break; #ifdef INET6 case AF_INET6: - __rpc_inet_ntop(AF_INET6, + inet_ntop(AF_INET6, &((const struct sockaddr_in6 *) addr)->sin6_addr, tmp, sizeof tmp); break; @@ -2432,4 +2431,5 @@ DECLARE_MODULE(nfslockd, nfslockd_mod, SI_SUB_VFS, SI_ORDER_ANY); /* So that loader and kldload(2) can find us, wherever we are.. */ MODULE_DEPEND(nfslockd, krpc, 1, 1, 1); MODULE_DEPEND(nfslockd, nfs, 1, 1, 1); +MODULE_DEPEND(nfslockd, nfslock, 1, 1, 1); MODULE_VERSION(nfslockd, 1); diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index 8edbc8e1327..6a10f9a2f49 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -419,6 +419,9 @@ cryptof_ioctl( case CRYPTO_AES_CBC: txform = &enc_xform_rijndael128; break; + case CRYPTO_AES_XTS: + txform = &enc_xform_aes_xts; + break; case CRYPTO_NULL_CBC: txform = &enc_xform_null; break; diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index afd79c84e73..e2995221333 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -123,7 +123,8 @@ #define CRYPTO_SHA2_384_HMAC 19 #define CRYPTO_SHA2_512_HMAC 20 #define CRYPTO_CAMELLIA_CBC 21 -#define CRYPTO_ALGORITHM_MAX 21 /* Keep updated - see below */ +#define CRYPTO_AES_XTS 22 +#define CRYPTO_ALGORITHM_MAX 22 /* Keep updated - see below */ /* Algorithm flags */ #define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index a404cbc75a2..e05b015c218 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -114,8 +114,16 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, if (error) return (error); } + ivp = iv; + /* + * xforms that provide a reinit method perform all IV + * handling themselves. + */ + if (exf->reinit) + exf->reinit(sw->sw_kschedule, iv); + if (flags & CRYPTO_F_IMBUF) { struct mbuf *m = (struct mbuf *) buf; @@ -135,7 +143,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, m_copydata(m, k, blks, blk); /* Actual encryption/decryption */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + blk); + } else { + exf->decrypt(sw->sw_kschedule, + blk); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block */ for (j = 0; j < blks; j++) blk[j] ^= ivp[j]; @@ -205,7 +221,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, idat = mtod(m, unsigned char *) + k; while (m->m_len >= k + blks && i > 0) { - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + idat); + } else { + exf->decrypt(sw->sw_kschedule, + idat); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block/IV */ for (j = 0; j < blks; j++) idat[j] ^= ivp[j]; @@ -261,7 +285,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, cuio_copydata(uio, k, blks, blk); /* Actual encryption/decryption */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + blk); + } else { + exf->decrypt(sw->sw_kschedule, + blk); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block */ for (j = 0; j < blks; j++) blk[j] ^= ivp[j]; @@ -319,7 +351,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, idat = (char *)iov->iov_base + k; while (iov->iov_len >= k + blks && i > 0) { - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + idat); + } else { + exf->decrypt(sw->sw_kschedule, + idat); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block/IV */ for (j = 0; j < blks; j++) idat[j] ^= ivp[j]; @@ -360,7 +400,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, return 0; /* Done with iovec encryption/decryption */ } else { /* contiguous buffer */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + for (i = crd->crd_skip; + i < crd->crd_skip + crd->crd_len; i += blks) { + if (crd->crd_flags & CRD_F_ENCRYPT) + exf->encrypt(sw->sw_kschedule, buf + i); + else + exf->decrypt(sw->sw_kschedule, buf + i); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { for (i = crd->crd_skip; i < crd->crd_skip + crd->crd_len; i += blks) { /* XOR with the IV/previous block, as appropriate. */ @@ -687,6 +735,9 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) case CRYPTO_RIJNDAEL128_CBC: txf = &enc_xform_rijndael128; goto enccommon; + case CRYPTO_AES_XTS: + txf = &enc_xform_aes_xts; + goto enccommon; case CRYPTO_CAMELLIA_CBC: txf = &enc_xform_camellia; goto enccommon; @@ -845,6 +896,7 @@ swcr_freesession(device_t dev, u_int64_t tid) case CRYPTO_CAST_CBC: case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: + case CRYPTO_AES_XTS: case CRYPTO_CAMELLIA_CBC: case CRYPTO_NULL_CBC: txf = swd->sw_exf; @@ -958,6 +1010,7 @@ swcr_process(device_t dev, struct cryptop *crp, int hint) case CRYPTO_CAST_CBC: case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: + case CRYPTO_AES_XTS: case CRYPTO_CAMELLIA_CBC: if ((crp->crp_etype = swcr_encdec(crd, sw, crp->crp_buf, crp->crp_flags)) != 0) @@ -1050,6 +1103,7 @@ swcr_attach(device_t dev) REGISTER(CRYPTO_MD5); REGISTER(CRYPTO_SHA1); REGISTER(CRYPTO_RIJNDAEL128_CBC); + REGISTER(CRYPTO_AES_XTS); REGISTER(CRYPTO_CAMELLIA_CBC); REGISTER(CRYPTO_DEFLATE_COMP); #undef REGISTER diff --git a/sys/opencrypto/deflate.c b/sys/opencrypto/deflate.c index 2113611ae0d..deaf0527344 100644 --- a/sys/opencrypto/deflate.c +++ b/sys/opencrypto/deflate.c @@ -50,13 +50,13 @@ __FBSDID("$FreeBSD$"); #include SDT_PROVIDER_DECLARE(opencrypto); -SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry, +SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, entry, entry, "int", "u_int32_t"); -SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, bad, +SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, bad, bad, "int", "int", "int", "int", "int"); -SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, iter, +SDT_PROBE_DEFINE5(opencrypto, deflate, deflate_global, iter, iter, "int", "int", "int", "int", "int"); -SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return, +SDT_PROBE_DEFINE2(opencrypto, deflate, deflate_global, return, return, "int", "u_int32_t"); int window_inflate = -1 * MAX_WBITS; diff --git a/sys/opencrypto/xform.c b/sys/opencrypto/xform.c index 1de9a1780c2..26e383c0645 100644 --- a/sys/opencrypto/xform.c +++ b/sys/opencrypto/xform.c @@ -64,40 +64,48 @@ __FBSDID("$FreeBSD$"); #include #include -static void null_encrypt(caddr_t, u_int8_t *); -static void null_decrypt(caddr_t, u_int8_t *); -static int null_setkey(u_int8_t **, u_int8_t *, int); -static void null_zerokey(u_int8_t **); - +static int null_setkey(u_int8_t **, u_int8_t *, int); static int des1_setkey(u_int8_t **, u_int8_t *, int); static int des3_setkey(u_int8_t **, u_int8_t *, int); static int blf_setkey(u_int8_t **, u_int8_t *, int); static int cast5_setkey(u_int8_t **, u_int8_t *, int); static int skipjack_setkey(u_int8_t **, u_int8_t *, int); static int rijndael128_setkey(u_int8_t **, u_int8_t *, int); +static int aes_xts_setkey(u_int8_t **, u_int8_t *, int); static int cml_setkey(u_int8_t **, u_int8_t *, int); + +static void null_encrypt(caddr_t, u_int8_t *); static void des1_encrypt(caddr_t, u_int8_t *); static void des3_encrypt(caddr_t, u_int8_t *); static void blf_encrypt(caddr_t, u_int8_t *); static void cast5_encrypt(caddr_t, u_int8_t *); static void skipjack_encrypt(caddr_t, u_int8_t *); static void rijndael128_encrypt(caddr_t, u_int8_t *); +static void aes_xts_encrypt(caddr_t, u_int8_t *); static void cml_encrypt(caddr_t, u_int8_t *); + +static void null_decrypt(caddr_t, u_int8_t *); static void des1_decrypt(caddr_t, u_int8_t *); static void des3_decrypt(caddr_t, u_int8_t *); static void blf_decrypt(caddr_t, u_int8_t *); static void cast5_decrypt(caddr_t, u_int8_t *); static void skipjack_decrypt(caddr_t, u_int8_t *); static void rijndael128_decrypt(caddr_t, u_int8_t *); +static void aes_xts_decrypt(caddr_t, u_int8_t *); static void cml_decrypt(caddr_t, u_int8_t *); + +static void null_zerokey(u_int8_t **); static void des1_zerokey(u_int8_t **); static void des3_zerokey(u_int8_t **); static void blf_zerokey(u_int8_t **); static void cast5_zerokey(u_int8_t **); static void skipjack_zerokey(u_int8_t **); static void rijndael128_zerokey(u_int8_t **); +static void aes_xts_zerokey(u_int8_t **); static void cml_zerokey(u_int8_t **); +static void aes_xts_reinit(caddr_t, u_int8_t *); + static void null_init(void *); static int null_update(void *, u_int8_t *, u_int16_t); static void null_final(u_int8_t *, void *); @@ -124,6 +132,7 @@ struct enc_xform enc_xform_null = { null_decrypt, null_setkey, null_zerokey, + NULL }; struct enc_xform enc_xform_des = { @@ -133,6 +142,7 @@ struct enc_xform enc_xform_des = { des1_decrypt, des1_setkey, des1_zerokey, + NULL }; struct enc_xform enc_xform_3des = { @@ -141,7 +151,8 @@ struct enc_xform enc_xform_3des = { des3_encrypt, des3_decrypt, des3_setkey, - des3_zerokey + des3_zerokey, + NULL }; struct enc_xform enc_xform_blf = { @@ -150,7 +161,8 @@ struct enc_xform enc_xform_blf = { blf_encrypt, blf_decrypt, blf_setkey, - blf_zerokey + blf_zerokey, + NULL }; struct enc_xform enc_xform_cast5 = { @@ -159,7 +171,8 @@ struct enc_xform enc_xform_cast5 = { cast5_encrypt, cast5_decrypt, cast5_setkey, - cast5_zerokey + cast5_zerokey, + NULL }; struct enc_xform enc_xform_skipjack = { @@ -168,7 +181,8 @@ struct enc_xform enc_xform_skipjack = { skipjack_encrypt, skipjack_decrypt, skipjack_setkey, - skipjack_zerokey + skipjack_zerokey, + NULL }; struct enc_xform enc_xform_rijndael128 = { @@ -178,6 +192,17 @@ struct enc_xform enc_xform_rijndael128 = { rijndael128_decrypt, rijndael128_setkey, rijndael128_zerokey, + NULL +}; + +struct enc_xform enc_xform_aes_xts = { + CRYPTO_AES_XTS, "AES-XTS", + RIJNDAEL128_BLOCK_LEN, 32, 64, + aes_xts_encrypt, + aes_xts_decrypt, + aes_xts_setkey, + aes_xts_zerokey, + aes_xts_reinit }; struct enc_xform enc_xform_arc4 = { @@ -187,6 +212,7 @@ struct enc_xform enc_xform_arc4 = { NULL, NULL, NULL, + NULL }; struct enc_xform enc_xform_camellia = { @@ -196,6 +222,7 @@ struct enc_xform enc_xform_camellia = { cml_decrypt, cml_setkey, cml_zerokey, + NULL }; /* Authentication instances */ @@ -226,7 +253,7 @@ struct auth_hash auth_hash_hmac_ripemd_160 = { }; struct auth_hash auth_hash_key_md5 = { - CRYPTO_MD5_KPDK, "Keyed MD5", + CRYPTO_MD5_KPDK, "Keyed MD5", 0, MD5_KPDK_HASH_LEN, 0, sizeof(MD5_CTX), (void (*)(void *)) MD5Init, MD5Update_int, (void (*)(u_int8_t *, void *)) MD5Final @@ -547,6 +574,107 @@ rijndael128_zerokey(u_int8_t **sched) *sched = NULL; } +#define AES_XTS_BLOCKSIZE 16 +#define AES_XTS_IVSIZE 8 +#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ + +struct aes_xts_ctx { + rijndael_ctx key1; + rijndael_ctx key2; + u_int8_t tweak[AES_XTS_BLOCKSIZE]; +}; + +void +aes_xts_reinit(caddr_t key, u_int8_t *iv) +{ + struct aes_xts_ctx *ctx = (struct aes_xts_ctx *)key; + u_int64_t blocknum; + u_int i; + + /* + * Prepare tweak as E_k2(IV). IV is specified as LE representation + * of a 64-bit block number which we allow to be passed in directly. + */ + bcopy(iv, &blocknum, AES_XTS_IVSIZE); + for (i = 0; i < AES_XTS_IVSIZE; i++) { + ctx->tweak[i] = blocknum & 0xff; + blocknum >>= 8; + } + /* Last 64 bits of IV are always zero */ + bzero(ctx->tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE); + + rijndael_encrypt(&ctx->key2, ctx->tweak, ctx->tweak); +} + +static void +aes_xts_crypt(struct aes_xts_ctx *ctx, u_int8_t *data, u_int do_encrypt) +{ + u_int8_t block[AES_XTS_BLOCKSIZE]; + u_int i, carry_in, carry_out; + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + block[i] = data[i] ^ ctx->tweak[i]; + + if (do_encrypt) + rijndael_encrypt(&ctx->key1, block, data); + else + rijndael_decrypt(&ctx->key1, block, data); + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + data[i] ^= ctx->tweak[i]; + + /* Exponentiate tweak */ + carry_in = 0; + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) { + carry_out = ctx->tweak[i] & 0x80; + ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0); + carry_in = carry_out; + } + if (carry_in) + ctx->tweak[0] ^= AES_XTS_ALPHA; + bzero(block, sizeof(block)); +} + +void +aes_xts_encrypt(caddr_t key, u_int8_t *data) +{ + aes_xts_crypt((struct aes_xts_ctx *)key, data, 1); +} + +void +aes_xts_decrypt(caddr_t key, u_int8_t *data) +{ + aes_xts_crypt((struct aes_xts_ctx *)key, data, 0); +} + +int +aes_xts_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + struct aes_xts_ctx *ctx; + + if (len != 32 && len != 64) + return EINVAL; + + *sched = malloc(sizeof(struct aes_xts_ctx), M_CRYPTO_DATA, + M_NOWAIT | M_ZERO); + if (*sched == NULL) + return ENOMEM; + ctx = (struct aes_xts_ctx *)*sched; + + rijndael_set_key(&ctx->key1, key, len * 4); + rijndael_set_key(&ctx->key2, key + (len / 2), len * 4); + + return 0; +} + +void +aes_xts_zerokey(u_int8_t **sched) +{ + bzero(*sched, sizeof(struct aes_xts_ctx)); + free(*sched, M_CRYPTO_DATA); + *sched = NULL; +} + static void cml_encrypt(caddr_t key, u_int8_t *blk) { diff --git a/sys/opencrypto/xform.h b/sys/opencrypto/xform.h index de7528b8cd9..0a7f981d511 100644 --- a/sys/opencrypto/xform.h +++ b/sys/opencrypto/xform.h @@ -54,6 +54,7 @@ struct enc_xform { void (*decrypt) (caddr_t, u_int8_t *); int (*setkey) (u_int8_t **, u_int8_t *, int len); void (*zerokey) (u_int8_t **); + void (*reinit) (caddr_t, u_int8_t *); }; struct comp_algo { @@ -80,6 +81,7 @@ extern struct enc_xform enc_xform_blf; extern struct enc_xform enc_xform_cast5; extern struct enc_xform enc_xform_skipjack; extern struct enc_xform enc_xform_rijndael128; +extern struct enc_xform enc_xform_aes_xts; extern struct enc_xform enc_xform_arc4; extern struct enc_xform enc_xform_camellia; diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC index 77667161d38..e137297eb14 100644 --- a/sys/pc98/conf/GENERIC +++ b/sys/pc98/conf/GENERIC @@ -59,7 +59,6 @@ options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options KBD_INSTALL_CDEV # install a CDEV entry in /dev options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) diff --git a/sys/pc98/pc98/canbus.c b/sys/pc98/pc98/canbus.c index 522b4d0ba5c..ceb2d71fb60 100644 --- a/sys/pc98/pc98/canbus.c +++ b/sys/pc98/pc98/canbus.c @@ -82,7 +82,7 @@ static int canbus_detach(device_t); /* Bus interface methods */ static int canbus_print_child(device_t, device_t); -static device_t canbus_add_child(device_t, int, const char *, int); +static device_t canbus_add_child(device_t, u_int, const char *, int); static struct resource * canbus_alloc_resource( device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static int canbus_activate_resource( @@ -235,7 +235,7 @@ canbus_print_child(device_t dev, device_t child) } static device_t -canbus_add_child(device_t bus, int order, const char *name, int unit) +canbus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct canbus_device *cbdev; diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index 671ce5b3cf3..32328c5b9c5 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -1120,40 +1120,36 @@ cpu_halt(void) __asm__ ("hlt"); } +static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ +TUNABLE_INT("machdep.idle_mwait", &idle_mwait); +SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RW, &idle_mwait, + 0, "Use MONITOR/MWAIT for short idle"); + +#define STATE_RUNNING 0x0 +#define STATE_MWAIT 0x1 +#define STATE_SLEEPING 0x2 + static void cpu_idle_hlt(int busy) { + int *state; + + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_SLEEPING; /* - * we must absolutely guarentee that hlt is the next instruction + * We must absolutely guarentee that hlt is the next instruction * after sti or we introduce a timing window. */ disable_intr(); - if (sched_runnable()) + if (sched_runnable()) enable_intr(); else __asm __volatile("sti; hlt"); -} - -static void -cpu_idle_spin(int busy) -{ - return; -} - -void (*cpu_idle_fn)(int) = cpu_idle_hlt; - -void -cpu_idle(int busy) -{ -#if defined(SMP) - if (mp_grab_cpu_hlt()) - return; -#endif - cpu_idle_fn(busy); + *state = STATE_RUNNING; } /* - * mwait cpu power states. Lower 4 bits are sub-states. + * MWAIT cpu power states. Lower 4 bits are sub-states. */ #define MWAIT_C0 0xf0 #define MWAIT_C1 0x00 @@ -1161,63 +1157,91 @@ cpu_idle(int busy) #define MWAIT_C3 0x20 #define MWAIT_C4 0x30 -#define MWAIT_DISABLED 0x0 -#define MWAIT_WOKEN 0x1 -#define MWAIT_WAITING 0x2 - static void cpu_idle_mwait(int busy) { - int *mwait; + int *state; - mwait = (int *)PCPU_PTR(monitorbuf); - *mwait = MWAIT_WAITING; - if (sched_runnable()) - return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_MWAIT; + if (!sched_runnable()) { + cpu_monitor(state, 0, 0); + if (*state == STATE_MWAIT) + cpu_mwait(0, MWAIT_C1); + } + *state = STATE_RUNNING; } static void -cpu_idle_mwait_hlt(int busy) +cpu_idle_spin(int busy) { - int *mwait; + int *state; + int i; - mwait = (int *)PCPU_PTR(monitorbuf); - if (busy == 0) { - *mwait = MWAIT_DISABLED; - cpu_idle_hlt(busy); - return; + state = (int *)PCPU_PTR(monitorbuf); + *state = STATE_RUNNING; + for (i = 0; i < 1000; i++) { + if (sched_runnable()) + return; + cpu_spinwait(); } - *mwait = MWAIT_WAITING; - if (sched_runnable()) +} + +void (*cpu_idle_fn)(int) = cpu_idle_hlt; + +void +cpu_idle(int busy) +{ + + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", + busy, curcpu); +#ifdef SMP + if (mp_grab_cpu_hlt()) return; - cpu_monitor(mwait, 0, 0); - if (*mwait == MWAIT_WAITING) - cpu_mwait(0, MWAIT_C1); +#endif + /* If we are busy - try to use fast methods. */ + if (busy) { + if ((cpu_feature2 & CPUID2_MON) && idle_mwait) { + cpu_idle_mwait(busy); + goto out; + } + } + + /* If we have time - switch timers into idle mode. */ + if (!busy) { + critical_enter(); + cpu_idleclock(); + } + + /* Call main idle method. */ + cpu_idle_fn(busy); + + /* Switch timers mack into active mode. */ + if (!busy) { + cpu_activeclock(); + critical_exit(); + } +out: + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", + busy, curcpu); } int cpu_idle_wakeup(int cpu) { struct pcpu *pcpu; - int *mwait; + int *state; - if (cpu_idle_fn == cpu_idle_spin) - return (1); - if (cpu_idle_fn != cpu_idle_mwait && cpu_idle_fn != cpu_idle_mwait_hlt) - return (0); pcpu = pcpu_find(cpu); - mwait = (int *)pcpu->pc_monitorbuf; + state = (int *)pcpu->pc_monitorbuf; /* * This doesn't need to be atomic since missing the race will * simply result in unnecessary IPIs. */ - if (cpu_idle_fn == cpu_idle_mwait_hlt && *mwait == MWAIT_DISABLED) + if (*state == STATE_SLEEPING) return (0); - *mwait = MWAIT_WOKEN; - + if (*state == STATE_MWAIT) + *state = STATE_RUNNING; return (1); } @@ -1230,7 +1254,6 @@ struct { } idle_tbl[] = { { cpu_idle_spin, "spin" }, { cpu_idle_mwait, "mwait" }, - { cpu_idle_mwait_hlt, "mwait_hlt" }, { cpu_idle_hlt, "hlt" }, { NULL, NULL } }; @@ -1248,13 +1271,17 @@ idle_sysctl_available(SYSCTL_HANDLER_ARGS) if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; - p += sprintf(p, "%s, ", idle_tbl[i].id_name); + p += sprintf(p, "%s%s", p != avail ? ", " : "", + idle_tbl[i].id_name); } error = sysctl_handle_string(oidp, avail, 0, req); free(avail, M_TEMP); return (error); } +SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, + 0, 0, idle_sysctl_available, "A", "list of available idle functions"); + static int idle_sysctl(SYSCTL_HANDLER_ARGS) { @@ -1286,9 +1313,6 @@ idle_sysctl(SYSCTL_HANDLER_ARGS) return (EINVAL); } -SYSCTL_PROC(_machdep, OID_AUTO, idle_available, CTLTYPE_STRING | CTLFLAG_RD, - 0, 0, idle_sysctl_available, "A", "list of available idle functions"); - SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0, idle_sysctl, "A", "currently selected idle function"); @@ -1752,52 +1776,13 @@ sdtossd(sd, ssd) ssd->ssd_gran = sd->sd_gran; } -/* - * Populate the (physmap) array with base/bound pairs describing the - * available physical memory in the system, then test this memory and - * build the phys_avail array describing the actually-available memory. - * - * If we cannot accurately determine the physical memory map, then use - * value from the 0xE801 call, and failing that, the RTC. - * - * Total memory size may be set by the kernel environment variable - * hw.physmem or the compile-time define MAXMEM. - * - * XXX first should be vm_paddr_t. - */ static void -getmemsize(int first) +basemem_setup(void) { - int i, off, physmap_idx, pa_indx, da_indx; - int pg_n; - u_long physmem_tunable; - u_int extmem; - u_int under16; - vm_paddr_t pa, physmap[PHYSMAP_SIZE]; + vm_paddr_t pa; pt_entry_t *pte; - quad_t dcons_addr, dcons_size; + int i; - bzero(physmap, sizeof(physmap)); - - /* XXX - some of EPSON machines can't use PG_N */ - pg_n = PG_N; - if (pc98_machine_type & M_EPSON_PC98) { - switch (epson_machine_id) { -#ifdef WB_CACHE - default: -#endif - case EPSON_PC486_HX: - case EPSON_PC486_HG: - case EPSON_PC486_HA: - pg_n = 0; - break; - } - } - - /* - * Perform "base memory" related probes & setup - */ - under16 = pc98_getmemsize(&basemem, &extmem); if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); @@ -1829,12 +1814,62 @@ getmemsize(int first) pmap_kenter(KERNBASE + pa, pa); /* - * if basemem != 640, map pages r/w into vm86 page table so - * that the bios can scribble on it. + * Map pages between basemem and ISA_HOLE_START, if any, r/w into + * the vm86 page table so that vm86 can scribble on them using + * the vm86 map too. XXX: why 2 ways for this and only 1 way for + * page 0, at least as initialized here? */ pte = (pt_entry_t *)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; +} + +/* + * Populate the (physmap) array with base/bound pairs describing the + * available physical memory in the system, then test this memory and + * build the phys_avail array describing the actually-available memory. + * + * If we cannot accurately determine the physical memory map, then use + * value from the 0xE801 call, and failing that, the RTC. + * + * Total memory size may be set by the kernel environment variable + * hw.physmem or the compile-time define MAXMEM. + * + * XXX first should be vm_paddr_t. + */ +static void +getmemsize(int first) +{ + int off, physmap_idx, pa_indx, da_indx; + u_long physmem_tunable; + vm_paddr_t physmap[PHYSMAP_SIZE]; + pt_entry_t *pte; + quad_t dcons_addr, dcons_size; + int i; + int pg_n; + u_int extmem; + u_int under16; + vm_paddr_t pa; + + bzero(physmap, sizeof(physmap)); + + /* XXX - some of EPSON machines can't use PG_N */ + pg_n = PG_N; + if (pc98_machine_type & M_EPSON_PC98) { + switch (epson_machine_id) { +#ifdef WB_CACHE + default: +#endif + case EPSON_PC486_HX: + case EPSON_PC486_HG: + case EPSON_PC486_HA: + pg_n = 0; + break; + } + } + + under16 = pc98_getmemsize(&basemem, &extmem); + basemem_setup(); physmap[0] = 0; physmap[1] = basemem * 1024; diff --git a/sys/pci/if_rl.c b/sys/pci/if_rl.c index ad7bbdc6703..f2170099cbc 100644 --- a/sys/pci/if_rl.c +++ b/sys/pci/if_rl.c @@ -125,16 +125,6 @@ MODULE_DEPEND(rl, miibus, 1, 1, 1); /* "device miibus" required. See GENERIC if you get errors here. */ #include "miibus_if.h" -/* - * Default to using PIO access for this driver. On SMP systems, - * there appear to be problems with memory mapped mode: it looks like - * doing too many memory mapped access back to back in rapid succession - * can hang the bus. I'm inclined to blame this on crummy design/construction - * on the part of RealTek. Memory mapped mode does appear to work on - * uniprocessor systems though. - */ -#define RL_USEIOSPACE - #include /* @@ -213,7 +203,7 @@ static void rl_read_eeprom(struct rl_softc *, uint8_t *, int, int, int); static void rl_reset(struct rl_softc *); static int rl_resume(device_t); static int rl_rxeof(struct rl_softc *); -static void rl_setmulti(struct rl_softc *); +static void rl_rxfilter(struct rl_softc *); static int rl_shutdown(device_t); static void rl_start(struct ifnet *); static void rl_start_locked(struct ifnet *); @@ -225,14 +215,6 @@ static void rl_watchdog(struct rl_softc *); static void rl_setwol(struct rl_softc *); static void rl_clrwol(struct rl_softc *); -#ifdef RL_USEIOSPACE -#define RL_RES SYS_RES_IOPORT -#define RL_RID RL_PCI_LOIO -#else -#define RL_RES SYS_RES_MEMORY -#define RL_RID RL_PCI_LOMEM -#endif - static device_method_t rl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rl_probe), @@ -537,10 +519,6 @@ rl_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); if (sc->rl_type == RL_8139) { - /* Pretend the internal PHY is only at address 0 */ - if (phy) { - return (0); - } switch (reg) { case MII_BMCR: rl8139_reg = RL_BMCR; @@ -595,10 +573,6 @@ rl_miibus_writereg(device_t dev, int phy, int reg, int data) sc = device_get_softc(dev); if (sc->rl_type == RL_8139) { - /* Pretend the internal PHY is only at address 0 */ - if (phy) { - return (0); - } switch (reg) { case MII_BMCR: rl8139_reg = RL_BMCR; @@ -673,54 +647,51 @@ rl_miibus_statchg(device_t dev) * Program the 64-bit multicast hash filter. */ static void -rl_setmulti(struct rl_softc *sc) +rl_rxfilter(struct rl_softc *sc) { struct ifnet *ifp = sc->rl_ifp; int h = 0; uint32_t hashes[2] = { 0, 0 }; struct ifmultiaddr *ifma; uint32_t rxfilt; - int mcnt = 0; RL_LOCK_ASSERT(sc); rxfilt = CSR_READ_4(sc, RL_RXCFG); - + rxfilt &= ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_BROAD | + RL_RXCFG_RX_MULTI); + /* Always accept frames destined for this host. */ + rxfilt |= RL_RXCFG_RX_INDIV; + /* Set capture broadcast bit to capture broadcast frames. */ + if (ifp->if_flags & IFF_BROADCAST) + rxfilt |= RL_RXCFG_RX_BROAD; if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { rxfilt |= RL_RXCFG_RX_MULTI; - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); - CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF); - CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF); - return; + if (ifp->if_flags & IFF_PROMISC) + rxfilt |= RL_RXCFG_RX_ALLPHYS; + hashes[0] = 0xFFFFFFFF; + hashes[1] = 0xFFFFFFFF; + } else { + /* Now program new ones. */ + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = ether_crc32_be(LLADDR((struct sockaddr_dl *) + ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + } + if_maddr_runlock(ifp); + if (hashes[0] != 0 || hashes[1] != 0) + rxfilt |= RL_RXCFG_RX_MULTI; } - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, RL_MAR0, 0); - CSR_WRITE_4(sc, RL_MAR4, 0); - - /* now program new ones */ - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - if_maddr_runlock(ifp); - - if (mcnt) - rxfilt |= RL_RXCFG_RX_MULTI; - else - rxfilt &= ~RL_RXCFG_RX_MULTI; - - CSR_WRITE_4(sc, RL_RXCFG, rxfilt); CSR_WRITE_4(sc, RL_MAR0, hashes[0]); CSR_WRITE_4(sc, RL_MAR4, hashes[1]); + CSR_WRITE_4(sc, RL_RXCFG, rxfilt); } static void @@ -805,8 +776,8 @@ rl_attach(device_t dev) struct rl_type *t; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *children; - int error = 0, hwrev, i, pmc, rid; - int unit; + int error = 0, hwrev, i, phy, pmc, rid; + int prefer_iomap, unit; uint16_t rl_did = 0; char tn[32]; @@ -828,10 +799,31 @@ rl_attach(device_t dev) pci_enable_busmaster(dev); - /* Map control/status registers. */ - rid = RL_RID; - sc->rl_res = bus_alloc_resource_any(dev, RL_RES, &rid, RF_ACTIVE); + /* + * Map control/status registers. + * Default to using PIO access for this driver. On SMP systems, + * there appear to be problems with memory mapped mode: it looks + * like doing too many memory mapped access back to back in rapid + * succession can hang the bus. I'm inclined to blame this on + * crummy design/construction on the part of RealTek. Memory + * mapped mode does appear to work on uniprocessor systems though. + */ + prefer_iomap = 1; + snprintf(tn, sizeof(tn), "dev.rl.%d.prefer_iomap", unit); + TUNABLE_INT_FETCH(tn, &prefer_iomap); + if (prefer_iomap) { + sc->rl_res_id = PCIR_BAR(0); + sc->rl_res_type = SYS_RES_IOPORT; + sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type, + &sc->rl_res_id, RF_ACTIVE); + } + if (prefer_iomap == 0 || sc->rl_res == NULL) { + sc->rl_res_id = PCIR_BAR(1); + sc->rl_res_type = SYS_RES_MEMORY; + sc->rl_res = bus_alloc_resource_any(dev, sc->rl_res_type, + &sc->rl_res_id, RF_ACTIVE); + } if (sc->rl_res == NULL) { device_printf(dev, "couldn't map ports/memory\n"); error = ENXIO; @@ -924,11 +916,16 @@ rl_attach(device_t dev) goto fail; } +#define RL_PHYAD_INTERNAL 0 + /* Do MII setup */ - if (mii_phy_probe(dev, &sc->rl_miibus, - rl_ifmedia_upd, rl_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + phy = MII_PHY_ANY; + if (sc->rl_type == RL_8139) + phy = RL_PHYAD_INTERNAL; + error = mii_attach(dev, &sc->rl_miibus, ifp, rl_ifmedia_upd, + rl_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); goto fail; } @@ -1029,7 +1026,8 @@ rl_detach(device_t dev) if (sc->rl_irq[0]) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->rl_irq[0]); if (sc->rl_res) - bus_release_resource(dev, RL_RES, RL_RID, sc->rl_res); + bus_release_resource(dev, sc->rl_res_type, sc->rl_res_id, + sc->rl_res); if (ifp) if_free(ifp); @@ -1298,6 +1296,7 @@ rl_rxeof(struct rl_softc *sc) total_len < ETHER_MIN_LEN || total_len > ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) { ifp->if_ierrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; rl_init_locked(sc); return (rx_npkts); } @@ -1409,6 +1408,7 @@ rl_txeof(struct rl_softc *sc) CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); oldthresh = sc->rl_txthresh; /* error recovery */ + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; rl_init_locked(sc); /* restore original threshold */ sc->rl_txthresh = oldthresh; @@ -1602,8 +1602,10 @@ rl_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count) /* XXX We should check behaviour on receiver stalls. */ - if (status & RL_ISR_SYSTEM_ERR) + if (status & RL_ISR_SYSTEM_ERR) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; rl_init_locked(sc); + } } return (rx_npkts); } @@ -1615,6 +1617,7 @@ rl_intr(void *arg) struct rl_softc *sc = arg; struct ifnet *ifp = sc->rl_ifp; uint16_t status; + int count; RL_LOCK(sc); @@ -1626,28 +1629,41 @@ rl_intr(void *arg) goto done_locked; #endif - for (;;) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + goto done_locked2; + status = CSR_READ_2(sc, RL_ISR); + if (status == 0xffff || (status & RL_INTRS) == 0) + goto done_locked; + /* + * Ours, disable further interrupts. + */ + CSR_WRITE_2(sc, RL_IMR, 0); + for (count = 16; count > 0; count--) { + CSR_WRITE_2(sc, RL_ISR, status); + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if (status & (RL_ISR_RX_OK | RL_ISR_RX_ERR)) + rl_rxeof(sc); + if (status & (RL_ISR_TX_OK | RL_ISR_TX_ERR)) + rl_txeof(sc); + if (status & RL_ISR_SYSTEM_ERR) { + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + rl_init_locked(sc); + RL_UNLOCK(sc); + return; + } + } status = CSR_READ_2(sc, RL_ISR); /* If the card has gone away, the read returns 0xffff. */ - if (status == 0xffff) + if (status == 0xffff || (status & RL_INTRS) == 0) break; - if (status != 0) - CSR_WRITE_2(sc, RL_ISR, status); - if ((status & RL_INTRS) == 0) - break; - if (status & RL_ISR_RX_OK) - rl_rxeof(sc); - if (status & RL_ISR_RX_ERR) - rl_rxeof(sc); - if ((status & RL_ISR_TX_OK) || (status & RL_ISR_TX_ERR)) - rl_txeof(sc); - if (status & RL_ISR_SYSTEM_ERR) - rl_init_locked(sc); } if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) rl_start_locked(ifp); +done_locked2: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + CSR_WRITE_2(sc, RL_IMR, RL_INTRS); done_locked: RL_UNLOCK(sc); } @@ -1797,13 +1813,15 @@ rl_init_locked(struct rl_softc *sc) { struct ifnet *ifp = sc->rl_ifp; struct mii_data *mii; - uint32_t rxcfg = 0; uint32_t eaddr[2]; RL_LOCK_ASSERT(sc); mii = device_get_softc(sc->rl_miibus); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + /* * Cancel pending I/O and free all RX/TX buffers. */ @@ -1851,30 +1869,8 @@ rl_init_locked(struct rl_softc *sc) CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG); CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG); - /* Set the individual bit to receive frames for this host only. */ - rxcfg = CSR_READ_4(sc, RL_RXCFG); - rxcfg |= RL_RXCFG_RX_INDIV; - - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) { - rxcfg |= RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_ALLPHYS; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* Set capture broadcast bit to capture broadcast frames. */ - if (ifp->if_flags & IFF_BROADCAST) { - rxcfg |= RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } else { - rxcfg &= ~RL_RXCFG_RX_BROAD; - CSR_WRITE_4(sc, RL_RXCFG, rxcfg); - } - - /* Program the multicast filter, if necessary. */ - rl_setmulti(sc); + /* Set RX filter. */ + rl_rxfilter(sc); #ifdef DEVICE_POLLING /* Disable interrupts if we are polling. */ @@ -1953,20 +1949,22 @@ rl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) case SIOCSIFFLAGS: RL_LOCK(sc); if (ifp->if_flags & IFF_UP) { - rl_init_locked(sc); - } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - rl_stop(sc); - } + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + ((ifp->if_flags ^ sc->rl_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI))) + rl_rxfilter(sc); + else + rl_init_locked(sc); + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) + rl_stop(sc); + sc->rl_if_flags = ifp->if_flags; RL_UNLOCK(sc); - error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: RL_LOCK(sc); - rl_setmulti(sc); + rl_rxfilter(sc); RL_UNLOCK(sc); - error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: @@ -2032,6 +2030,7 @@ rl_watchdog(struct rl_softc *sc) rl_txeof(sc); rl_rxeof(sc); + sc->rl_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; rl_init_locked(sc); } diff --git a/sys/powerpc/aim/clock.c b/sys/powerpc/aim/clock.c index 92f0c66d306..eb3337cae9e 100644 --- a/sys/powerpc/aim/clock.c +++ b/sys/powerpc/aim/clock.c @@ -65,107 +65,195 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include +#include #include #include /* * Initially we assume a processor with a bus frequency of 12.5 MHz. */ -u_long ns_per_tick = 80; +static int initialized = 0; +static u_long ns_per_tick = 80; static u_long ticks_per_sec = 12500000; -static long ticks_per_intr; +static u_long *decr_counts[MAXCPU]; +static int decr_et_start(struct eventtimer *et, + struct bintime *first, struct bintime *period); +static int decr_et_stop(struct eventtimer *et); static timecounter_get_t decr_get_timecount; -static struct timecounter decr_timecounter = { +struct decr_state { + int mode; /* 0 - off, 1 - periodic, 2 - one-shot. */ + int32_t div; /* Periodic divisor. */ +}; +static DPCPU_DEFINE(struct decr_state, decr_state); + +static struct eventtimer decr_et; +static struct timecounter decr_tc = { decr_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency */ - "decrementer" /* name */ + "timebase" /* name */ }; +/* + * Decrementor interrupt handler. + */ void decr_intr(struct trapframe *frame) { - int32_t tick, nticks; + struct decr_state *s = DPCPU_PTR(decr_state); + int nticks = 0; + int32_t val; - /* - * Check whether we are initialized. - */ - if (!ticks_per_intr) + if (!initialized) return; - /* - * Based on the actual time delay since the last decrementer reload, - * we arrange for earlier interrupt next time. - */ - __asm ("mfdec %0" : "=r"(tick)); - for (nticks = 0; tick < 0; nticks++) - tick += ticks_per_intr; - mtdec(tick); + (*decr_counts[curcpu])++; + + if (s->mode == 1) { + /* + * Based on the actual time delay since the last decrementer + * reload, we arrange for earlier interrupt next time. + */ + __asm ("mfdec %0" : "=r"(val)); + while (val < 0) { + val += s->div; + nticks++; + } + mtdec(val); + } else if (s->mode == 2) { + nticks = 1; + decr_et_stop(NULL); + } while (nticks-- > 0) { - if (PCPU_GET(cpuid) == 0) - hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); - else - hardclock_cpu(TRAPF_USERMODE(frame)); - - statclock(TRAPF_USERMODE(frame)); - if (profprocs != 0) - profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + if (decr_et.et_active) + decr_et.et_event_cb(&decr_et, decr_et.et_arg); } } +/* + * BSP early initialization. + */ void decr_init(void) { struct cpuref cpu; - register_t msr; + char buf[32]; /* * Check the BSP's timebase frequency. Sometimes we can't find the BSP, so fall * back to the first CPU in this case. */ - if (platform_smp_get_bsp(&cpu) != 0) platform_smp_first_cpu(&cpu); - ticks_per_sec = platform_timebase_freq(&cpu); - - msr = mfmsr(); - mtmsr(msr & ~PSL_EE); - ns_per_tick = 1000000000 / ticks_per_sec; - ticks_per_intr = ticks_per_sec / hz; - mtdec(ticks_per_intr); set_cputicker(mftb, ticks_per_sec, 0); - - mtmsr(msr); + snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); + intrcnt_add(buf, &decr_counts[curcpu]); + decr_et_stop(NULL); + initialized = 1; } #ifdef SMP +/* + * AP early initialization. + */ void decr_ap_init(void) { + char buf[32]; + snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); + intrcnt_add(buf, &decr_counts[curcpu]); + decr_et_stop(NULL); } #endif +/* + * Final initialization. + */ void decr_tc_init(void) { - decr_timecounter.tc_frequency = ticks_per_sec; - tc_init(&decr_timecounter); + + decr_tc.tc_frequency = ticks_per_sec; + tc_init(&decr_tc); + decr_et.et_name = "decrementer"; + decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | + ET_FLAGS_PERCPU; + decr_et.et_quality = 1000; + decr_et.et_frequency = ticks_per_sec; + decr_et.et_min_period.sec = 0; + decr_et.et_min_period.frac = + ((0x00000002LLU << 32) / ticks_per_sec) << 32; + decr_et.et_max_period.sec = 0x7fffffffLLU / ticks_per_sec; + decr_et.et_max_period.frac = + ((0x7fffffffLLU << 32) / ticks_per_sec) << 32; + decr_et.et_start = decr_et_start; + decr_et.et_stop = decr_et_stop; + decr_et.et_priv = NULL; + et_register(&decr_et); } +/* + * Event timer start method. + */ +static int +decr_et_start(struct eventtimer *et, + struct bintime *first, struct bintime *period) +{ + struct decr_state *s = DPCPU_PTR(decr_state); + uint32_t fdiv; + + if (period != NULL) { + s->mode = 1; + s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32; + if (period->sec != 0) + s->div += decr_et.et_frequency * period->sec; + } else { + s->mode = 2; + s->div = 0x7fffffff; + } + if (first != NULL) { + fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32; + if (first->sec != 0) + fdiv += decr_et.et_frequency * first->sec; + } else + fdiv = s->div; + + mtdec(fdiv); + return (0); +} + +/* + * Event timer stop method. + */ +static int +decr_et_stop(struct eventtimer *et) +{ + struct decr_state *s = DPCPU_PTR(decr_state); + + s->mode = 0; + s->div = 0x7fffffff; + mtdec(s->div); + return (0); +} + +/* + * Timecounter get method. + */ static unsigned decr_get_timecount(struct timecounter *tc) { @@ -189,17 +277,3 @@ DELAY(int n) tb = mftb(); } -/* - * Nothing to do. - */ -void -cpu_startprofclock(void) -{ - - /* Do nothing */ -} - -void -cpu_stopprofclock(void) -{ -} diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c index 35d0ee4985a..ab2d1f32018 100644 --- a/sys/powerpc/aim/copyinout.c +++ b/sys/powerpc/aim/copyinout.c @@ -80,16 +80,28 @@ int setfault(faultbuf); /* defined in locore.S */ static __inline void set_user_sr(pmap_t pm, const void *addr) { + struct slb *slb; register_t esid, vsid, slb1, slb2; esid = USER_ADDR >> ADDR_SR_SHFT; - PMAP_LOCK(pm); - vsid = va_to_vsid(pm, (vm_offset_t)addr); - PMAP_UNLOCK(pm); + + /* Try lockless look-up first */ + slb = user_va_to_slb_entry(pm, (vm_offset_t)addr); + + if (slb == NULL) { + /* If it isn't there, we need to pre-fault the VSID */ + PMAP_LOCK(pm); + vsid = va_to_vsid(pm, (vm_offset_t)addr); + PMAP_UNLOCK(pm); + } else { + vsid = slb->slbv >> SLBV_VSID_SHIFT; + } slb1 = vsid << SLBV_VSID_SHIFT; slb2 = (esid << SLBE_ESID_SHIFT) | SLBE_VALID | USER_SR; + curthread->td_pcb->pcb_cpu.aim.usr_segm = + (uintptr_t)addr >> ADDR_SR_SHFT; __asm __volatile ("slbie %0; slbmte %1, %2" :: "r"(esid << 28), "r"(slb1), "r"(slb2)); isync(); diff --git a/sys/powerpc/aim/interrupt.c b/sys/powerpc/aim/interrupt.c index 5f92d243368..b06fb92e233 100644 --- a/sys/powerpc/aim/interrupt.c +++ b/sys/powerpc/aim/interrupt.c @@ -72,6 +72,7 @@ void powerpc_interrupt(struct trapframe *framep) { struct thread *td; + struct trapframe *oldframe; register_t ee; td = curthread; @@ -88,8 +89,11 @@ powerpc_interrupt(struct trapframe *framep) case EXC_DECR: critical_enter(); atomic_add_int(&td->td_intr_nesting_level, 1); + oldframe = td->td_intr_frame; + td->td_intr_frame = framep; decr_intr(framep); - atomic_subtract_int(&td->td_intr_nesting_level, 1); + td->td_intr_frame = oldframe; + atomic_subtract_int(&td->td_intr_nesting_level, 1); critical_exit(); break; diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index a2f13efd6ca..9dec1f75944 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -167,15 +167,6 @@ struct bat battable[16]; struct kva_md_info kmi; -static void -powerpc_ofw_shutdown(void *junk, int howto) -{ - if (howto & RB_HALT) { - OF_halt(); - } - OF_reboot(); -} - static void cpu_startup(void *dummy) { @@ -233,9 +224,6 @@ cpu_startup(void *dummy) */ bufinit(); vm_pager_bufferinit(); - - EVENTHANDLER_REGISTER(shutdown_final, powerpc_ofw_shutdown, 0, - SHUTDOWN_PRI_LAST); } extern char kernel_text[], _end[]; @@ -270,6 +258,7 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, char *env; register_t msr, scratch; uint8_t *cache_check; + int cacheline_warn; #ifndef __powerpc64__ int ppc64; #endif @@ -277,6 +266,7 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, end = 0; kmdp = NULL; trap_offset = 0; + cacheline_warn = 0; /* * Parse metadata if present and fetch parameters. Must be done @@ -372,7 +362,8 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, /* * Disable translation in case the vector area hasn't been - * mapped (G5). + * mapped (G5). Note that no OFW calls can be made until + * translation is re-enabled. */ msr = mfmsr(); @@ -399,7 +390,7 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, /* Work around psim bug */ if (cacheline_size == 0) { - printf("WARNING: cacheline size undetermined, setting to 32\n"); + cacheline_warn = 1; cacheline_size = 32; } @@ -498,8 +489,8 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, bcopy(generictrap, (void *)EXC_SC, (size_t)&trapsize); bcopy(generictrap, (void *)EXC_FPA, (size_t)&trapsize); bcopy(generictrap, (void *)EXC_VEC, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_VECAST, (size_t)&trapsize); - bcopy(generictrap, (void *)EXC_THRM, (size_t)&trapsize); + bcopy(generictrap, (void *)EXC_VECAST_G4, (size_t)&trapsize); + bcopy(generictrap, (void *)EXC_VECAST_G5, (size_t)&trapsize); __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD); /* @@ -508,6 +499,11 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, mtmsr(msr); isync(); + /* Warn if cachline size was not determined */ + if (cacheline_warn == 1) { + printf("WARNING: cacheline size undetermined, setting to 32\n"); + } + /* * Choose a platform module so we can get the physical memory map. */ @@ -621,8 +617,7 @@ cpu_initclocks(void) { decr_tc_init(); - stathz = hz; - profhz = hz; + cpu_initclocks_bsp(); } /* @@ -651,7 +646,13 @@ cpu_idle(int busy) panic("ints disabled in idleproc!"); } #endif + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", + busy, curcpu); if (powerpc_pow_enabled) { + if (!busy) { + critical_enter(); + cpu_idleclock(); + } switch (vers) { case IBM970: case IBM970FX: @@ -671,7 +672,13 @@ cpu_idle(int busy) isync(); break; } + if (!busy) { + cpu_activeclock(); + critical_exit(); + } } + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", + busy, curcpu); } int diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c index 2d090db5ea9..27d4ef3790c 100644 --- a/sys/powerpc/aim/mmu_oea.c +++ b/sys/powerpc/aim/mmu_oea.c @@ -203,6 +203,7 @@ extern struct pmap ofw_pmap; * Lock for the pteg and pvo tables. */ struct mtx moea_table_mutex; +struct mtx moea_vsid_mutex; /* tlbie instruction synchronization */ static struct mtx tlbie_mtx; @@ -220,8 +221,6 @@ u_int moea_pteg_mask; struct pvo_head *moea_pvo_table; /* pvo entries by pteg index */ struct pvo_head moea_pvo_kunmanaged = LIST_HEAD_INITIALIZER(moea_pvo_kunmanaged); /* list of unmanaged pages */ -struct pvo_head moea_pvo_unmanaged = - LIST_HEAD_INITIALIZER(moea_pvo_unmanaged); /* list of unmanaged pages */ uma_zone_t moea_upvo_zone; /* zone for pvo entries for unmanaged pages */ uma_zone_t moea_mpvo_zone; /* zone for pvo entries for managed pages */ @@ -327,9 +326,12 @@ void moea_deactivate(mmu_t, struct thread *); void moea_cpu_bootstrap(mmu_t, int); void moea_bootstrap(mmu_t, vm_offset_t, vm_offset_t); void *moea_mapdev(mmu_t, vm_offset_t, vm_size_t); +void *moea_mapdev_attr(mmu_t, vm_offset_t, vm_size_t, vm_memattr_t); void moea_unmapdev(mmu_t, vm_offset_t, vm_size_t); vm_offset_t moea_kextract(mmu_t, vm_offset_t); +void moea_kenter_attr(mmu_t, vm_offset_t, vm_offset_t, vm_memattr_t); void moea_kenter(mmu_t, vm_offset_t, vm_offset_t); +void moea_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma); boolean_t moea_dev_direct_mapped(mmu_t, vm_offset_t, vm_size_t); static void moea_sync_icache(mmu_t, pmap_t, vm_offset_t, vm_size_t); @@ -365,34 +367,67 @@ static mmu_method_t moea_methods[] = { MMUMETHOD(mmu_zero_page_idle, moea_zero_page_idle), MMUMETHOD(mmu_activate, moea_activate), MMUMETHOD(mmu_deactivate, moea_deactivate), + MMUMETHOD(mmu_page_set_memattr, moea_page_set_memattr), /* Internal interfaces */ MMUMETHOD(mmu_bootstrap, moea_bootstrap), MMUMETHOD(mmu_cpu_bootstrap, moea_cpu_bootstrap), + MMUMETHOD(mmu_mapdev_attr, moea_mapdev_attr), MMUMETHOD(mmu_mapdev, moea_mapdev), MMUMETHOD(mmu_unmapdev, moea_unmapdev), MMUMETHOD(mmu_kextract, moea_kextract), MMUMETHOD(mmu_kenter, moea_kenter), + MMUMETHOD(mmu_kenter_attr, moea_kenter_attr), MMUMETHOD(mmu_dev_direct_mapped,moea_dev_direct_mapped), { 0, 0 } }; -static mmu_def_t oea_mmu = { - MMU_TYPE_OEA, - moea_methods, - 0 -}; -MMU_DEF(oea_mmu); +MMU_DEF(oea_mmu, MMU_TYPE_OEA, moea_methods, 0); + +static __inline uint32_t +moea_calc_wimg(vm_offset_t pa, vm_memattr_t ma) +{ + uint32_t pte_lo; + int i; + + if (ma != VM_MEMATTR_DEFAULT) { + switch (ma) { + case VM_MEMATTR_UNCACHEABLE: + return (PTE_I | PTE_G); + case VM_MEMATTR_WRITE_COMBINING: + case VM_MEMATTR_WRITE_BACK: + case VM_MEMATTR_PREFETCHABLE: + return (PTE_I); + case VM_MEMATTR_WRITE_THROUGH: + return (PTE_W | PTE_M); + } + } + + /* + * Assume the page is cache inhibited and access is guarded unless + * it's in our available memory array. + */ + pte_lo = PTE_I | PTE_G; + for (i = 0; i < pregions_sz; i++) { + if ((pa >= pregions[i].mr_start) && + (pa < (pregions[i].mr_start + pregions[i].mr_size))) { + pte_lo = PTE_M; + break; + } + } + + return pte_lo; +} static void tlbie(vm_offset_t va) { mtx_lock_spin(&tlbie_mtx); + __asm __volatile("ptesync"); __asm __volatile("tlbie %0" :: "r"(va)); - __asm __volatile("tlbsync"); - powerpc_sync(); + __asm __volatile("eieio; tlbsync; ptesync"); mtx_unlock_spin(&tlbie_mtx); } @@ -425,22 +460,6 @@ va_to_pteg(u_int sr, vm_offset_t addr) return (hash & moea_pteg_mask); } -static __inline struct pvo_head * -pa_to_pvoh(vm_offset_t pa, vm_page_t *pg_p) -{ - struct vm_page *pg; - - pg = PHYS_TO_VM_PAGE(pa); - - if (pg_p != NULL) - *pg_p = pg; - - if (pg == NULL) - return (&moea_pvo_unmanaged); - - return (&pg->md.mdpg_pvoh); -} - static __inline struct pvo_head * vm_page_to_pvoh(vm_page_t m) { @@ -819,6 +838,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) */ mtx_init(&moea_table_mutex, "pmap table", NULL, MTX_DEF | MTX_RECURSE); + mtx_init(&moea_vsid_mutex, "VSID table", NULL, MTX_DEF); mtx_init(&tlbie_mtx, "tlbie", NULL, MTX_SPIN); @@ -881,6 +901,7 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) struct vm_page m; m.phys_addr = translations[i].om_pa + off; + m.md.mdpg_cache_attrs = VM_MEMATTR_DEFAULT; m.oflags = VPO_BUSY; PMAP_LOCK(&ofw_pmap); moea_enter_locked(&ofw_pmap, @@ -1088,7 +1109,7 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, struct pvo_head *pvo_head; uma_zone_t zone; vm_page_t pg; - u_int pte_lo, pvo_flags, was_exec, i; + u_int pte_lo, pvo_flags, was_exec; int error; if (!moea_initialized) { @@ -1130,19 +1151,7 @@ moea_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, } } - /* - * Assume the page is cache inhibited and access is guarded unless - * it's in our available memory array. - */ - pte_lo = PTE_I | PTE_G; - for (i = 0; i < pregions_sz; i++) { - if ((VM_PAGE_TO_PHYS(m) >= pregions[i].mr_start) && - (VM_PAGE_TO_PHYS(m) < - (pregions[i].mr_start + pregions[i].mr_size))) { - pte_lo = PTE_M; - break; - } - } + pte_lo = moea_calc_wimg(VM_PAGE_TO_PHYS(m), pmap_page_get_memattr(m)); if (prot & VM_PROT_WRITE) { pte_lo |= PTE_BW; @@ -1417,15 +1426,61 @@ moea_ts_referenced(mmu_t mmu, vm_page_t m) return (moea_clear_bit(m, PTE_REF)); } +/* + * Modify the WIMG settings of all mappings for a page. + */ +void +moea_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma) +{ + struct pvo_entry *pvo; + struct pvo_head *pvo_head; + struct pte *pt; + pmap_t pmap; + u_int lo; + + if (m->flags & PG_FICTITIOUS) { + m->md.mdpg_cache_attrs = ma; + return; + } + + vm_page_lock_queues(); + pvo_head = vm_page_to_pvoh(m); + lo = moea_calc_wimg(VM_PAGE_TO_PHYS(m), ma); + + LIST_FOREACH(pvo, pvo_head, pvo_vlink) { + pmap = pvo->pvo_pmap; + PMAP_LOCK(pmap); + pt = moea_pvo_to_pte(pvo, -1); + pvo->pvo_pte.pte.pte_lo &= ~PTE_WIMG; + pvo->pvo_pte.pte.pte_lo |= lo; + if (pt != NULL) { + moea_pte_change(pt, &pvo->pvo_pte.pte, + pvo->pvo_vaddr); + if (pvo->pvo_pmap == kernel_pmap) + isync(); + } + mtx_unlock(&moea_table_mutex); + PMAP_UNLOCK(pmap); + } + m->md.mdpg_cache_attrs = ma; + vm_page_unlock_queues(); +} + /* * Map a wired page into kernel virtual address space. */ void moea_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa) +{ + + moea_kenter_attr(mmu, va, pa, VM_MEMATTR_DEFAULT); +} + +void +moea_kenter_attr(mmu_t mmu, vm_offset_t va, vm_offset_t pa, vm_memattr_t ma) { u_int pte_lo; int error; - int i; #if 0 if (va < VM_MIN_KERNEL_ADDRESS) @@ -1433,14 +1488,7 @@ moea_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa) va); #endif - pte_lo = PTE_I | PTE_G; - for (i = 0; i < pregions_sz; i++) { - if ((pa >= pregions[i].mr_start) && - (pa < (pregions[i].mr_start + pregions[i].mr_size))) { - pte_lo = PTE_M; - break; - } - } + pte_lo = moea_calc_wimg(pa, ma); PMAP_LOCK(kernel_pmap); error = moea_pvo_enter(kernel_pmap, moea_upvo_zone, @@ -1589,6 +1637,7 @@ moea_pinit(mmu_t mmu, pmap_t pmap) } + mtx_lock(&moea_vsid_mutex); /* * Allocate some segment registers for this pmap. */ @@ -1615,7 +1664,7 @@ moea_pinit(mmu_t mmu, pmap_t pmap) entropy = (moea_vsidcontext >> 20); continue; } - i = ffs(~moea_vsid_bitmap[i]) - 1; + i = ffs(~moea_vsid_bitmap[n]) - 1; mask = 1 << i; hash &= 0xfffff & ~(VSID_NBPW - 1); hash |= i; @@ -1623,9 +1672,11 @@ moea_pinit(mmu_t mmu, pmap_t pmap) moea_vsid_bitmap[n] |= mask; for (i = 0; i < 16; i++) pmap->pm_sr[i] = VSID_MAKE(i, hash); + mtx_unlock(&moea_vsid_mutex); return; } + mtx_unlock(&moea_vsid_mutex); panic("moea_pinit: out of segments"); } @@ -1737,10 +1788,12 @@ moea_release(mmu_t mmu, pmap_t pmap) if (pmap->pm_sr[0] == 0) panic("moea_release"); + mtx_lock(&moea_vsid_mutex); idx = VSID_TO_HASH(pmap->pm_sr[0]) & (NPMAPS-1); mask = 1 << (idx % VSID_NBPW); idx /= VSID_NBPW; moea_vsid_bitmap[idx] &= ~mask; + mtx_unlock(&moea_vsid_mutex); PMAP_LOCK_DESTROY(pmap); } @@ -2428,6 +2481,13 @@ moea_dev_direct_mapped(mmu_t mmu, vm_offset_t pa, vm_size_t size) */ void * moea_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) +{ + + return (moea_mapdev_attr(mmu, pa, size, VM_MEMATTR_DEFAULT)); +} + +void * +moea_mapdev_attr(mmu_t mmu, vm_offset_t pa, vm_size_t size, vm_memattr_t ma) { vm_offset_t va, tmpva, ppa, offset; int i; @@ -2436,8 +2496,6 @@ moea_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) offset = pa & PAGE_MASK; size = roundup(offset + size, PAGE_SIZE); - GIANT_REQUIRED; - /* * If the physical address lies within a valid BAT table entry, * return the 1:1 mapping. This currently doesn't work @@ -2453,7 +2511,7 @@ moea_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) panic("moea_mapdev: Couldn't alloc kernel virtual memory"); for (tmpva = va; size > 0;) { - moea_kenter(mmu, tmpva, ppa); + moea_kenter_attr(mmu, tmpva, ppa, ma); tlbie(tmpva); size -= PAGE_SIZE; tmpva += PAGE_SIZE; diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 962e8ec528b..5e74a13fdb9 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -211,14 +211,14 @@ TLBIE(uint64_t vpn) { mfmsr %0; \ mr %1, %0; \ insrdi %1,%5,1,0; \ - mtmsrd %1; \ + mtmsrd %1; isync; \ ptesync; \ \ sld %1,%2,%4; \ or %1,%1,%3; \ tlbie %1; \ \ - mtmsrd %0; \ + mtmsrd %0; isync; \ eieio; \ tlbsync; \ ptesync;" @@ -285,6 +285,7 @@ extern void bs_remap_earlyboot(void); * Lock for the pteg and pvo tables. */ struct mtx moea64_table_mutex; +struct mtx moea64_slb_mutex; /* * PTEG data. @@ -297,11 +298,8 @@ u_int moea64_pteg_mask; * PVO data. */ struct pvo_head *moea64_pvo_table; /* pvo entries by pteg index */ -/* lists of unmanaged pages */ -struct pvo_head moea64_pvo_kunmanaged = +struct pvo_head moea64_pvo_kunmanaged = /* list of unmanaged pages */ LIST_HEAD_INITIALIZER(moea64_pvo_kunmanaged); -struct pvo_head moea64_pvo_unmanaged = - LIST_HEAD_INITIALIZER(moea64_pvo_unmanaged); uma_zone_t moea64_upvo_zone; /* zone for pvo entries for unmanaged pages */ uma_zone_t moea64_mpvo_zone; /* zone for pvo entries for managed pages */ @@ -422,8 +420,11 @@ void moea64_zero_page_idle(mmu_t, vm_page_t); void moea64_activate(mmu_t, struct thread *); void moea64_deactivate(mmu_t, struct thread *); void *moea64_mapdev(mmu_t, vm_offset_t, vm_size_t); +void *moea64_mapdev_attr(mmu_t, vm_offset_t, vm_size_t, vm_memattr_t); void moea64_unmapdev(mmu_t, vm_offset_t, vm_size_t); vm_offset_t moea64_kextract(mmu_t, vm_offset_t); +void moea64_page_set_memattr(mmu_t, vm_page_t m, vm_memattr_t ma); +void moea64_kenter_attr(mmu_t, vm_offset_t, vm_offset_t, vm_memattr_t ma); void moea64_kenter(mmu_t, vm_offset_t, vm_offset_t); boolean_t moea64_dev_direct_mapped(mmu_t, vm_offset_t, vm_size_t); static void moea64_sync_icache(mmu_t, pmap_t, vm_offset_t, vm_size_t); @@ -460,25 +461,23 @@ static mmu_method_t moea64_methods[] = { MMUMETHOD(mmu_zero_page_idle, moea64_zero_page_idle), MMUMETHOD(mmu_activate, moea64_activate), MMUMETHOD(mmu_deactivate, moea64_deactivate), + MMUMETHOD(mmu_page_set_memattr, moea64_page_set_memattr), /* Internal interfaces */ MMUMETHOD(mmu_bootstrap, moea64_bootstrap), MMUMETHOD(mmu_cpu_bootstrap, moea64_cpu_bootstrap), MMUMETHOD(mmu_mapdev, moea64_mapdev), + MMUMETHOD(mmu_mapdev_attr, moea64_mapdev_attr), MMUMETHOD(mmu_unmapdev, moea64_unmapdev), MMUMETHOD(mmu_kextract, moea64_kextract), MMUMETHOD(mmu_kenter, moea64_kenter), + MMUMETHOD(mmu_kenter_attr, moea64_kenter_attr), MMUMETHOD(mmu_dev_direct_mapped,moea64_dev_direct_mapped), { 0, 0 } }; -static mmu_def_t oea64_mmu = { - MMU_TYPE_G5, - moea64_methods, - 0 -}; -MMU_DEF(oea64_mmu); +MMU_DEF(oea64_mmu, MMU_TYPE_G5, moea64_methods, 0); static __inline u_int va_to_pteg(uint64_t vsid, vm_offset_t addr, int large) @@ -492,22 +491,6 @@ va_to_pteg(uint64_t vsid, vm_offset_t addr, int large) return (hash & moea64_pteg_mask); } -static __inline struct pvo_head * -pa_to_pvoh(vm_offset_t pa, vm_page_t *pg_p) -{ - struct vm_page *pg; - - pg = PHYS_TO_VM_PAGE(pa); - - if (pg_p != NULL) - *pg_p = pg; - - if (pg == NULL) - return (&moea64_pvo_unmanaged); - - return (&pg->md.mdpg_pvoh); -} - static __inline struct pvo_head * vm_page_to_pvoh(vm_page_t m) { @@ -636,11 +619,24 @@ moea64_pte_change(struct lpte *pt, struct lpte *pvo_pt, uint64_t vpn) } static __inline uint64_t -moea64_calc_wimg(vm_offset_t pa) +moea64_calc_wimg(vm_offset_t pa, vm_memattr_t ma) { uint64_t pte_lo; int i; + if (ma != VM_MEMATTR_DEFAULT) { + switch (ma) { + case VM_MEMATTR_UNCACHEABLE: + return (LPTE_I | LPTE_G); + case VM_MEMATTR_WRITE_COMBINING: + case VM_MEMATTR_WRITE_BACK: + case VM_MEMATTR_PREFETCHABLE: + return (LPTE_I); + case VM_MEMATTR_WRITE_THROUGH: + return (LPTE_W | LPTE_M); + } + } + /* * Assume the page is cache inhibited and access is guarded unless * it's in our available memory array. @@ -842,7 +838,7 @@ moea64_bootstrap_slb_prefault(vm_offset_t va, int large) if (large) entry.slbv |= SLBV_L; - slb_insert(kernel_pmap, cache, &entry); + slb_insert_kernel(entry.slbe, entry.slbv); } #endif @@ -1068,6 +1064,7 @@ moea64_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend) */ mtx_init(&moea64_table_mutex, "pmap table", NULL, MTX_DEF | MTX_RECURSE); + mtx_init(&moea64_slb_mutex, "SLB table", NULL, MTX_DEF); /* * Initialize the TLBIE lock. TLBIE can only be executed by one CPU. @@ -1379,7 +1376,7 @@ void moea64_set_scratchpage_pa(int which, vm_offset_t pa) { moea64_scratchpage_pte[which]->pte_lo &= ~(LPTE_WIMG | LPTE_RPGN); moea64_scratchpage_pte[which]->pte_lo |= - moea64_calc_wimg(pa) | (uint64_t)pa; + moea64_calc_wimg(pa, VM_MEMATTR_DEFAULT) | (uint64_t)pa; EIEIO(); moea64_scratchpage_pte[which]->pte_hi |= LPTE_VALID; @@ -1527,7 +1524,7 @@ moea64_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot, zone = moea64_upvo_zone; } - pte_lo = moea64_calc_wimg(VM_PAGE_TO_PHYS(m)); + pte_lo = moea64_calc_wimg(VM_PAGE_TO_PHYS(m), pmap_page_get_memattr(m)); if (prot & VM_PROT_WRITE) { pte_lo |= LPTE_BW; @@ -1894,24 +1891,56 @@ moea64_ts_referenced(mmu_t mmu, vm_page_t m) return (moea64_clear_bit(m, LPTE_REF)); } +/* + * Modify the WIMG settings of all mappings for a page. + */ +void +moea64_page_set_memattr(mmu_t mmu, vm_page_t m, vm_memattr_t ma) +{ + struct pvo_entry *pvo; + struct pvo_head *pvo_head; + struct lpte *pt; + pmap_t pmap; + uint64_t lo; + + if (m->flags & PG_FICTITIOUS) { + m->md.mdpg_cache_attrs = ma; + return; + } + + vm_page_lock_queues(); + pvo_head = vm_page_to_pvoh(m); + lo = moea64_calc_wimg(VM_PAGE_TO_PHYS(m), ma); + LIST_FOREACH(pvo, pvo_head, pvo_vlink) { + pmap = pvo->pvo_pmap; + PMAP_LOCK(pmap); + LOCK_TABLE(); + pt = moea64_pvo_to_pte(pvo); + pvo->pvo_pte.lpte.pte_lo &= ~LPTE_WIMG; + pvo->pvo_pte.lpte.pte_lo |= lo; + if (pt != NULL) { + moea64_pte_change(pt, &pvo->pvo_pte.lpte, + pvo->pvo_vpn); + if (pvo->pvo_pmap == kernel_pmap) + isync(); + } + UNLOCK_TABLE(); + PMAP_UNLOCK(pmap); + } + m->md.mdpg_cache_attrs = ma; + vm_page_unlock_queues(); +} + /* * Map a wired page into kernel virtual address space. */ void -moea64_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa) +moea64_kenter_attr(mmu_t mmu, vm_offset_t va, vm_offset_t pa, vm_memattr_t ma) { uint64_t pte_lo; int error; -#if 0 - if (!pmap_bootstrapped) { - if (va >= VM_MIN_KERNEL_ADDRESS && va < virtual_end) - panic("Trying to enter an address in KVA -- %#" - PRIxPTR "!\n",pa); - } -#endif - - pte_lo = moea64_calc_wimg(pa); + pte_lo = moea64_calc_wimg(pa, ma); PMAP_LOCK(kernel_pmap); error = moea64_pvo_enter(kernel_pmap, moea64_upvo_zone, @@ -1931,6 +1960,13 @@ moea64_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa) PMAP_UNLOCK(kernel_pmap); } +void +moea64_kenter(mmu_t mmu, vm_offset_t va, vm_offset_t pa) +{ + + moea64_kenter_attr(mmu, va, pa, VM_MEMATTR_DEFAULT); +} + /* * Extract the physical page address associated with the given kernel virtual * address. @@ -2054,6 +2090,7 @@ moea64_get_unique_vsid(void) { entropy = 0; __asm __volatile("mftb %0" : "=r"(entropy)); + mtx_lock(&moea64_slb_mutex); for (i = 0; i < NVSIDS; i += VSID_NBPW) { u_int n; @@ -2077,15 +2114,19 @@ moea64_get_unique_vsid(void) { entropy = (moea64_vsidcontext >> 20); continue; } - i = ffs(~moea64_vsid_bitmap[i]) - 1; + i = ffs(~moea64_vsid_bitmap[n]) - 1; mask = 1 << i; hash &= VSID_HASHMASK & ~(VSID_NBPW - 1); hash |= i; } + KASSERT(!(moea64_vsid_bitmap[n] & mask), + ("Allocating in-use VSID %#zx\n", hash)); moea64_vsid_bitmap[n] |= mask; + mtx_unlock(&moea64_slb_mutex); return (hash); } + mtx_unlock(&moea64_slb_mutex); panic("%s: out of segments",__func__); } @@ -2095,15 +2136,16 @@ moea64_pinit(mmu_t mmu, pmap_t pmap) { PMAP_LOCK_INIT(pmap); - SPLAY_INIT(&pmap->pm_slbtree); + pmap->pm_slb_tree_root = slb_alloc_tree(); pmap->pm_slb = slb_alloc_user_cache(); + pmap->pm_slb_len = 0; } #else void moea64_pinit(mmu_t mmu, pmap_t pmap) { int i; - register_t hash; + uint32_t hash; PMAP_LOCK_INIT(pmap); @@ -2120,6 +2162,8 @@ moea64_pinit(mmu_t mmu, pmap_t pmap) for (i = 0; i < 16; i++) pmap->pm_sr[i] = VSID_MAKE(i, hash); + + KASSERT(pmap->pm_sr[0] != 0, ("moea64_pinit: pm_sr[0] = 0")); } #endif @@ -2227,12 +2271,16 @@ moea64_qremove(mmu_t mmu, vm_offset_t va, int count) void moea64_release_vsid(uint64_t vsid) { - int idx, mask; + int idx, mask; - idx = vsid & (NVSIDS-1); - mask = 1 << (idx % VSID_NBPW); - idx /= VSID_NBPW; - moea64_vsid_bitmap[idx] &= ~mask; + mtx_lock(&moea64_slb_mutex); + idx = vsid & (NVSIDS-1); + mask = 1 << (idx % VSID_NBPW); + idx /= VSID_NBPW; + KASSERT(moea64_vsid_bitmap[idx] & mask, + ("Freeing unallocated VSID %#jx", vsid)); + moea64_vsid_bitmap[idx] &= ~mask; + mtx_unlock(&moea64_slb_mutex); } @@ -2244,13 +2292,12 @@ moea64_release(mmu_t mmu, pmap_t pmap) * Free segment registers' VSIDs */ #ifdef __powerpc64__ - free_vsids(pmap); + slb_free_tree(pmap); slb_free_user_cache(pmap->pm_slb); #else - if (pmap->pm_sr[0] == 0) - panic("moea64_release"); + KASSERT(pmap->pm_sr[0] != 0, ("moea64_release: pm_sr[0] = 0")); - moea64_release_vsid(pmap->pm_sr[0]); + moea64_release_vsid(VSID_TO_HASH(pmap->pm_sr[0])); #endif PMAP_LOCK_DESTROY(pmap); @@ -2412,7 +2459,6 @@ moea64_pvo_enter(pmap_t pm, uma_zone_t zone, struct pvo_head *pvo_head, * the bootstrap pool. */ - moea64_pvo_enter_calls++; first = 0; bootstrap = (flags & PVO_BOOTSTRAP); @@ -2432,6 +2478,8 @@ moea64_pvo_enter(pmap_t pm, uma_zone_t zone, struct pvo_head *pvo_head, */ LOCK_TABLE(); + moea64_pvo_enter_calls++; + LIST_FOREACH(pvo, &moea64_pvo_table[ptegidx], pvo_olink) { if (pvo->pvo_pmap == pm && PVO_VADDR(pvo) == va) { if ((pvo->pvo_pte.lpte.pte_lo & LPTE_RPGN) == pa && @@ -2596,14 +2644,15 @@ moea64_pvo_remove(struct pvo_entry *pvo) * if we aren't going to reuse it. */ LIST_REMOVE(pvo, pvo_olink); + + moea64_pvo_entries--; + moea64_pvo_remove_calls++; + UNLOCK_TABLE(); if (!(pvo->pvo_vaddr & PVO_BOOTSTRAP)) uma_zfree((pvo->pvo_vaddr & PVO_MANAGED) ? moea64_mpvo_zone : moea64_upvo_zone, pvo); - - moea64_pvo_entries--; - moea64_pvo_remove_calls++; } static struct pvo_entry * @@ -2613,18 +2662,25 @@ moea64_pvo_find_va(pmap_t pm, vm_offset_t va) int ptegidx; uint64_t vsid; #ifdef __powerpc64__ - struct slb slb; + uint64_t slbv; - /* The page is not mapped if the segment isn't */ - if (va_to_slb_entry(pm, va, &slb) != 0) - return NULL; + if (pm == kernel_pmap) { + slbv = kernel_va_to_slbv(va); + } else { + struct slb *slb; + slb = user_va_to_slb_entry(pm, va); + /* The page is not mapped if the segment isn't */ + if (slb == NULL) + return NULL; + slbv = slb->slbv; + } - vsid = (slb.slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT; - if (slb.slbv & SLBV_L) + vsid = (slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT; + if (slbv & SLBV_L) va &= ~moea64_large_page_mask; else va &= ~ADDR_POFF; - ptegidx = va_to_pteg(vsid, va, slb.slbv & SLBV_L); + ptegidx = va_to_pteg(vsid, va, slbv & SLBV_L); #else va &= ~ADDR_POFF; vsid = va_to_vsid(pm, va); @@ -2959,7 +3015,7 @@ moea64_dev_direct_mapped(mmu_t mmu, vm_offset_t pa, vm_size_t size) * NOT real memory. */ void * -moea64_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) +moea64_mapdev_attr(mmu_t mmu, vm_offset_t pa, vm_size_t size, vm_memattr_t ma) { vm_offset_t va, tmpva, ppa, offset; @@ -2973,7 +3029,7 @@ moea64_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) panic("moea64_mapdev: Couldn't alloc kernel virtual memory"); for (tmpva = va; size > 0;) { - moea64_kenter(mmu, tmpva, ppa); + moea64_kenter_attr(mmu, tmpva, ppa, ma); size -= PAGE_SIZE; tmpva += PAGE_SIZE; ppa += PAGE_SIZE; @@ -2982,6 +3038,13 @@ moea64_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) return ((void *)(va + offset)); } +void * +moea64_mapdev(mmu_t mmu, vm_offset_t pa, vm_size_t size) +{ + + return moea64_mapdev_attr(mmu, pa, size, VM_MEMATTR_DEFAULT); +} + void moea64_unmapdev(mmu_t mmu, vm_offset_t va, vm_size_t size) { diff --git a/sys/powerpc/aim/nexus.c b/sys/powerpc/aim/nexus.c index b3350a1799c..b17de11eccc 100644 --- a/sys/powerpc/aim/nexus.c +++ b/sys/powerpc/aim/nexus.c @@ -63,6 +63,7 @@ #include #include +#include #include #include @@ -114,7 +115,7 @@ static int nexus_attach(device_t); /* * Bus interface */ -static device_t nexus_add_child(device_t, int, const char *, int); +static device_t nexus_add_child(device_t, u_int, const char *, int); static void nexus_probe_nomatch(device_t, device_t); static int nexus_read_ivar(device_t, device_t, int, uintptr_t *); static int nexus_write_ivar(device_t, device_t, int, uintptr_t); @@ -162,6 +163,7 @@ static device_method_t nexus_methods[] = { /* Bus interface. Resource management is business of the children... */ DEVMETHOD(bus_add_child, nexus_add_child), DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch), DEVMETHOD(bus_read_ivar, nexus_read_ivar), DEVMETHOD(bus_write_ivar, nexus_write_ivar), @@ -260,7 +262,7 @@ nexus_probe_nomatch(device_t dev, device_t child) } static device_t -nexus_add_child(device_t dev, int order, const char *name, int unit) +nexus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct nexus_devinfo *dinfo; diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/aim/ofw_machdep.c index 21b88477807..e0bf5057521 100644 --- a/sys/powerpc/aim/ofw_machdep.c +++ b/sys/powerpc/aim/ofw_machdep.c @@ -526,21 +526,22 @@ openfirmware(void *args) return (result); } -void -OF_halt() -{ - int retval; /* dummy, this may not be needed */ - - OF_interpret("shut-down", 1, &retval); - for (;;); /* just in case */ -} - void OF_reboot() { - int retval; /* dummy, this may not be needed */ + struct { + cell_t name; + cell_t nargs; + cell_t nreturns; + cell_t arg; + } args; + + args.name = (cell_t)(uintptr_t)"interpret"; + args.nargs = 1; + args.nreturns = 0; + args.arg = (cell_t)(uintptr_t)"reset-all"; + openfirmware_core(&args); /* Don't do rendezvous! */ - OF_interpret("reset-all", 1, &retval); for (;;); /* just in case */ } diff --git a/sys/powerpc/aim/slb.c b/sys/powerpc/aim/slb.c index 7ea45931e26..e7bdaf85b94 100644 --- a/sys/powerpc/aim/slb.c +++ b/sys/powerpc/aim/slb.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -45,65 +44,212 @@ uintptr_t moea64_get_unique_vsid(void); void moea64_release_vsid(uint64_t vsid); - -struct slbcontainer { - struct slb slb; - SPLAY_ENTRY(slbcontainer) slb_node; -}; - -static int slb_compare(struct slbcontainer *a, struct slbcontainer *b); static void slb_zone_init(void *); -SPLAY_PROTOTYPE(slb_tree, slbcontainer, slb_node, slb_compare); -SPLAY_GENERATE(slb_tree, slbcontainer, slb_node, slb_compare); - -uma_zone_t slb_zone; +uma_zone_t slbt_zone; uma_zone_t slb_cache_zone; SYSINIT(slb_zone_init, SI_SUB_KMEM, SI_ORDER_ANY, slb_zone_init, NULL); -int -va_to_slb_entry(pmap_t pm, vm_offset_t va, struct slb *slb) +struct slbtnode { + uint16_t ua_alloc; + uint8_t ua_level; + /* Only 36 bits needed for full 64-bit address space. */ + uint64_t ua_base; + union { + struct slbtnode *ua_child[16]; + struct slb slb_entries[16]; + } u; +}; + +/* + * For a full 64-bit address space, there are 36 bits in play in an + * esid, so 8 levels, with the leaf being at level 0. + * + * |3333|3322|2222|2222|1111|1111|11 | | | esid + * |5432|1098|7654|3210|9876|5432|1098|7654|3210| bits + * +----+----+----+----+----+----+----+----+----+-------- + * | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | level + */ +#define UAD_ROOT_LEVEL 8 +#define UAD_LEAF_LEVEL 0 + +static inline int +esid2idx(uint64_t esid, int level) { - struct slbcontainer cont, *found; - uint64_t esid; + int shift; + + shift = level * 4; + return ((esid >> shift) & 0xF); +} + +/* + * The ua_base field should have 0 bits after the first 4*(level+1) + * bits; i.e. only + */ +#define uad_baseok(ua) \ + (esid2base(ua->ua_base, ua->ua_level) == ua->ua_base) + + +static inline uint64_t +esid2base(uint64_t esid, int level) +{ + uint64_t mask; + int shift; + + shift = (level + 1) * 4; + mask = ~((1ULL << shift) - 1); + return (esid & mask); +} + +/* + * Allocate a new leaf node for the specified esid/vmhandle from the + * parent node. + */ +static struct slb * +make_new_leaf(uint64_t esid, uint64_t slbv, struct slbtnode *parent) +{ + struct slbtnode *child; + struct slb *retval; + int idx; + + idx = esid2idx(esid, parent->ua_level); + KASSERT(parent->u.ua_child[idx] == NULL, ("Child already exists!")); + + /* unlock and M_WAITOK and loop? */ + child = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + KASSERT(child != NULL, ("unhandled NULL case")); + + child->ua_level = UAD_LEAF_LEVEL; + child->ua_base = esid2base(esid, child->ua_level); + idx = esid2idx(esid, child->ua_level); + child->u.slb_entries[idx].slbv = slbv; + child->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; + setbit(&child->ua_alloc, idx); + + retval = &child->u.slb_entries[idx]; + + /* + * The above stores must be visible before the next one, so + * that a lockless searcher always sees a valid path through + * the tree. + */ + powerpc_sync(); + + idx = esid2idx(esid, parent->ua_level); + parent->u.ua_child[idx] = child; + setbit(&parent->ua_alloc, idx); + + return (retval); +} + +/* + * Allocate a new intermediate node to fit between the parent and + * esid. + */ +static struct slbtnode* +make_intermediate(uint64_t esid, struct slbtnode *parent) +{ + struct slbtnode *child, *inter; + int idx, level; + + idx = esid2idx(esid, parent->ua_level); + child = parent->u.ua_child[idx]; + KASSERT(esid2base(esid, child->ua_level) != child->ua_base, + ("No need for an intermediate node?")); + + /* + * Find the level where the existing child and our new esid + * meet. It must be lower than parent->ua_level or we would + * have chosen a different index in parent. + */ + level = child->ua_level + 1; + while (esid2base(esid, level) != + esid2base(child->ua_base, level)) + level++; + KASSERT(level < parent->ua_level, + ("Found splitting level %d for %09jx and %09jx, " + "but it's the same as %p's", + level, esid, child->ua_base, parent)); + + /* unlock and M_WAITOK and loop? */ + inter = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + KASSERT(inter != NULL, ("unhandled NULL case")); + + /* Set up intermediate node to point to child ... */ + inter->ua_level = level; + inter->ua_base = esid2base(esid, inter->ua_level); + idx = esid2idx(child->ua_base, inter->ua_level); + inter->u.ua_child[idx] = child; + setbit(&inter->ua_alloc, idx); + powerpc_sync(); + + /* Set up parent to point to intermediate node ... */ + idx = esid2idx(inter->ua_base, parent->ua_level); + parent->u.ua_child[idx] = inter; + setbit(&parent->ua_alloc, idx); + + return (inter); +} + +uint64_t +kernel_va_to_slbv(vm_offset_t va) +{ + uint64_t esid, slbv; esid = (uintptr_t)va >> ADDR_SR_SHFT; - slb->slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; - if (pm == kernel_pmap) { - /* Set kernel VSID to deterministic value */ - slb->slbv = va_to_vsid(kernel_pmap, va) << SLBV_VSID_SHIFT; + /* Set kernel VSID to deterministic value */ + slbv = va_to_vsid(kernel_pmap, va) << SLBV_VSID_SHIFT; - /* Figure out if this is a large-page mapping */ - if (hw_direct_map && va < VM_MIN_KERNEL_ADDRESS) { - /* - * XXX: If we have set up a direct map, assumes - * all physical memory is mapped with large pages. - */ - if (mem_valid(va, 0) == 0) - slb->slbv |= SLBV_L; - } - - return (0); + /* Figure out if this is a large-page mapping */ + if (hw_direct_map && va < VM_MIN_KERNEL_ADDRESS) { + /* + * XXX: If we have set up a direct map, assumes + * all physical memory is mapped with large pages. + */ + if (mem_valid(va, 0) == 0) + slbv |= SLBV_L; + } + + return (slbv); +} + +struct slb * +user_va_to_slb_entry(pmap_t pm, vm_offset_t va) +{ + uint64_t esid = va >> ADDR_SR_SHFT; + struct slbtnode *ua; + int idx; + + ua = pm->pm_slb_tree_root; + + for (;;) { + KASSERT(uad_baseok(ua), ("uad base %016jx level %d bad!", + ua->ua_base, ua->ua_level)); + idx = esid2idx(esid, ua->ua_level); + + /* + * This code is specific to ppc64 where a load is + * atomic, so no need for atomic_load macro. + */ + if (ua->ua_level == UAD_LEAF_LEVEL) + return ((ua->u.slb_entries[idx].slbe & SLBE_VALID) ? + &ua->u.slb_entries[idx] : NULL); + + ua = ua->u.ua_child[idx]; + if (ua == NULL || + esid2base(esid, ua->ua_level) != ua->ua_base) + return (NULL); } - PMAP_LOCK_ASSERT(pm, MA_OWNED); - - cont.slb.slbe = slb->slbe; - found = SPLAY_FIND(slb_tree, &pm->pm_slbtree, &cont); - - if (found == NULL) - return (-1); - - slb->slbv = found->slb.slbv; - return (0); + return (NULL); } uint64_t va_to_vsid(pmap_t pm, vm_offset_t va) { - struct slb entry; + struct slb *entry; /* Shortcut kernel case */ if (pm == kernel_pmap) @@ -114,56 +260,150 @@ va_to_vsid(pmap_t pm, vm_offset_t va) * to the PMAP's segment table. */ - if (va_to_slb_entry(pm, va, &entry) != 0) - return (allocate_vsid(pm, (uintptr_t)va >> ADDR_SR_SHFT, 0)); + entry = user_va_to_slb_entry(pm, va); - return ((entry.slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT); + if (entry == NULL) + return (allocate_user_vsid(pm, + (uintptr_t)va >> ADDR_SR_SHFT, 0)); + + return ((entry->slbv & SLBV_VSID_MASK) >> SLBV_VSID_SHIFT); } uint64_t -allocate_vsid(pmap_t pm, uint64_t esid, int large) +allocate_user_vsid(pmap_t pm, uint64_t esid, int large) { - uint64_t vsid; - struct slbcontainer *slb_entry, kern_entry; - struct slb *prespill; + uint64_t vsid, slbv; + struct slbtnode *ua, *next, *inter; + struct slb *slb; + int idx; - prespill = NULL; + KASSERT(pm != kernel_pmap, ("Attempting to allocate a kernel VSID")); - if (pm == kernel_pmap) { - vsid = va_to_vsid(pm, esid << ADDR_SR_SHFT); - slb_entry = &kern_entry; - prespill = PCPU_GET(slb); - } else { - vsid = moea64_get_unique_vsid(); - slb_entry = uma_zalloc(slb_zone, M_NOWAIT); - - if (slb_entry == NULL) - panic("Could not allocate SLB mapping!"); - - prespill = pm->pm_slb; - } - - slb_entry->slb.slbe = (esid << SLBE_ESID_SHIFT) | SLBE_VALID; - slb_entry->slb.slbv = vsid << SLBV_VSID_SHIFT; + PMAP_LOCK_ASSERT(pm, MA_OWNED); + vsid = moea64_get_unique_vsid(); + slbv = vsid << SLBV_VSID_SHIFT; if (large) - slb_entry->slb.slbv |= SLBV_L; + slbv |= SLBV_L; - if (pm != kernel_pmap) { - PMAP_LOCK_ASSERT(pm, MA_OWNED); - SPLAY_INSERT(slb_tree, &pm->pm_slbtree, slb_entry); + ua = pm->pm_slb_tree_root; + + /* Descend to the correct leaf or NULL pointer. */ + for (;;) { + KASSERT(uad_baseok(ua), + ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); + idx = esid2idx(esid, ua->ua_level); + + if (ua->ua_level == UAD_LEAF_LEVEL) { + ua->u.slb_entries[idx].slbv = slbv; + eieio(); + ua->u.slb_entries[idx].slbe = (esid << SLBE_ESID_SHIFT) + | SLBE_VALID; + setbit(&ua->ua_alloc, idx); + slb = &ua->u.slb_entries[idx]; + break; + } + + next = ua->u.ua_child[idx]; + if (next == NULL) { + slb = make_new_leaf(esid, slbv, ua); + break; + } + + /* + * Check if the next item down has an okay ua_base. + * If not, we need to allocate an intermediate node. + */ + if (esid2base(esid, next->ua_level) != next->ua_base) { + inter = make_intermediate(esid, ua); + slb = make_new_leaf(esid, slbv, inter); + break; + } + + ua = next; } /* * Someone probably wants this soon, and it may be a wired * SLB mapping, so pre-spill this entry. */ - if (prespill != NULL) - slb_insert(pm, prespill, &slb_entry->slb); + eieio(); + slb_insert_user(pm, slb); return (vsid); } +void +free_vsid(pmap_t pm, uint64_t esid, int large) +{ + struct slbtnode *ua; + int idx; + + PMAP_LOCK_ASSERT(pm, MA_OWNED); + + ua = pm->pm_slb_tree_root; + /* Descend to the correct leaf. */ + for (;;) { + KASSERT(uad_baseok(ua), + ("uad base %09jx level %d bad!", ua->ua_base, ua->ua_level)); + + idx = esid2idx(esid, ua->ua_level); + if (ua->ua_level == UAD_LEAF_LEVEL) { + ua->u.slb_entries[idx].slbv = 0; + eieio(); + ua->u.slb_entries[idx].slbe = 0; + clrbit(&ua->ua_alloc, idx); + return; + } + + ua = ua->u.ua_child[idx]; + if (ua == NULL || + esid2base(esid, ua->ua_level) != ua->ua_base) { + /* Perhaps just return instead of assert? */ + KASSERT(0, + ("Asked to remove an entry that was never inserted!")); + return; + } + } +} + +static void +free_slb_tree_node(struct slbtnode *ua) +{ + int idx; + + for (idx = 0; idx < 16; idx++) { + if (ua->ua_level != UAD_LEAF_LEVEL) { + if (ua->u.ua_child[idx] != NULL) + free_slb_tree_node(ua->u.ua_child[idx]); + } else { + if (ua->u.slb_entries[idx].slbv != 0) + moea64_release_vsid(ua->u.slb_entries[idx].slbv + >> SLBV_VSID_SHIFT); + } + } + + uma_zfree(slbt_zone, ua); +} + +void +slb_free_tree(pmap_t pm) +{ + + free_slb_tree_node(pm->pm_slb_tree_root); +} + +struct slbtnode * +slb_alloc_tree(void) +{ + struct slbtnode *root; + + root = uma_zalloc(slbt_zone, M_NOWAIT | M_ZERO); + root->ua_level = UAD_ROOT_LEVEL; + + return (root); +} + /* Lock entries mapping kernel text and stacks */ #define SLB_SPILLABLE(slbe) \ @@ -171,126 +411,87 @@ allocate_vsid(pmap_t pm, uint64_t esid, int large) (slbe & SLBE_ESID_MASK) > 16*SEGMENT_LENGTH) || \ (slbe & SLBE_ESID_MASK) > VM_MAX_KERNEL_ADDRESS) void -slb_insert(pmap_t pm, struct slb *slbcache, struct slb *slb_entry) +slb_insert_kernel(uint64_t slbe, uint64_t slbv) { - uint64_t slbe, slbv; - int i, j, to_spill; + struct slb *slbcache; + int i, j; /* We don't want to be preempted while modifying the kernel map */ critical_enter(); - to_spill = -1; - slbv = slb_entry->slbv; - slbe = slb_entry->slbe; + slbcache = PCPU_GET(slb); - /* Hunt for a likely candidate */ - - for (i = mftb() % 64, j = 0; j < 64; j++, i = (i+1) % 64) { - if (pm == kernel_pmap && i == USER_SR) - continue; - - if (!(slbcache[i].slbe & SLBE_VALID)) { - to_spill = i; - break; + /* Check for an unused slot, abusing the USER_SR slot as a full flag */ + if (slbcache[USER_SR].slbe == 0) { + for (i = 0; i < USER_SR; i++) { + if (!(slbcache[i].slbe & SLBE_VALID)) + goto fillkernslb; } - if (to_spill < 0 && (pm != kernel_pmap || - SLB_SPILLABLE(slbcache[i].slbe))) - to_spill = i; + if (i == USER_SR) + slbcache[USER_SR].slbe = 1; } - if (to_spill < 0) - panic("SLB spill on ESID %#lx, but no available candidates!\n", - (slbe & SLBE_ESID_MASK) >> SLBE_ESID_SHIFT); + for (i = mftb() % 64, j = 0; j < 64; j++, i = (i+1) % 64) { + if (i == USER_SR) + continue; - if (slbcache[to_spill].slbe & SLBE_VALID) { - /* Invalidate this first to avoid races */ - slbcache[to_spill].slbe = 0; - mb(); + if (SLB_SPILLABLE(slbcache[i].slbe)) + break; } - slbcache[to_spill].slbv = slbv; - slbcache[to_spill].slbe = slbe | (uint64_t)to_spill; + + KASSERT(j < 64, ("All kernel SLB slots locked!")); + +fillkernslb: + slbcache[i].slbv = slbv; + slbcache[i].slbe = slbe | (uint64_t)i; /* If it is for this CPU, put it in the SLB right away */ - if (pm == kernel_pmap && pmap_bootstrapped) { + if (pmap_bootstrapped) { /* slbie not required */ __asm __volatile ("slbmte %0, %1" :: - "r"(slbcache[to_spill].slbv), - "r"(slbcache[to_spill].slbe)); + "r"(slbcache[i].slbv), "r"(slbcache[i].slbe)); } critical_exit(); } -int -vsid_to_esid(pmap_t pm, uint64_t vsid, uint64_t *esid) +void +slb_insert_user(pmap_t pm, struct slb *slb) { - uint64_t slbv; - struct slbcontainer *entry; - -#ifdef INVARIANTS - if (pm == kernel_pmap) - panic("vsid_to_esid only works on user pmaps"); + int i; PMAP_LOCK_ASSERT(pm, MA_OWNED); -#endif - slbv = vsid << SLBV_VSID_SHIFT; - - SPLAY_FOREACH(entry, slb_tree, &pm->pm_slbtree) { - if (slbv == entry->slb.slbv) { - *esid = entry->slb.slbe >> SLBE_ESID_SHIFT; - return (0); - } + if (pm->pm_slb_len < 64) { + i = pm->pm_slb_len; + pm->pm_slb_len++; + } else { + i = mftb() % 64; } - return (-1); -} - -void -free_vsids(pmap_t pm) -{ - struct slbcontainer *entry; - - while (!SPLAY_EMPTY(&pm->pm_slbtree)) { - entry = SPLAY_MIN(slb_tree, &pm->pm_slbtree); - - SPLAY_REMOVE(slb_tree, &pm->pm_slbtree, entry); - - moea64_release_vsid(entry->slb.slbv >> SLBV_VSID_SHIFT); - uma_zfree(slb_zone, entry); - } -} - -static int -slb_compare(struct slbcontainer *a, struct slbcontainer *b) -{ - if (a->slb.slbe == b->slb.slbe) - return (0); - else if (a->slb.slbe < b->slb.slbe) - return (-1); - else - return (1); + /* Note that this replacement is atomic with respect to trap_subr */ + pm->pm_slb[i] = slb; } static void slb_zone_init(void *dummy) { - slb_zone = uma_zcreate("SLB segment", sizeof(struct slbcontainer), + slbt_zone = uma_zcreate("SLB tree node", sizeof(struct slbtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); - slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb), + slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb *), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM); } -struct slb * +struct slb ** slb_alloc_user_cache(void) { return (uma_zalloc(slb_cache_zone, M_ZERO)); } void -slb_free_user_cache(struct slb *slb) +slb_free_user_cache(struct slb **slb) { uma_zfree(slb_cache_zone, slb); } diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c index df5c97153e9..db48e7ba76a 100644 --- a/sys/powerpc/aim/trap.c +++ b/sys/powerpc/aim/trap.c @@ -34,8 +34,6 @@ #include __FBSDID("$FreeBSD$"); -#include "opt_ktrace.h" - #include #include #include @@ -50,9 +48,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#endif #include #include @@ -208,9 +203,19 @@ trap(struct trapframe *frame) enable_vec(td); break; - case EXC_VECAST: - printf("Vector assist exception!\n"); - sig = SIGILL; + case EXC_VECAST_G4: + case EXC_VECAST_G5: + /* + * We get a VPU assist exception for IEEE mode + * vector operations on denormalized floats. + * Emulating this is a giant pain, so for now, + * just switch off IEEE mode and treat them as + * zero. + */ + + save_vec(td); + td->td_pcb->pcb_vec.vscr |= ALTIVEC_VSCR_NJ; + enable_vec(td); break; case EXC_ALI: @@ -450,33 +455,35 @@ syscall(struct trapframe *frame) static int handle_slb_spill(pmap_t pm, vm_offset_t addr) { - struct slb slb_entry; - int error, i; + struct slb *user_entry; + uint64_t esid; + int i; + + esid = (uintptr_t)addr >> ADDR_SR_SHFT; if (pm == kernel_pmap) { - error = va_to_slb_entry(pm, addr, &slb_entry); - if (error) - return (error); - - slb_insert(pm, PCPU_GET(slb), &slb_entry); + slb_insert_kernel((esid << SLBE_ESID_SHIFT) | SLBE_VALID, + kernel_va_to_slbv(addr)); return (0); } PMAP_LOCK(pm); - error = va_to_slb_entry(pm, addr, &slb_entry); - if (error != 0) - (void)allocate_vsid(pm, (uintptr_t)addr >> ADDR_SR_SHFT, 0); - else { + user_entry = user_va_to_slb_entry(pm, addr); + + if (user_entry == NULL) { + /* allocate_vsid auto-spills it */ + (void)allocate_user_vsid(pm, esid, 0); + } else { /* * Check that another CPU has not already mapped this. * XXX: Per-thread SLB caches would be better. */ - for (i = 0; i < 64; i++) - if (pm->pm_slb[i].slbe == (slb_entry.slbe | i)) + for (i = 0; i < pm->pm_slb_len; i++) + if (pm->pm_slb[i] == user_entry) break; - if (i == 64) - slb_insert(pm, pm->pm_slb, &slb_entry); + if (i == pm->pm_slb_len) + slb_insert_user(pm, user_entry); } PMAP_UNLOCK(pm); @@ -518,19 +525,7 @@ trap_pfault(struct trapframe *frame, int user) map = &p->p_vmspace->vm_map; #ifdef __powerpc64__ - user_sr = 0; - __asm ("slbmfev %0, %1" - : "=r"(user_sr) - : "r"(USER_SR)); - - PMAP_LOCK(&p->p_vmspace->vm_pmap); - user_sr >>= SLBV_VSID_SHIFT; - rv = vsid_to_esid(&p->p_vmspace->vm_pmap, user_sr, - &user_sr); - PMAP_UNLOCK(&p->p_vmspace->vm_pmap); - - if (rv != 0) - return (SIGSEGV); + user_sr = td->td_pcb->pcb_cpu.aim.usr_segm; #else __asm ("mfsr %0, %1" : "=r"(user_sr) diff --git a/sys/powerpc/aim/trap_subr.S b/sys/powerpc/aim/trap_subr.S deleted file mode 100644 index 5d9596b5184..00000000000 --- a/sys/powerpc/aim/trap_subr.S +++ /dev/null @@ -1,677 +0,0 @@ -/* $FreeBSD$ */ -/* $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $ */ - -/*- - * Copyright (C) 1995, 1996 Wolfgang Solfrank. - * Copyright (C) 1995, 1996 TooLs GmbH. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by TooLs GmbH. - * 4. The name of TooLs GmbH may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. - */ - -/* - * NOTICE: This is not a standalone file. to use it, #include it in - * your port's locore.S, like so: - * - * #include - */ - -/* - * Save/restore segment registers - */ -#define RESTORE_SRS(pmap,sr) mtsr 0,sr; \ - lwz sr,1*4(pmap); mtsr 1,sr; \ - lwz sr,2*4(pmap); mtsr 2,sr; \ - lwz sr,3*4(pmap); mtsr 3,sr; \ - lwz sr,4*4(pmap); mtsr 4,sr; \ - lwz sr,5*4(pmap); mtsr 5,sr; \ - lwz sr,6*4(pmap); mtsr 6,sr; \ - lwz sr,7*4(pmap); mtsr 7,sr; \ - lwz sr,8*4(pmap); mtsr 8,sr; \ - lwz sr,9*4(pmap); mtsr 9,sr; \ - lwz sr,10*4(pmap); mtsr 10,sr; \ - lwz sr,11*4(pmap); mtsr 11,sr; \ - lwz sr,12*4(pmap); mtsr 12,sr; \ - lwz sr,13*4(pmap); mtsr 13,sr; \ - lwz sr,14*4(pmap); mtsr 14,sr; \ - lwz sr,15*4(pmap); mtsr 15,sr; isync; - -/* - * User SRs are loaded through a pointer to the current pmap. - */ -#define RESTORE_USER_SRS(pmap,sr) \ - GET_CPUINFO(pmap); \ - lwz pmap,PC_CURPMAP(pmap); \ - lwzu sr,PM_SR(pmap); \ - RESTORE_SRS(pmap,sr) - -/* - * Kernel SRs are loaded directly from kernel_pmap_ - */ -#define RESTORE_KERN_SRS(pmap,sr) \ - lis pmap,CNAME(kernel_pmap_store)@ha; \ - lwzu sr,CNAME(kernel_pmap_store)+PM_SR@l(pmap); \ - RESTORE_SRS(pmap,sr) - -/* - * FRAME_SETUP assumes: - * SPRG1 SP (1) - * SPRG3 trap type - * savearea r28-r31,DAR,DSISR (DAR & DSISR only for DSI traps) - * r28 LR - * r29 CR - * r30 scratch - * r31 scratch - * r1 kernel stack - * SRR0/1 as at start of trap - */ -#define FRAME_SETUP(savearea) \ -/* Have to enable translation to allow access of kernel stack: */ \ - GET_CPUINFO(%r31); \ - mfsrr0 %r30; \ - stw %r30,(savearea+CPUSAVE_SRR0)(%r31); /* save SRR0 */ \ - mfsrr1 %r30; \ - stw %r30,(savearea+CPUSAVE_SRR1)(%r31); /* save SRR1 */ \ - mfmsr %r30; \ - ori %r30,%r30,(PSL_DR|PSL_IR|PSL_RI)@l; /* relocation on */ \ - mtmsr %r30; /* stack can now be accessed */ \ - isync; \ - mfsprg1 %r31; /* get saved SP */ \ - stwu %r31,-FRAMELEN(%r1); /* save it in the callframe */ \ - stw %r0, FRAME_0+8(%r1); /* save r0 in the trapframe */ \ - stw %r31,FRAME_1+8(%r1); /* save SP " " */ \ - stw %r2, FRAME_2+8(%r1); /* save r2 " " */ \ - stw %r28,FRAME_LR+8(%r1); /* save LR " " */ \ - stw %r29,FRAME_CR+8(%r1); /* save CR " " */ \ - GET_CPUINFO(%r2); \ - lwz %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */ \ - lwz %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */ \ - lwz %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */ \ - lwz %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */ \ - stw %r3, FRAME_3+8(%r1); /* save r3-r31 */ \ - stw %r4, FRAME_4+8(%r1); \ - stw %r5, FRAME_5+8(%r1); \ - stw %r6, FRAME_6+8(%r1); \ - stw %r7, FRAME_7+8(%r1); \ - stw %r8, FRAME_8+8(%r1); \ - stw %r9, FRAME_9+8(%r1); \ - stw %r10, FRAME_10+8(%r1); \ - stw %r11, FRAME_11+8(%r1); \ - stw %r12, FRAME_12+8(%r1); \ - stw %r13, FRAME_13+8(%r1); \ - stw %r14, FRAME_14+8(%r1); \ - stw %r15, FRAME_15+8(%r1); \ - stw %r16, FRAME_16+8(%r1); \ - stw %r17, FRAME_17+8(%r1); \ - stw %r18, FRAME_18+8(%r1); \ - stw %r19, FRAME_19+8(%r1); \ - stw %r20, FRAME_20+8(%r1); \ - stw %r21, FRAME_21+8(%r1); \ - stw %r22, FRAME_22+8(%r1); \ - stw %r23, FRAME_23+8(%r1); \ - stw %r24, FRAME_24+8(%r1); \ - stw %r25, FRAME_25+8(%r1); \ - stw %r26, FRAME_26+8(%r1); \ - stw %r27, FRAME_27+8(%r1); \ - stw %r28, FRAME_28+8(%r1); \ - stw %r29, FRAME_29+8(%r1); \ - stw %r30, FRAME_30+8(%r1); \ - stw %r31, FRAME_31+8(%r1); \ - lwz %r28,(savearea+CPUSAVE_AIM_DAR)(%r2); /* saved DAR */ \ - lwz %r29,(savearea+CPUSAVE_AIM_DSISR)(%r2);/* saved DSISR */\ - lwz %r30,(savearea+CPUSAVE_SRR0)(%r2); /* saved SRR0 */ \ - lwz %r31,(savearea+CPUSAVE_SRR1)(%r2); /* saved SRR1 */ \ - mfxer %r3; \ - mfctr %r4; \ - mfsprg3 %r5; \ - stw %r3, FRAME_XER+8(1); /* save xer/ctr/exc */ \ - stw %r4, FRAME_CTR+8(1); \ - stw %r5, FRAME_EXC+8(1); \ - stw %r28,FRAME_AIM_DAR+8(1); \ - stw %r29,FRAME_AIM_DSISR+8(1); /* save dsisr/srr0/srr1 */ \ - stw %r30,FRAME_SRR0+8(1); \ - stw %r31,FRAME_SRR1+8(1) - -#define FRAME_LEAVE(savearea) \ -/* Now restore regs: */ \ - lwz %r2,FRAME_SRR0+8(%r1); \ - lwz %r3,FRAME_SRR1+8(%r1); \ - lwz %r4,FRAME_CTR+8(%r1); \ - lwz %r5,FRAME_XER+8(%r1); \ - lwz %r6,FRAME_LR+8(%r1); \ - GET_CPUINFO(%r7); \ - stw %r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */ \ - stw %r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */ \ - lwz %r7,FRAME_CR+8(%r1); \ - mtctr %r4; \ - mtxer %r5; \ - mtlr %r6; \ - mtsprg1 %r7; /* save cr */ \ - lwz %r31,FRAME_31+8(%r1); /* restore r0-31 */ \ - lwz %r30,FRAME_30+8(%r1); \ - lwz %r29,FRAME_29+8(%r1); \ - lwz %r28,FRAME_28+8(%r1); \ - lwz %r27,FRAME_27+8(%r1); \ - lwz %r26,FRAME_26+8(%r1); \ - lwz %r25,FRAME_25+8(%r1); \ - lwz %r24,FRAME_24+8(%r1); \ - lwz %r23,FRAME_23+8(%r1); \ - lwz %r22,FRAME_22+8(%r1); \ - lwz %r21,FRAME_21+8(%r1); \ - lwz %r20,FRAME_20+8(%r1); \ - lwz %r19,FRAME_19+8(%r1); \ - lwz %r18,FRAME_18+8(%r1); \ - lwz %r17,FRAME_17+8(%r1); \ - lwz %r16,FRAME_16+8(%r1); \ - lwz %r15,FRAME_15+8(%r1); \ - lwz %r14,FRAME_14+8(%r1); \ - lwz %r13,FRAME_13+8(%r1); \ - lwz %r12,FRAME_12+8(%r1); \ - lwz %r11,FRAME_11+8(%r1); \ - lwz %r10,FRAME_10+8(%r1); \ - lwz %r9, FRAME_9+8(%r1); \ - lwz %r8, FRAME_8+8(%r1); \ - lwz %r7, FRAME_7+8(%r1); \ - lwz %r6, FRAME_6+8(%r1); \ - lwz %r5, FRAME_5+8(%r1); \ - lwz %r4, FRAME_4+8(%r1); \ - lwz %r3, FRAME_3+8(%r1); \ - lwz %r2, FRAME_2+8(%r1); \ - lwz %r0, FRAME_0+8(%r1); \ - lwz %r1, FRAME_1+8(%r1); \ -/* Can't touch %r1 from here on */ \ - mtsprg2 %r2; /* save r2 & r3 */ \ - mtsprg3 %r3; \ -/* Disable translation, machine check and recoverability: */ \ - mfmsr %r2; \ - andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_EE|PSL_ME|PSL_RI)@l; \ - mtmsr %r2; \ - isync; \ -/* Decide whether we return to user mode: */ \ - GET_CPUINFO(%r2); \ - lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); \ - mtcr %r3; \ - bf 17,1f; /* branch if PSL_PR is false */ \ -/* Restore user SRs */ \ - RESTORE_USER_SRS(%r2,%r3); \ -1: mfsprg1 %r2; /* restore cr */ \ - mtcr %r2; \ - GET_CPUINFO(%r2); \ - lwz %r3,(savearea+CPUSAVE_SRR0)(%r2); /* restore srr0 */ \ - mtsrr0 %r3; \ - lwz %r3,(savearea+CPUSAVE_SRR1)(%r2); /* restore srr1 */ \ - \ - /* Make sure HV bit of MSR propagated to SRR1 */ \ - mfmsr %r2; \ - or %r3,%r2,%r3; \ - \ - mtsrr1 %r3; \ - mfsprg2 %r2; /* restore r2 & r3 */ \ - mfsprg3 %r3 - -/* - * The next two routines are 64-bit glue code. The first is used to test if - * we are on a 64-bit system. By copying it to the illegal instruction - * handler, we can test for 64-bit mode by trying to execute a 64-bit - * instruction and seeing what happens. The second gets copied in front - * of all the other handlers to restore 32-bit bridge mode when traps - * are taken. - */ - -/* 64-bit test code. Sets SPRG2 to 0 if an illegal instruction is executed */ - - .globl CNAME(testppc64),CNAME(testppc64size) -CNAME(testppc64): - mtsprg1 %r31 - mfsrr0 %r31 - addi %r31, %r31, 4 - mtsrr0 %r31 - - li %r31, 0 - mtsprg2 %r31 - mfsprg1 %r31 - - rfi -CNAME(testppc64size) = .-CNAME(testppc64) - - -/* 64-bit bridge mode restore snippet. Gets copied in front of everything else - * on 64-bit systems. */ - - .globl CNAME(restorebridge),CNAME(restorebridgesize) -CNAME(restorebridge): - mtsprg1 %r31 - mfmsr %r31 - clrldi %r31,%r31,1 - mtmsrd %r31 - mfsprg1 %r31 - isync -CNAME(restorebridgesize) = .-CNAME(restorebridge) - -#ifdef SMP -/* - * Processor reset exception handler. These are typically - * the first instructions the processor executes after a - * software reset. We do this in two bits so that we are - * not still hanging around in the trap handling region - * once the MMU is turned on. - */ - .globl CNAME(rstcode), CNAME(rstsize) -CNAME(rstcode): - ba cpu_reset -CNAME(rstsize) = . - CNAME(rstcode) - -cpu_reset: - bl 1f - - .space 124 - -1: - mflr %r1 - addi %r1,%r1,(124-16)@l - - lis %r3,1@l - bla CNAME(pmap_cpu_bootstrap) - bla CNAME(cpudep_ap_bootstrap) - mr %r1,%r3 - bla CNAME(machdep_ap_bootstrap) - - /* Should not be reached */ -9: - b 9b -#endif - -/* - * This code gets copied to all the trap vectors - * (except ISI/DSI, ALI, and the interrupts) - */ - - .globl CNAME(trapcode),CNAME(trapsize) -CNAME(trapcode): - mtsprg1 %r1 /* save SP */ - mflr %r1 /* Save the old LR in r1 */ - mtsprg2 %r1 /* And then in SPRG2 */ - li %r1, 0x20 /* How to get the vector from LR */ - bla generictrap /* LR & SPRG3 is exception # */ -CNAME(trapsize) = .-CNAME(trapcode) - -/* - * 64-bit version of trapcode. Identical, except it calls generictrap64. - */ - .globl CNAME(trapcode64) -CNAME(trapcode64): - mtsprg1 %r1 /* save SP */ - mflr %r1 /* Save the old LR in r1 */ - mtsprg2 %r1 /* And then in SPRG2 */ - li %r1, 0x20 /* How to get the vector from LR */ - bla generictrap64 /* LR & SPRG3 is exception # */ - -/* - * For ALI: has to save DSISR and DAR - */ - .globl CNAME(alitrap),CNAME(alisize) -CNAME(alitrap): - mtsprg1 %r1 /* save SP */ - GET_CPUINFO(%r1) - stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */ - stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1) - stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1) - mfdar %r30 - mfdsisr %r31 - stw %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1) - mfsprg1 %r1 /* restore SP, in case of branch */ - mflr %r28 /* save LR */ - mfcr %r29 /* save CR */ - - /* Put our exception vector in SPRG3 */ - li %r31, EXC_ALI - mtsprg3 %r31 - - /* Test whether we already had PR set */ - mfsrr1 %r31 - mtcr %r31 - bla s_trap -CNAME(alisize) = .-CNAME(alitrap) - -/* - * Similar to the above for DSI - * Has to handle BAT spills - * and standard pagetable spills - */ - .globl CNAME(dsitrap),CNAME(dsisize) -CNAME(dsitrap): - mtsprg1 %r1 /* save SP */ - GET_CPUINFO(%r1) - stw %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */ - stw %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1) - stw %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) - stw %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) - mfsprg1 %r1 /* restore SP */ - mfcr %r29 /* save CR */ - mfxer %r30 /* save XER */ - mtsprg2 %r30 /* in SPRG2 */ - mfsrr1 %r31 /* test kernel mode */ - mtcr %r31 - bt 17,1f /* branch if PSL_PR is set */ - mfdar %r31 /* get fault address */ - rlwinm %r31,%r31,7,25,28 /* get segment * 8 */ - - /* get batu */ - addis %r31,%r31,CNAME(battable)@ha - lwz %r30,CNAME(battable)@l(31) - mtcr %r30 - bf 30,1f /* branch if supervisor valid is - false */ - /* get batl */ - lwz %r31,CNAME(battable)+4@l(31) -/* We randomly use the highest two bat registers here */ - mftb %r28 - andi. %r28,%r28,1 - bne 2f - mtdbatu 2,%r30 - mtdbatl 2,%r31 - b 3f -2: - mtdbatu 3,%r30 - mtdbatl 3,%r31 -3: - mfsprg2 %r30 /* restore XER */ - mtxer %r30 - mtcr %r29 /* restore CR */ - mtsprg1 %r1 - GET_CPUINFO(%r1) - lwz %r28,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* restore r28-r31 */ - lwz %r29,(PC_DISISAVE+CPUSAVE_R29)(%r1) - lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) - lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) - mfsprg1 %r1 - rfi /* return to trapped code */ -1: - mflr %r28 /* save LR (SP already saved) */ - bla disitrap -CNAME(dsisize) = .-CNAME(dsitrap) - -/* - * Preamble code for DSI/ISI traps - */ -disitrap: - /* Write the trap vector to SPRG3 by computing LR & 0xff00 */ - mflr %r1 - andi. %r1,%r1,0xff00 - mtsprg3 %r1 - - GET_CPUINFO(%r1) - lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1) - stw %r30,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) - lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_R29)(%r1) - lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) - stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1) - lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1) - mfdar %r30 - mfdsisr %r31 - stw %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1) - -#ifdef KDB - /* Try and detect a kernel stack overflow */ - mfsrr1 %r31 - mtcr %r31 - bt 17,realtrap /* branch is user mode */ - mfsprg1 %r31 /* get old SP */ - sub. %r30,%r31,%r30 /* SP - DAR */ - bge 1f - neg %r30,%r30 /* modulo value */ -1: cmplwi %cr0,%r30,4096 /* is DAR within a page of SP? */ - bge %cr0,realtrap /* no, too far away. */ - - /* Now convert this DSI into a DDB trap. */ - GET_CPUINFO(%r1) - lwz %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DAR)(%r1) /* get DAR */ - stw %r30,(PC_DBSAVE +CPUSAVE_AIM_DAR)(%r1) /* save DAR */ - lwz %r30,(PC_TEMPSAVE+CPUSAVE_AIM_DSISR)(%r1) /* get DSISR */ - stw %r30,(PC_DBSAVE +CPUSAVE_AIM_DSISR)(%r1) /* save DSISR */ - lwz %r30,(PC_DISISAVE+CPUSAVE_R28)(%r1) /* get r28 */ - stw %r30,(PC_DBSAVE +CPUSAVE_R28)(%r1) /* save r28 */ - lwz %r31,(PC_DISISAVE+CPUSAVE_R29)(%r1) /* get r29 */ - stw %r31,(PC_DBSAVE +CPUSAVE_R29)(%r1) /* save r29 */ - lwz %r30,(PC_DISISAVE+CPUSAVE_R30)(%r1) /* get r30 */ - stw %r30,(PC_DBSAVE +CPUSAVE_R30)(%r1) /* save r30 */ - lwz %r31,(PC_DISISAVE+CPUSAVE_R31)(%r1) /* get r31 */ - stw %r31,(PC_DBSAVE +CPUSAVE_R31)(%r1) /* save r31 */ - b dbtrap -#endif - - /* XXX need stack probe here */ -realtrap: -/* Test whether we already had PR set */ - mfsrr1 %r1 - mtcr %r1 - mfsprg1 %r1 /* restore SP (might have been - overwritten) */ - bf 17,k_trap /* branch if PSL_PR is false */ - GET_CPUINFO(%r1) - lwz %r1,PC_CURPCB(%r1) - RESTORE_KERN_SRS(%r30,%r31) /* enable kernel mapping */ - ba s_trap - -/* - * generictrap does some standard setup for trap handling to minimize - * the code that need be installed in the actual vectors. It expects - * the following conditions. - * - * R1 - Trap vector = LR & (0xff00 | R1) - * SPRG1 - Original R1 contents - * SPRG2 - Original LR - */ - -generictrap64: - mtsprg3 %r31 - mfmsr %r31 - clrldi %r31,%r31,1 - mtmsrd %r31 - mfsprg3 %r31 - isync - -generictrap: - /* Save R1 for computing the exception vector */ - mtsprg3 %r1 - - /* Save interesting registers */ - GET_CPUINFO(%r1) - stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) /* free r28-r31 */ - stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1) - stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1) - mfsprg1 %r1 /* restore SP, in case of branch */ - mfsprg2 %r28 /* save LR */ - mfcr %r29 /* save CR */ - - /* Compute the exception vector from the link register */ - mfsprg3 %r31 - ori %r31,%r31,0xff00 - mflr %r30 - and %r30,%r30,%r31 - mtsprg3 %r30 - - /* Test whether we already had PR set */ - mfsrr1 %r31 - mtcr %r31 - -s_trap: - bf 17,k_trap /* branch if PSL_PR is false */ - GET_CPUINFO(%r1) -u_trap: - lwz %r1,PC_CURPCB(%r1) - RESTORE_KERN_SRS(%r30,%r31) /* enable kernel mapping */ - -/* - * Now the common trap catching code. - */ -k_trap: - FRAME_SETUP(PC_TEMPSAVE) -/* Call C interrupt dispatcher: */ -trapagain: - addi %r3,%r1,8 - bl CNAME(powerpc_interrupt) - .globl CNAME(trapexit) /* backtrace code sentinel */ -CNAME(trapexit): - -/* Disable interrupts: */ - mfmsr %r3 - andi. %r3,%r3,~PSL_EE@l - mtmsr %r3 -/* Test AST pending: */ - lwz %r5,FRAME_SRR1+8(%r1) - mtcr %r5 - bf 17,1f /* branch if PSL_PR is false */ - - GET_CPUINFO(%r3) /* get per-CPU pointer */ - lwz %r4, PC_CURTHREAD(%r3) /* deref to get curthread */ - lwz %r4, TD_FLAGS(%r4) /* get thread flags value */ - lis %r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@h - ori %r5,%r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@l - and. %r4,%r4,%r5 - beq 1f - mfmsr %r3 /* re-enable interrupts */ - ori %r3,%r3,PSL_EE@l - mtmsr %r3 - isync - addi %r3,%r1,8 - bl CNAME(ast) - .globl CNAME(asttrapexit) /* backtrace code sentinel #2 */ -CNAME(asttrapexit): - b trapexit /* test ast ret value ? */ -1: - FRAME_LEAVE(PC_TEMPSAVE) - - .globl CNAME(rfi_patch1) /* replace rfi with rfid on ppc64 */ -CNAME(rfi_patch1): - rfi - - .globl CNAME(rfid_patch) -CNAME(rfid_patch): - rfid - -#if defined(KDB) -/* - * Deliberate entry to dbtrap - */ - .globl CNAME(breakpoint) -CNAME(breakpoint): - mtsprg1 %r1 - mfmsr %r3 - mtsrr1 %r3 - andi. %r3,%r3,~(PSL_EE|PSL_ME)@l - mtmsr %r3 /* disable interrupts */ - isync - GET_CPUINFO(%r3) - stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r3) - stw %r29,(PC_DBSAVE+CPUSAVE_R29)(%r3) - stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r3) - stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r3) - mflr %r28 - li %r29,EXC_BPT - mtlr %r29 - mfcr %r29 - mtsrr0 %r28 - -/* - * Now the kdb trap catching code. - */ -dbtrap: - /* Write the trap vector to SPRG3 by computing LR & 0xff00 */ - mflr %r1 - andi. %r1,%r1,0xff00 - mtsprg3 %r1 - - lis %r1,(tmpstk+TMPSTKSZ-16)@ha /* get new SP */ - addi %r1,%r1,(tmpstk+TMPSTKSZ-16)@l - - FRAME_SETUP(PC_DBSAVE) -/* Call C trap code: */ - addi %r3,%r1,8 - bl CNAME(db_trap_glue) - or. %r3,%r3,%r3 - bne dbleave -/* This wasn't for KDB, so switch to real trap: */ - lwz %r3,FRAME_EXC+8(%r1) /* save exception */ - GET_CPUINFO(%r4) - stw %r3,(PC_DBSAVE+CPUSAVE_R31)(%r4) - FRAME_LEAVE(PC_DBSAVE) - mtsprg1 %r1 /* prepare for entrance to realtrap */ - GET_CPUINFO(%r1) - stw %r28,(PC_TEMPSAVE+CPUSAVE_R28)(%r1) - stw %r29,(PC_TEMPSAVE+CPUSAVE_R29)(%r1) - stw %r30,(PC_TEMPSAVE+CPUSAVE_R30)(%r1) - stw %r31,(PC_TEMPSAVE+CPUSAVE_R31)(%r1) - mflr %r28 - mfcr %r29 - lwz %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) - mtsprg3 %r31 /* SPRG3 was clobbered by FRAME_LEAVE */ - mfsprg1 %r1 - b realtrap -dbleave: - FRAME_LEAVE(PC_DBSAVE) - .globl CNAME(rfi_patch2) /* replace rfi with rfid on ppc64 */ -CNAME(rfi_patch2): - rfi - -/* - * In case of KDB we want a separate trap catcher for it - */ - .globl CNAME(dblow),CNAME(dbsize) -CNAME(dblow): - mtsprg1 %r1 /* save SP */ - mtsprg2 %r29 /* save r29 */ - mfcr %r29 /* save CR in r29 */ - mfsrr1 %r1 - mtcr %r1 - bf 17,1f /* branch if privileged */ - - /* Unprivileged case */ - mtcr %r29 /* put the condition register back */ - mfsprg2 %r29 /* ... and r29 */ - mflr %r1 /* save LR */ - mtsprg2 %r1 /* And then in SPRG2 */ - li %r1, 0 /* How to get the vector from LR */ - - bla generictrap /* and we look like a generic trap */ -1: - /* Privileged, so drop to KDB */ - GET_CPUINFO(%r1) - stw %r28,(PC_DBSAVE+CPUSAVE_R28)(%r1) /* free r28 */ - mfsprg2 %r28 /* r29 holds cr... */ - stw %r28,(PC_DBSAVE+CPUSAVE_R29)(%r1) /* free r29 */ - stw %r30,(PC_DBSAVE+CPUSAVE_R30)(%r1) /* free r30 */ - stw %r31,(PC_DBSAVE+CPUSAVE_R31)(%r1) /* free r31 */ - mflr %r28 /* save LR */ - bla dbtrap -CNAME(dbsize) = .-CNAME(dblow) -#endif /* KDB */ diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index 680de100707..e0dae3ccb42 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -49,45 +49,59 @@ * Requires that r28-r31 be scratch, with r28 initialized to the SLB cache */ -restoresrs: +/* + * User SRs are loaded through a pointer to the current pmap. + */ +restore_usersrs: + GET_CPUINFO(%r28); + ld %r28,PC_USERSLB(%r28); li %r29, 0 /* Set the counter to zero */ slbia slbmfee %r31,%r29 clrrdi %r31,%r31,28 slbie %r31 -instslb: - ld %r31, 8(%r28); /* Load SLBE */ +instuserslb: + ld %r31, 0(%r28); /* Load SLB entry pointer */ + cmpli 0, %r31, 0; /* If NULL, stop */ + beqlr; - cmpli 0, %r31, 0; /* If SLBE is not valid, get the next */ - beq nslb; - - ld %r30, 0(%r28) /* Load SLBV */ + ld %r30, 0(%r31) /* Load SLBV */ + ld %r31, 8(%r31) /* Load SLBE */ + or %r31, %r31, %r29 /* Set SLBE slot */ slbmte %r30, %r31; /* Install SLB entry */ -nslb: - addi %r28, %r28, 16; /* Advance */ + addi %r28, %r28, 8; /* Advance pointer */ addi %r29, %r29, 1; cmpli 0, %r29, 64; /* Repeat if we are not at the end */ - blt instslb; - + blt instuserslb; blr; /* - * User SRs are loaded through a pointer to the current pmap. + * Kernel SRs are loaded directly from the PCPU fields */ -#define RESTORE_USER_SRS() \ - GET_CPUINFO(%r28); \ - ld %r28,PC_USERSLB(%r28); \ - bl restoresrs; +restore_kernsrs: + GET_CPUINFO(%r28); + addi %r28,%r28,PC_KERNSLB; + li %r29, 0 /* Set the counter to zero */ -/* - * Kernel SRs are loaded directly from kernel_pmap_ - */ -#define RESTORE_KERN_SRS() \ - GET_CPUINFO(%r28); \ - addi %r28,%r28,PC_KERNSLB; \ - bl restoresrs; + slbia + slbmfee %r31,%r29 + clrrdi %r31,%r31,28 + slbie %r31 +instkernslb: + ld %r31, 8(%r28); /* Load SLBE */ + + cmpli 0, %r31, 0; /* If SLBE is not valid, stop */ + beqlr; + ld %r30, 0(%r28) /* Load SLBV */ + slbmte %r30, %r31; /* Install SLB entry */ + + addi %r28, %r28, 16; /* Advance pointer */ + addi %r29, %r29, 1; + cmpli 0, %r29, USER_SR; /* Repeat if we are not at the end */ + blt instkernslb; + blr; /* * FRAME_SETUP assumes: @@ -237,7 +251,7 @@ nslb: std %r30,(savearea+CPUSAVE_R30)(%r3); \ std %r31,(savearea+CPUSAVE_R31)(%r3); \ mflr %r27; /* preserve LR */ \ - RESTORE_USER_SRS(); /* uses r28-r31 */ \ + bl restore_usersrs; /* uses r28-r31 */ \ mtlr %r27; \ ld %r31,(savearea+CPUSAVE_R31)(%r3); \ ld %r30,(savearea+CPUSAVE_R30)(%r3); \ @@ -432,7 +446,7 @@ realtrap: ld %r1,PC_CURPCB(%r1) mr %r27,%r28 /* Save LR, r29 */ mtsprg2 %r29 - RESTORE_KERN_SRS() /* enable kernel mapping */ + bl restore_kernsrs /* enable kernel mapping */ mfsprg2 %r29 mr %r28,%r27 ba s_trap @@ -482,7 +496,7 @@ u_trap: ld %r1,PC_CURPCB(%r1) mr %r27,%r28 /* Save LR, r29 */ mtsprg2 %r29 - RESTORE_KERN_SRS() /* enable kernel mapping */ + bl restore_kernsrs /* enable kernel mapping */ mfsprg2 %r29 mr %r28,%r27 diff --git a/sys/powerpc/aim/vm_machdep.c b/sys/powerpc/aim/vm_machdep.c index 6ee03fbb8c0..d1d569fc0f8 100644 --- a/sys/powerpc/aim/vm_machdep.c +++ b/sys/powerpc/aim/vm_machdep.c @@ -237,15 +237,6 @@ cpu_exit(td) { } -/* - * Reset back to firmware. - */ -void -cpu_reset() -{ - OF_reboot(); -} - /* * Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-)) */ diff --git a/sys/powerpc/booke/clock.c b/sys/powerpc/booke/clock.c index 5b9979a8145..a50a504fa69 100644 --- a/sys/powerpc/booke/clock.c +++ b/sys/powerpc/booke/clock.c @@ -63,12 +63,14 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include +#include #include -#include #include +#include #include #include #include @@ -78,33 +80,46 @@ __FBSDID("$FreeBSD$"); /* * Initially we assume a processor with a bus frequency of 12.5 MHz. */ -u_int tickspending; -u_long ns_per_tick = 80; -static u_long ticks_per_sec = 12500000; -static long ticks_per_intr; +static int initialized = 0; +static u_long ns_per_tick = 80; +static u_long ticks_per_sec = 12500000; +static u_long *decr_counts[MAXCPU]; #define DIFF19041970 2082844800 +static int decr_et_start(struct eventtimer *et, + struct bintime *first, struct bintime *period); +static int decr_et_stop(struct eventtimer *et); static timecounter_get_t decr_get_timecount; +struct decr_state { + int mode; /* 0 - off, 1 - periodic, 2 - one-shot. */ + int32_t div; /* Periodic divisor. */ +}; +static DPCPU_DEFINE(struct decr_state, decr_state); + +static struct eventtimer decr_et; static struct timecounter decr_timecounter = { decr_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency */ - "decrementer" /* name */ + "timebase" /* name */ }; +/* + * Decrementor interrupt handler. + */ void decr_intr(struct trapframe *frame) { + struct decr_state *s = DPCPU_PTR(decr_state); - /* - * Check whether we are initialized. - */ - if (!ticks_per_intr) + if (!initialized) return; + (*decr_counts[curcpu])++; + /* * Interrupt handler must reset DIS to avoid getting another * interrupt once EE is enabled. @@ -113,14 +128,11 @@ decr_intr(struct trapframe *frame) CTR1(KTR_INTR, "%s: DEC interrupt", __func__); - if (PCPU_GET(cpuid) == 0) - hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); - else - hardclock_cpu(TRAPF_USERMODE(frame)); + if (s->mode == 2) + decr_et_stop(NULL); - statclock(TRAPF_USERMODE(frame)); - if (profprocs != 0) - profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + if (decr_et.et_active) + decr_et.et_event_cb(&decr_et, decr_et.et_arg); } void @@ -128,57 +140,129 @@ cpu_initclocks(void) { decr_tc_init(); - stathz = hz; - profhz = hz; + cpu_initclocks_bsp(); } +/* + * BSP early initialization. + */ void decr_init(void) { struct cpuref cpu; - unsigned int msr; + char buf[32]; if (platform_smp_get_bsp(&cpu) != 0) platform_smp_first_cpu(&cpu); ticks_per_sec = platform_timebase_freq(&cpu); - - msr = mfmsr(); - mtmsr(msr & ~(PSL_EE)); - ns_per_tick = 1000000000 / ticks_per_sec; - ticks_per_intr = ticks_per_sec / hz; - - mtdec(ticks_per_intr); - - mtspr(SPR_DECAR, ticks_per_intr); - mtspr(SPR_TCR, mfspr(SPR_TCR) | TCR_DIE | TCR_ARE); set_cputicker(mftb, ticks_per_sec, 0); - - mtmsr(msr); + snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); + intrcnt_add(buf, &decr_counts[curcpu]); + decr_et_stop(NULL); + initialized = 1; } #ifdef SMP +/* + * AP early initialization. + */ void decr_ap_init(void) { + char buf[32]; - /* Set auto-reload value and enable DEC interrupts in TCR */ - mtspr(SPR_DECAR, ticks_per_intr); - mtspr(SPR_TCR, mfspr(SPR_TCR) | TCR_DIE | TCR_ARE); - - CTR2(KTR_INTR, "%s: set TCR=%p", __func__, mfspr(SPR_TCR)); + snprintf(buf, sizeof(buf), "cpu%d:decrementer", curcpu); + intrcnt_add(buf, &decr_counts[curcpu]); + decr_et_stop(NULL); } #endif +/* + * Final initialization. + */ void decr_tc_init(void) { decr_timecounter.tc_frequency = ticks_per_sec; tc_init(&decr_timecounter); + decr_et.et_name = "decrementer"; + decr_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | + ET_FLAGS_PERCPU; + decr_et.et_quality = 1000; + decr_et.et_frequency = ticks_per_sec; + decr_et.et_min_period.sec = 0; + decr_et.et_min_period.frac = + ((0x00000002LLU << 32) / ticks_per_sec) << 32; + decr_et.et_max_period.sec = 0xfffffffeLLU / ticks_per_sec; + decr_et.et_max_period.frac = + ((0xfffffffeLLU << 32) / ticks_per_sec) << 32; + decr_et.et_start = decr_et_start; + decr_et.et_stop = decr_et_stop; + decr_et.et_priv = NULL; + et_register(&decr_et); } +/* + * Event timer start method. + */ +static int +decr_et_start(struct eventtimer *et, + struct bintime *first, struct bintime *period) +{ + struct decr_state *s = DPCPU_PTR(decr_state); + uint32_t fdiv, tcr; + + if (period != NULL) { + s->mode = 1; + s->div = (decr_et.et_frequency * (period->frac >> 32)) >> 32; + if (period->sec != 0) + s->div += decr_et.et_frequency * period->sec; + } else { + s->mode = 2; + s->div = 0xffffffff; + } + if (first != NULL) { + fdiv = (decr_et.et_frequency * (first->frac >> 32)) >> 32; + if (first->sec != 0) + fdiv += decr_et.et_frequency * first->sec; + } else + fdiv = s->div; + + tcr = mfspr(SPR_TCR); + tcr |= TCR_DIE; + if (s->mode == 1) { + mtspr(SPR_DECAR, s->div); + tcr |= TCR_ARE; + } else + tcr &= ~TCR_ARE; + mtdec(fdiv); + mtspr(SPR_TCR, tcr); + return (0); +} + +/* + * Event timer stop method. + */ +static int +decr_et_stop(struct eventtimer *et) +{ + struct decr_state *s = DPCPU_PTR(decr_state); + uint32_t tcr; + + s->mode = 0; + s->div = 0xffffffff; + tcr = mfspr(SPR_TCR); + tcr &= ~(TCR_DIE | TCR_ARE); + mtspr(SPR_TCR, tcr); + return (0); +} + +/* + * Timecounter get method. + */ static unsigned decr_get_timecount(struct timecounter *tc) { @@ -203,18 +287,3 @@ DELAY(int n) } while (now < end || (now > start && end < start)); } -/* - * Nothing to do. - */ -void -cpu_startprofclock(void) -{ - - /* Do nothing */ -} - -void -cpu_stopprofclock(void) -{ - -} diff --git a/sys/powerpc/booke/interrupt.c b/sys/powerpc/booke/interrupt.c index 1626a8fbd27..c0bdee1e96c 100644 --- a/sys/powerpc/booke/interrupt.c +++ b/sys/powerpc/booke/interrupt.c @@ -116,11 +116,15 @@ void powerpc_decr_interrupt(struct trapframe *framep) { struct thread *td; + struct trapframe *oldframe; td = PCPU_GET(curthread); critical_enter(); atomic_add_int(&td->td_intr_nesting_level, 1); + oldframe = td->td_intr_frame; + td->td_intr_frame = framep; decr_intr(framep); + td->td_intr_frame = oldframe; atomic_subtract_int(&td->td_intr_nesting_level, 1); critical_exit(); framep->srr1 &= ~PSL_WE; diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c index c725dd85bf3..c4b80cc665e 100644 --- a/sys/powerpc/booke/machdep.c +++ b/sys/powerpc/booke/machdep.c @@ -488,9 +488,21 @@ cpu_idle (int busy) } #endif + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d", + busy, curcpu); + if (!busy) { + critical_enter(); + cpu_idleclock(); + } /* Freescale E500 core RM section 6.4.1. */ msr = msr | PSL_WE; __asm __volatile("msync; mtmsr %0; isync" :: "r" (msr)); + if (!busy) { + cpu_activeclock(); + critical_exit(); + } + CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done", + busy, curcpu); } int diff --git a/sys/powerpc/booke/platform_bare.c b/sys/powerpc/booke/platform_bare.c index 627470d6cce..c569d751f0b 100644 --- a/sys/powerpc/booke/platform_bare.c +++ b/sys/powerpc/booke/platform_bare.c @@ -70,6 +70,8 @@ static int bare_smp_next_cpu(platform_t, struct cpuref *cpuref); static int bare_smp_get_bsp(platform_t, struct cpuref *cpuref); static int bare_smp_start_cpu(platform_t, struct pcpu *cpu); +static void e500_reset(platform_t); + static platform_method_t bare_methods[] = { PLATFORMMETHOD(platform_probe, bare_probe), PLATFORMMETHOD(platform_mem_regions, bare_mem_regions), @@ -80,6 +82,8 @@ static platform_method_t bare_methods[] = { PLATFORMMETHOD(platform_smp_get_bsp, bare_smp_get_bsp), PLATFORMMETHOD(platform_smp_start_cpu, bare_smp_start_cpu), + PLATFORMMETHOD(platform_reset, e500_reset), + { 0, 0 } }; @@ -260,3 +264,30 @@ bare_smp_start_cpu(platform_t plat, struct pcpu *pc) return (ENXIO); #endif } + +static void +e500_reset(platform_t plat) +{ + uint32_t ver = SVR_VER(mfspr(SPR_SVR)); + + if (ver == SVR_MPC8572E || ver == SVR_MPC8572 || + ver == SVR_MPC8548E || ver == SVR_MPC8548) + /* Systems with dedicated reset register */ + ccsr_write4(OCP85XX_RSTCR, 2); + else { + /* Clear DBCR0, disables debug interrupts and events. */ + mtspr(SPR_DBCR0, 0); + __asm __volatile("isync"); + + /* Enable Debug Interrupts in MSR. */ + mtmsr(mfmsr() | PSL_DE); + + /* Enable debug interrupts and issue reset. */ + mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | + DBCR0_RST_SYSTEM); + } + + printf("Reset failed...\n"); + while (1); +} + diff --git a/sys/powerpc/booke/pmap.c b/sys/powerpc/booke/pmap.c index 7f2feb947dc..c5e285c8f72 100644 --- a/sys/powerpc/booke/pmap.c +++ b/sys/powerpc/booke/pmap.c @@ -384,12 +384,7 @@ static mmu_method_t mmu_booke_methods[] = { { 0, 0 } }; -static mmu_def_t booke_mmu = { - MMU_TYPE_BOOKE, - mmu_booke_methods, - 0 -}; -MMU_DEF(booke_mmu); +MMU_DEF(booke_mmu, MMU_TYPE_BOOKE, mmu_booke_methods, 0); static inline void tlb_miss_lock(void) diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c index 93dc597e3e1..a2d0d7037b1 100644 --- a/sys/powerpc/booke/trap.c +++ b/sys/powerpc/booke/trap.c @@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$"); #include "opt_fpu_emu.h" -#include "opt_ktrace.h" #include #include @@ -51,9 +50,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#endif #include #include diff --git a/sys/powerpc/conf/GENERIC b/sys/powerpc/conf/GENERIC index 891d9aa4ad8..c23e9acdcd3 100644 --- a/sys/powerpc/conf/GENERIC +++ b/sys/powerpc/conf/GENERIC @@ -60,7 +60,6 @@ options STACK #stack(9) support options SYSVSHM #SYSV-style shared memory options SYSVMSG #SYSV-style message queues options SYSVSEM #SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing @@ -174,6 +173,9 @@ device sbp # SCSI over FireWire (Requires scbus and da) device fwe # Ethernet over FireWire (non-standard!) # Misc +device ds1775 # PowerMac7,2 temperature sensor +device fcu # Apple Fan Control Unit +device max6690 # PowerMac7,2 temperature sensor device powermac_nvram # Open Firmware configuration NVRAM device smu # Apple System Management Unit diff --git a/sys/powerpc/conf/GENERIC64 b/sys/powerpc/conf/GENERIC64 index 79bd1d8a065..b861e51e18b 100644 --- a/sys/powerpc/conf/GENERIC64 +++ b/sys/powerpc/conf/GENERIC64 @@ -59,7 +59,6 @@ options STACK #stack(9) support options SYSVSHM #SYSV-style shared memory options SYSVMSG #SYSV-style message queues options SYSVSEM #SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) options AUDIT # Security event auditing @@ -76,8 +75,8 @@ options WITNESS #Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones -# To make an SMP kernel, the next line is needed -#options SMP # Symmetric MultiProcessor Kernel +# Make an SMP-capable kernel by default +options SMP # Symmetric MultiProcessor Kernel # CPU frequency control device cpufreq @@ -171,6 +170,9 @@ device sbp # SCSI over FireWire (Requires scbus and da) device fwe # Ethernet over FireWire (non-standard!) # Misc +device ds1775 # PowerMac7,2 temperature sensor +device fcu # Apple Fan Control Unit +device max6690 # PowerMac7,2 temperature sensor device powermac_nvram # Open Firmware configuration NVRAM device smu # Apple System Management Unit diff --git a/sys/powerpc/conf/Makefile b/sys/powerpc/conf/Makefile index 562bc4693cd..f6652381004 100644 --- a/sys/powerpc/conf/Makefile +++ b/sys/powerpc/conf/Makefile @@ -1,5 +1,8 @@ # $FreeBSD$ TARGET=powerpc +.if ${MACHINE_ARCH} == powerpc || ${MACHINE_ARCH} == powerpc64 +TARGET_ARCH?=${MACHINE_ARCH} +.endif .include "${.CURDIR}/../../conf/makeLINT.mk" diff --git a/sys/powerpc/conf/NOTES b/sys/powerpc/conf/NOTES index f3b19eae6c6..7248eabcd2f 100644 --- a/sys/powerpc/conf/NOTES +++ b/sys/powerpc/conf/NOTES @@ -8,7 +8,8 @@ ##################################################################### # CPU OPTIONS -machine powerpc powerpc +# You must specify a machine directive to choose powerpc or powerpc64 +#machine powerpc powerpc[64] # # You must specify at least one CPU (the one you intend to run on). @@ -35,6 +36,9 @@ device kiic # Apple Keywest I2C Controller device ofwd # Open Firmware disks device adb # Apple Desktop Bus device cuda # VIA-CUDA ADB interface +device ds1775 # PowerMac7,2 temperature sensor +device fcu # Apple Fan Control Unit +device max6690 # PowerMac7,2 temperature sensor device pmu # Apple Power Management Unit device smu # Apple System Management Unit device snd_ai2s # Apple I2S Audio @@ -44,6 +48,7 @@ device snd_davbus # Apple Davbus Audio ##################################################################### # Devices we don't want to deal with +nodevice bktr nodevice fdc nodevice ppc nodevice splash diff --git a/sys/powerpc/include/altivec.h b/sys/powerpc/include/altivec.h index ba16a0bd19f..9a6c5d31bad 100644 --- a/sys/powerpc/include/altivec.h +++ b/sys/powerpc/include/altivec.h @@ -29,6 +29,9 @@ #ifndef _MACHINE_ALTIVEC_H_ #define _MACHINE_ALTIVEC_H_ +#define ALTIVEC_VSCR_NJ 0x00010000 /* Enable non-Java mode */ +#define ALTIVEC_VSCR_SAT 0x00000001 /* Saturation status bit */ + void enable_vec(struct thread *); void save_vec(struct thread *); diff --git a/sys/powerpc/include/elf.h b/sys/powerpc/include/elf.h index 25c25063f9f..e1a5bc8c864 100644 --- a/sys/powerpc/include/elf.h +++ b/sys/powerpc/include/elf.h @@ -99,8 +99,14 @@ __ElfType(Auxinfo); #define AT_ICACHEBSIZE 11 /* Instruction cache block size for the uP. */ #define AT_UCACHEBSIZE 12 /* Cache block size, or `0' if cache not unified. */ #define AT_EXECPATH 13 /* Path to the executable. */ +#define AT_CANARY 14 /* Canary for SSP */ +#define AT_CANARYLEN 15 /* Length of the canary. */ +#define AT_OSRELDATE 16 /* OSRELDATE. */ +#define AT_NCPUS 17 /* Number of CPUs. */ +#define AT_PAGESIZES 18 /* Pagesizes. */ +#define AT_PAGESIZESLEN 19 /* Number of pagesizes. */ -#define AT_COUNT 14 /* Count of defined aux entry types. */ +#define AT_COUNT 20 /* Count of defined aux entry types. */ /* * Relocation types. diff --git a/sys/powerpc/include/intr_machdep.h b/sys/powerpc/include/intr_machdep.h index 5a0e04ad812..67d7e796f9b 100644 --- a/sys/powerpc/include/intr_machdep.h +++ b/sys/powerpc/include/intr_machdep.h @@ -48,6 +48,8 @@ struct trapframe; driver_filter_t powerpc_ipi_handler; +void intrcnt_add(const char *name, u_long **countp); + void powerpc_register_pic(device_t, u_int); int powerpc_ign_lookup(uint32_t pic_id); diff --git a/sys/powerpc/include/md_var.h b/sys/powerpc/include/md_var.h index 65c952a027f..a90967a3e41 100644 --- a/sys/powerpc/include/md_var.h +++ b/sys/powerpc/include/md_var.h @@ -47,8 +47,6 @@ extern int busdma_swi_pending; extern vm_offset_t kstack0; extern vm_offset_t kstack0_phys; -extern u_long ns_per_tick; - extern int powerpc_pow_enabled; extern int cacheline_size; extern int hw_direct_map; diff --git a/sys/powerpc/include/memdev.h b/sys/powerpc/include/memdev.h index 584eb4c8364..97000c951b2 100644 --- a/sys/powerpc/include/memdev.h +++ b/sys/powerpc/include/memdev.h @@ -31,7 +31,7 @@ d_open_t memopen; d_read_t memrw; -#define memioctl (d_ioctl_t *)NULL +d_ioctl_t memioctl; d_mmap_t memmmap; void dev_mem_md_init(void); diff --git a/sys/powerpc/include/mmuvar.h b/sys/powerpc/include/mmuvar.h index 6e5a213536b..821a49774d5 100644 --- a/sys/powerpc/include/mmuvar.h +++ b/sys/powerpc/include/mmuvar.h @@ -31,7 +31,8 @@ /* * A PowerPC MMU implementation is declared with a kernel object and - * an associated method table, similar to a device driver. + * an associated method table. The MMU_DEF macro is used to declare + * the class, and also links it to the global MMU class list. * * e.g. * @@ -44,13 +45,12 @@ * { 0, 0 } * }; * - * static mmu_def_t ppc8xx_mmu = { - * "ppc8xx", - * ppc8xx_methods, - * sizeof(ppc8xx_mmu_softc), // or 0 if no softc - * }; + * MMU_DEF(ppc8xx, MMU_TYPE_8xx, ppc8xx_methods, sizeof(ppc8xx_mmu_softc)); * - * MMU_DEF(ppc8xx_mmu); + * A single level of inheritance is supported in a similar fashion to + * kobj inheritance e.g. + * + * MMU_DEF_1(ppc860c, MMU_TYPE_860c, ppc860c_methods, 0, ppc8xx); */ #include @@ -84,7 +84,29 @@ typedef struct kobj_class mmu_def_t; #define MMUMETHOD KOBJMETHOD -#define MMU_DEF(name) DATA_SET(mmu_set, name) +#define MMU_DEF(name, ident, methods, size) \ + \ +mmu_def_t name = { \ + ident, methods, size, NULL \ +}; \ +DATA_SET(mmu_set, name) + +#define MMU_DEF_INHERIT(name, ident, methods, size, base1) \ + \ +static kobj_class_t name ## _baseclasses[] = \ + { &base1, NULL }; \ +mmu_def_t name = { \ + ident, methods, size, name ## _baseclasses \ +}; \ +DATA_SET(mmu_set, name) + + +#if 0 +mmu_def_t name = { \ + ident, methods, size, name ## _baseclasses \ +}; +DATA_SET(mmu_set, name) +#endif /* * Known MMU names diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index bf79224795c..612b45b4bc1 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -43,7 +43,6 @@ void OF_getetheraddr(device_t dev, u_char *addr); void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)); boolean_t OF_bootstrap(void); -void OF_halt(void); void OF_reboot(void); void ofw_mem_regions(struct mem_region **, int *, struct mem_region **, int *); diff --git a/sys/powerpc/include/param.h b/sys/powerpc/include/param.h index 91bb238dd51..d71d0483bd0 100644 --- a/sys/powerpc/include/param.h +++ b/sys/powerpc/include/param.h @@ -68,7 +68,7 @@ #endif #if defined(SMP) || defined(KLD_MODULE) -#define MAXCPU 2 +#define MAXCPU 4 #else #define MAXCPU 1 #endif /* SMP || KLD_MODULE */ diff --git a/sys/powerpc/include/pcb.h b/sys/powerpc/include/pcb.h index b30b4196816..a037276cf1b 100644 --- a/sys/powerpc/include/pcb.h +++ b/sys/powerpc/include/pcb.h @@ -59,13 +59,14 @@ struct pcb { uint32_t vr[32][4]; register_t vrsave; register_t spare[2]; - register_t vscr; + register_t vscr; /* aligned at vector element 3 */ } pcb_vec __aligned(16); /* Vector processor */ unsigned int pcb_veccpu; /* which CPU had our vector stuff. */ union { struct { + vm_offset_t usr_segm; /* Base address */ register_t usr_esid; /* USER_SR segment */ register_t usr_vsid; /* USER_SR segment */ } aim; diff --git a/sys/powerpc/include/pcpu.h b/sys/powerpc/include/pcpu.h index 0d29b506fc9..949bbf39133 100644 --- a/sys/powerpc/include/pcpu.h +++ b/sys/powerpc/include/pcpu.h @@ -55,7 +55,7 @@ struct pmap; #define PCPU_MD_AIM64_FIELDS \ struct slb pc_slb[64]; \ - struct slb *pc_userslb; + struct slb **pc_userslb; #ifdef __powerpc64__ #define PCPU_MD_AIM_FIELDS PCPU_MD_AIM64_FIELDS diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h index 453964fcc4c..c030416235e 100644 --- a/sys/powerpc/include/pmap.h +++ b/sys/powerpc/include/pmap.h @@ -86,16 +86,15 @@ struct pmap_md { #define NPMAPS 32768 #endif /* !defined(NPMAPS) */ -struct slbcontainer; - -SPLAY_HEAD(slb_tree, slbcontainer); +struct slbtnode; struct pmap { struct mtx pm_mtx; #ifdef __powerpc64__ - struct slb_tree pm_slbtree; - struct slb *pm_slb; + struct slbtnode *pm_slb_tree_root; + struct slb **pm_slb; + int pm_slb_len; #else register_t pm_sr[16]; #endif @@ -123,13 +122,13 @@ struct pvo_entry { LIST_HEAD(pvo_head, pvo_entry); struct md_page { - u_int64_t mdpg_attrs; + u_int64_t mdpg_attrs; + vm_memattr_t mdpg_cache_attrs; struct pvo_head mdpg_pvoh; }; -#define pmap_page_get_memattr(m) VM_MEMATTR_DEFAULT +#define pmap_page_get_memattr(m) ((m)->md.mdpg_cache_attrs) #define pmap_page_is_mapped(m) (!LIST_EMPTY(&(m)->md.mdpg_pvoh)) -#define pmap_page_set_memattr(m, ma) (void)0 /* * Return the VSID corresponding to a given virtual address. @@ -139,14 +138,20 @@ struct md_page { * NB: The PMAP MUST be locked already. */ uint64_t va_to_vsid(pmap_t pm, vm_offset_t va); -int va_to_slb_entry(pmap_t pm, vm_offset_t va, struct slb *); -uint64_t allocate_vsid(pmap_t pm, uint64_t esid, int large); -void slb_insert(pmap_t pm, struct slb *dst, struct slb *); -int vsid_to_esid(pmap_t pm, uint64_t vsid, uint64_t *esid); -void free_vsids(pmap_t pm); -struct slb *slb_alloc_user_cache(void); -void slb_free_user_cache(struct slb *); +/* Lock-free, non-allocating lookup routines */ +uint64_t kernel_va_to_slbv(vm_offset_t va); +struct slb *user_va_to_slb_entry(pmap_t pm, vm_offset_t va); + +uint64_t allocate_user_vsid(pmap_t pm, uint64_t esid, int large); +void free_vsid(pmap_t pm, uint64_t esid, int large); +void slb_insert_user(pmap_t pm, struct slb *slb); +void slb_insert_kernel(uint64_t slbe, uint64_t slbv); + +struct slbtnode *slb_alloc_tree(void); +void slb_free_tree(pmap_t pm); +struct slb **slb_alloc_user_cache(void); +void slb_free_user_cache(struct slb **); #else @@ -182,7 +187,6 @@ struct md_page { #define pmap_page_get_memattr(m) VM_MEMATTR_DEFAULT #define pmap_page_is_mapped(m) (!TAILQ_EMPTY(&(m)->md.pv_list)) -#define pmap_page_set_memattr(m, ma) (void)0 #endif /* AIM */ @@ -204,9 +208,12 @@ extern struct pmap kernel_pmap_store; void pmap_bootstrap(vm_offset_t, vm_offset_t); void pmap_kenter(vm_offset_t va, vm_offset_t pa); +void pmap_kenter_attr(vm_offset_t va, vm_offset_t pa, vm_memattr_t); void pmap_kremove(vm_offset_t); void *pmap_mapdev(vm_offset_t, vm_size_t); +void *pmap_mapdev_attr(vm_offset_t, vm_size_t, vm_memattr_t); void pmap_unmapdev(vm_offset_t, vm_size_t); +void pmap_page_set_memattr(vm_page_t, vm_memattr_t); void pmap_deactivate(struct thread *); vm_offset_t pmap_kextract(vm_offset_t); int pmap_dev_direct_mapped(vm_offset_t, vm_size_t); diff --git a/sys/powerpc/include/smp.h b/sys/powerpc/include/smp.h index 64d13dbdd7b..cf952788c68 100644 --- a/sys/powerpc/include/smp.h +++ b/sys/powerpc/include/smp.h @@ -36,6 +36,7 @@ #define IPI_RENDEZVOUS 2 #define IPI_STOP 3 #define IPI_STOP_HARD 3 +#define IPI_HARDCLOCK 4 #ifndef LOCORE diff --git a/sys/powerpc/include/sr.h b/sys/powerpc/include/sr.h index ae66314de6d..ed9801a2891 100644 --- a/sys/powerpc/include/sr.h +++ b/sys/powerpc/include/sr.h @@ -42,7 +42,11 @@ #define SR_VSID_MASK 0x00ffffff /* Virtual Segment ID mask */ /* Kernel segment register usage */ +#ifdef __powerpc64__ +#define USER_SR 63 +#else #define USER_SR 12 +#endif #define KERNEL_SR 13 #define KERNEL2_SR 14 #define KERNEL3_SR 15 diff --git a/sys/powerpc/include/trap_aim.h b/sys/powerpc/include/trap_aim.h index 8370f56f3c7..afb77db1e75 100644 --- a/sys/powerpc/include/trap_aim.h +++ b/sys/powerpc/include/trap_aim.h @@ -54,9 +54,12 @@ /* The following is only available on the 601: */ #define EXC_RUNMODETRC 0x2000 /* Run Mode/Trace Exception */ +/* The following are only available on 970(G5): */ +#define EXC_VECAST_G5 0x1700 /* AltiVec Assist */ + /* The following are only available on 7400(G4): */ #define EXC_VEC 0x0f20 /* AltiVec Unavailable */ -#define EXC_VECAST 0x1600 /* AltiVec Assist */ +#define EXC_VECAST_G4 0x1600 /* AltiVec Assist */ /* The following are only available on 604/750/7400: */ #define EXC_PERF 0x0f00 /* Performance Monitoring */ diff --git a/sys/powerpc/include/vm.h b/sys/powerpc/include/vm.h index f8f77f0088a..4c4d7cf8557 100644 --- a/sys/powerpc/include/vm.h +++ b/sys/powerpc/include/vm.h @@ -32,11 +32,13 @@ #include /* Memory attributes. */ -#define VM_MEMATTR_CACHING_INHIBIT ((vm_memattr_t)PTE_I) -#define VM_MEMATTR_GUARD ((vm_memattr_t)PTE_G) -#define VM_MEMATTR_MEMORY_COHERENCE ((vm_memattr_t)PTE_M) -#define VM_MEMATTR_WRITE_THROUGH ((vm_memattr_t)PTE_W) - #define VM_MEMATTR_DEFAULT 0 +#define VM_MEMATTR_UNCACHEABLE 0x01 +#define VM_MEMATTR_UNCACHED VM_MEMATTR_UNCACHEABLE +#define VM_MEMATTR_CACHEABLE 0x02 +#define VM_MEMATTR_WRITE_COMBINING 0x04 +#define VM_MEMATTR_WRITE_BACK 0x08 +#define VM_MEMATTR_WRITE_THROUGH 0x10 +#define VM_MEMATTR_PREFETCHABLE 0x20 #endif /* !_MACHINE_VM_H_ */ diff --git a/sys/powerpc/mpc85xx/mpc85xx.c b/sys/powerpc/mpc85xx/mpc85xx.c index 75304496d2f..564bf84b877 100644 --- a/sys/powerpc/mpc85xx/mpc85xx.c +++ b/sys/powerpc/mpc85xx/mpc85xx.c @@ -164,28 +164,3 @@ law_pci_target(struct resource *res, int *trgt_mem, int *trgt_io) return (rv); } -void -cpu_reset(void) -{ - uint32_t ver = SVR_VER(mfspr(SPR_SVR)); - - if (ver == SVR_MPC8572E || ver == SVR_MPC8572 || - ver == SVR_MPC8548E || ver == SVR_MPC8548) - /* Systems with dedicated reset register */ - ccsr_write4(OCP85XX_RSTCR, 2); - else { - /* Clear DBCR0, disables debug interrupts and events. */ - mtspr(SPR_DBCR0, 0); - __asm __volatile("isync"); - - /* Enable Debug Interrupts in MSR. */ - mtmsr(mfmsr() | PSL_DE); - - /* Enable debug interrupts and issue reset. */ - mtspr(SPR_DBCR0, mfspr(SPR_DBCR0) | DBCR0_IDM | - DBCR0_RST_SYSTEM); - } - - printf("Reset failed...\n"); - while (1); -} diff --git a/sys/powerpc/ofw/ofw_real.c b/sys/powerpc/ofw/ofw_real.c index 8eb86b47a59..963e96cbd0c 100644 --- a/sys/powerpc/ofw/ofw_real.c +++ b/sys/powerpc/ofw/ofw_real.c @@ -101,7 +101,7 @@ static ssize_t ofw_real_package_to_path(ofw_t, phandle_t package, char *buf, static int ofw_real_call_method(ofw_t, ihandle_t instance, const char *method, int nargs, int nreturns, cell_t *args_and_returns); static int ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, - unsigned long *returns); + cell_t *returns); static ihandle_t ofw_real_open(ofw_t, const char *device); static void ofw_real_close(ofw_t, ihandle_t instance); static ssize_t ofw_real_read(ofw_t, ihandle_t instance, void *addr, size_t len); @@ -756,7 +756,7 @@ ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method, cell_t instance; cell_t args_n_results[12]; } args; - cell_t *cp, *ap; + cell_t *ap, *cp; int n; args.name = (cell_t)(uintptr_t)"call-method"; @@ -791,8 +791,7 @@ ofw_real_call_method(ofw_t ofw, ihandle_t instance, const char *method, } static int -ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, - unsigned long *returns) +ofw_real_interpret(ofw_t ofw, const char *cmd, int nreturns, cell_t *returns) { vm_offset_t argsptr; struct { diff --git a/sys/powerpc/ofw/ofw_syscons.c b/sys/powerpc/ofw/ofw_syscons.c index 47a9a8bcdb8..e638e4b9c75 100644 --- a/sys/powerpc/ofw/ofw_syscons.c +++ b/sys/powerpc/ofw/ofw_syscons.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include @@ -280,7 +281,7 @@ ofwfb_configure(int flags) OF_getprop(node, "address", &fb_phys, sizeof(fb_phys)); bus_space_map(&bs_be_tag, fb_phys, sc->sc_height * sc->sc_stride, - 0, &sc->sc_addr); + BUS_SPACE_MAP_PREFETCHABLE, &sc->sc_addr); /* * Get the PCI addresses of the adapter. The node may be the @@ -632,8 +633,25 @@ ofwfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, sc = (struct ofwfb_softc *)adp; - if (sc->sc_num_pciaddrs == 0) - return (ENOMEM); + /* + * Make sure the requested address lies within the PCI device's + * assigned addrs + */ + for (i = 0; i < sc->sc_num_pciaddrs; i++) + if (offset >= sc->sc_pciaddrs[i].phys_lo && + offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) + { + /* + * If this is a prefetchable BAR, we can (and should) + * enable write-combining. + */ + if (sc->sc_pciaddrs[i].phys_hi & + OFW_PCI_PHYS_HI_PREFETCHABLE) + *memattr = VM_MEMATTR_WRITE_COMBINING; + + *paddr = offset; + return (0); + } /* * Hack for Radeon... @@ -643,16 +661,6 @@ ofwfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, return (0); } - /* - * Make sure the requested address lies within the PCI device's assigned addrs - */ - for (i = 0; i < sc->sc_num_pciaddrs; i++) - if (offset >= sc->sc_pciaddrs[i].phys_lo && - offset < (sc->sc_pciaddrs[i].phys_lo + sc->sc_pciaddrs[i].size_lo)) { - *paddr = offset; - return (0); - } - /* * This might be a legacy VGA mem request: if so, just point it at the * framebuffer, since it shouldn't be touched @@ -662,6 +670,12 @@ ofwfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr, return (0); } + /* + * Error if we didn't have a better idea. + */ + if (sc->sc_num_pciaddrs == 0) + return (ENOMEM); + return (EINVAL); } diff --git a/sys/powerpc/powermac/ata_kauai.c b/sys/powerpc/powermac/ata_kauai.c index fd45061e5a6..3ad2a48ee2a 100644 --- a/sys/powerpc/powermac/ata_kauai.c +++ b/sys/powerpc/powermac/ata_kauai.c @@ -217,8 +217,10 @@ ata_kauai_probe(device_t dev) ch = &sc->sc_ch.sc_ch; compatstring = ofw_bus_get_compat(dev); - if (compatstring != NULL && strcmp(compatstring,"shasta-ata") == 0) + if (compatstring != NULL && strcmp(compatstring,"shasta-ata") == 0) { + ch->flags |= ATA_NO_ATAPI_DMA; sc->shasta = 1; + } /* Pre-K2 controllers apparently need this hack */ if (!sc->shasta && diff --git a/sys/powerpc/powermac/cuda.c b/sys/powerpc/powermac/cuda.c index 0499352adec..99a0ea9c461 100644 --- a/sys/powerpc/powermac/cuda.c +++ b/sys/powerpc/powermac/cuda.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -72,6 +73,7 @@ static u_int cuda_adb_autopoll(device_t dev, uint16_t mask); static u_int cuda_poll(device_t dev); static void cuda_send_inbound(struct cuda_softc *sc); static void cuda_send_outbound(struct cuda_softc *sc); +static void cuda_shutdown(void *xsc, int howto); /* * Clock interface @@ -249,6 +251,8 @@ cuda_attach(device_t dev) } clock_register(dev, 1000); + EVENTHANDLER_REGISTER(shutdown_final, cuda_shutdown, sc, + SHUTDOWN_PRI_LAST); return (bus_generic_attach(dev)); } @@ -739,6 +743,20 @@ cuda_adb_autopoll(device_t dev, uint16_t mask) { return (0); } +static void +cuda_shutdown(void *xsc, int howto) +{ + struct cuda_softc *sc = xsc; + uint8_t cmd[] = {CUDA_PSEUDO, 0}; + + cmd[1] = (howto & RB_HALT) ? CMD_POWEROFF : CMD_RESET; + cuda_poll(sc->sc_dev); + cuda_send(sc, 1, 2, cmd); + + while (1) + cuda_poll(sc->sc_dev); +} + #define DIFF19041970 2082844800 static int diff --git a/sys/powerpc/powermac/fcu.c b/sys/powerpc/powermac/fcu.c new file mode 100644 index 00000000000..7318f1e8759 --- /dev/null +++ b/sys/powerpc/powermac/fcu.c @@ -0,0 +1,506 @@ +/*- + * Copyright (c) 2010 Andreas Tobler + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +/* FCU registers + * /u3@0,f8000000/i2c@f8001000/fan@15e + */ +#define FCU_RPM_FAIL 0x0b /* fans states in bits 0<1-6>7 */ +#define FCU_RPM_AVAILABLE 0x0c +#define FCU_RPM_ACTIVE 0x0d +#define FCU_RPM_READ(x) 0x11 + (x) * 2 +#define FCU_RPM_SET(x) 0x10 + (x) * 2 + +#define FCU_PWM_FAIL 0x2b +#define FCU_PWM_AVAILABLE 0x2c +#define FCU_PWM_ACTIVE 0x2d +#define FCU_PWM_READ(x) 0x31 + (x) * 2 +#define FCU_PWM_SET(x) 0x30 + (x) * 2 + +struct fcu_fan { + int id; + cell_t min_rpm; + cell_t max_rpm; + char location[32]; + enum { + FCU_FAN_RPM, + FCU_FAN_PWM + } type; + int setpoint; +}; + +struct fcu_softc { + device_t sc_dev; + struct intr_config_hook enum_hook; + uint32_t sc_addr; + struct fcu_fan *sc_fans; + int sc_nfans; +}; + +static int fcu_rpm_shift; + +/* Regular bus attachment functions */ +static int fcu_probe(device_t); +static int fcu_attach(device_t); + +/* Utility functions */ +static void fcu_attach_fans(device_t dev); +static int fcu_fill_fan_prop(device_t dev); +static int fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm); +static int fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm); +static int fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS); +static void fcu_start(void *xdev); +static int fcu_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buf, + int len); +static int fcu_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data); + +static device_method_t fcu_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fcu_probe), + DEVMETHOD(device_attach, fcu_attach), + { 0, 0 }, +}; + +static driver_t fcu_driver = { + "fcu", + fcu_methods, + sizeof(struct fcu_softc) +}; + +static devclass_t fcu_devclass; + +DRIVER_MODULE(fcu, iicbus, fcu_driver, fcu_devclass, 0, 0); +MALLOC_DEFINE(M_FCU, "fcu", "FCU Sensor Information"); + +static int +fcu_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, + int len) +{ + unsigned char buf[4]; + struct iic_msg msg[] = { + { addr, IIC_M_WR, 0, buf } + }; + + msg[0].len = len + 1; + buf[0] = reg; + memcpy(buf + 1, buff, len); + if (iicbus_transfer(dev, msg, 1) != 0) { + device_printf(dev, "iicbus write failed\n"); + return (EIO); + } + + return (0); + +} + +static int +fcu_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) +{ + uint8_t buf[4]; + + struct iic_msg msg[2] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_RD, 1, buf }, + }; + + if (iicbus_transfer(dev, msg, 2) != 0) { + device_printf(dev, "iicbus read failed\n"); + return (EIO); + } + + *data = *((uint8_t*)buf); + + return (0); +} + +static int +fcu_probe(device_t dev) +{ + const char *name, *compatible; + struct fcu_softc *sc; + + name = ofw_bus_get_name(dev); + compatible = ofw_bus_get_compat(dev); + + if (!name) + return (ENXIO); + + if (strcmp(name, "fan") != 0 || strcmp(compatible, "fcu") != 0) + return (ENXIO); + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_addr = iicbus_get_addr(dev); + + device_set_desc(dev, "Apple Fan Control Unit"); + + return (0); +} + +static int +fcu_attach(device_t dev) +{ + struct fcu_softc *sc; + + sc = device_get_softc(dev); + + sc->enum_hook.ich_func = fcu_start; + sc->enum_hook.ich_arg = dev; + + /* We have to wait until interrupts are enabled. I2C read and write + * only works if the interrupts are available. + * The unin/i2c is controlled by the htpic on unin. But this is not + * the master. The openpic on mac-io is controlling the htpic. + * This one gets attached after the mac-io probing and then the + * interrupts will be available. + */ + + if (config_intrhook_establish(&sc->enum_hook) != 0) + return (ENOMEM); + + return (0); +} + +static void +fcu_start(void *xdev) +{ + unsigned char buf[1] = { 0xff }; + struct fcu_softc *sc; + + device_t dev = (device_t)xdev; + + sc = device_get_softc(dev); + + /* Start the fcu device. */ + fcu_write(sc->sc_dev, sc->sc_addr, 0xe, buf, 1); + fcu_write(sc->sc_dev, sc->sc_addr, 0x2e, buf, 1); + fcu_read_1(sc->sc_dev, sc->sc_addr, 0, buf); + fcu_rpm_shift = (buf[0] == 1) ? 2 : 3; + + device_printf(dev, "FCU initialized, RPM shift: %d\n", + fcu_rpm_shift); + + /* Detect and attach child devices. */ + + fcu_attach_fans(dev); + + config_intrhook_disestablish(&sc->enum_hook); + +} + +static int +fcu_fan_set_rpm(device_t dev, struct fcu_fan *fan, int rpm) +{ + uint8_t reg; + struct fcu_softc *sc; + unsigned char buf[2]; + + sc = device_get_softc(dev); + + /* Clamp to allowed range */ + rpm = max(fan->min_rpm, rpm); + rpm = min(fan->max_rpm, rpm); + + if (fan->type == FCU_FAN_RPM) { + reg = FCU_RPM_SET(fan->id); + fan->setpoint = rpm; + } else if (fan->type == FCU_FAN_PWM) { + reg = FCU_PWM_SET(fan->id); + if (rpm > 3500) + rpm = 3500; + if (rpm < 500) + rpm = 500; + fan->setpoint = rpm; + /* PWM 30: 550 rpm, PWM 255: 3400 rpm. */ + rpm = (rpm * 255) / 3500; + } else { + device_printf(dev, "Unknown fan type: %d\n", fan->type); + return (EIO); + } + + if (fan->type == FCU_FAN_RPM) { + buf[0] = rpm >> (8 - fcu_rpm_shift); + buf[1] = rpm << fcu_rpm_shift; + fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 2); + } else { + buf[0] = rpm; + fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 1); + } + + return (0); +} + +static int +fcu_fan_get_rpm(device_t dev, struct fcu_fan *fan, int *rpm) +{ + uint8_t reg; + struct fcu_softc *sc; + uint8_t buff[2] = { 0, 0 }; + uint8_t active = 0, avail = 0, fail = 0; + + sc = device_get_softc(dev); + + if (fan->type == FCU_FAN_RPM) { + /* Check if the fan is available. */ + reg = FCU_RPM_AVAILABLE; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail); + if ((avail & (1 << fan->id)) == 0) { + device_printf(dev, "RPM Fan not available ID: %d\n", + fan->id); + return (EIO); + } + /* Check if we have a failed fan. */ + reg = FCU_RPM_FAIL; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail); + if ((fail & (1 << fan->id)) != 0) { + device_printf(dev, "RPM Fan failed ID: %d\n", fan->id); + return (EIO); + } + /* Check if fan is active. */ + reg = FCU_RPM_ACTIVE; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active); + if ((active & (1 << fan->id)) == 0) { + device_printf(dev, "RPM Fan not active ID: %d\n", + fan->id); + return (ENXIO); + } + reg = FCU_RPM_READ(fan->id); + } else if (fan->type == FCU_FAN_PWM) { + /* Check if the fan is available. */ + reg = FCU_PWM_AVAILABLE; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail); + if ((avail & (1 << fan->id)) == 0) { + device_printf(dev, "PWM Fan not available ID: %d\n", + fan->id); + return (EIO); + } + /* Check if we have a failed fan. */ + reg = FCU_PWM_FAIL; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail); + if ((fail & (1 << fan->id)) != 0) { + device_printf(dev, "PWM Fan failed ID: %d\n", fan->id); + return (EIO); + } + /* Check if fan is active. */ + reg = FCU_PWM_ACTIVE; + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active); + if ((active & (1 << fan->id)) == 0) { + device_printf(dev, "PWM Fan not active ID: %d\n", + fan->id); + return (ENXIO); + } + reg = FCU_PWM_READ(fan->id); + } else { + device_printf(dev, "Unknown fan type: %d\n", fan->type); + return (EIO); + } + + /* It seems that we can read the fans rpm. */ + fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buff); + + *rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift; + + return (0); +} + +/* + * This function returns the number of fans. If we call it the second time + * and we have allocated memory for sc->sc_fans, we fill in the properties. + */ +static int +fcu_fill_fan_prop(device_t dev) +{ + phandle_t child; + struct fcu_softc *sc; + u_int id[8]; + char location[96]; + char type[64]; + int i = 0, j, len = 0, prop_len, prev_len = 0; + + sc = device_get_softc(dev); + + child = ofw_bus_get_node(dev); + + /* Fill the fan location property. */ + prop_len = OF_getprop(child, "hwctrl-location", location, + sizeof(location)); + while (len < prop_len) { + if (sc->sc_fans != NULL) { + strcpy(sc->sc_fans[i].location, location + len); + } + prev_len = strlen(location + len) + 1; + len += prev_len; + i++; + } + if (sc->sc_fans == NULL) + return (i); + + /* Fill the fan type property. */ + len = 0; + i = 0; + prev_len = 0; + prop_len = OF_getprop(child, "hwctrl-type", type, sizeof(type)); + while (len < prop_len) { + if (strcmp(type + len, "fan-rpm") == 0) + sc->sc_fans[i].type = FCU_FAN_RPM; + else + sc->sc_fans[i].type = FCU_FAN_PWM; + prev_len = strlen(type + len) + 1; + len += prev_len; + i++; + } + + /* Fill the fan ID property. */ + prop_len = OF_getprop(child, "hwctrl-id", id, sizeof(id)); + for (j = 0; j < i; j++) + sc->sc_fans[j].id = ((id[j] >> 8) & 0x0f) % 8; + + return (i); +} + +static int +fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t fcu; + struct fcu_softc *sc; + struct fcu_fan *fan; + int rpm = 0, error; + + fcu = arg1; + sc = device_get_softc(fcu); + fan = &sc->sc_fans[arg2]; + fcu_fan_get_rpm(fcu, fan, &rpm); + error = sysctl_handle_int(oidp, &rpm, 0, req); + + if (error || !req->newptr) + return (error); + + return (fcu_fan_set_rpm(fcu, fan, rpm)); +} + +static void +fcu_attach_fans(device_t dev) +{ + struct fcu_softc *sc; + struct sysctl_oid *oid, *fanroot_oid; + struct sysctl_ctx_list *ctx; + phandle_t child; + char sysctl_name[32]; + int i, j; + + sc = device_get_softc(dev); + + sc->sc_nfans = 0; + + child = ofw_bus_get_node(dev); + + /* Count the actual number of fans. */ + sc->sc_nfans = fcu_fill_fan_prop(dev); + + device_printf(dev, "%d fans detected!\n", sc->sc_nfans); + + if (sc->sc_nfans == 0) { + device_printf(dev, "WARNING: No fans detected!\n"); + return; + } + + sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct fcu_fan), M_FCU, + M_WAITOK | M_ZERO); + + ctx = device_get_sysctl_ctx(dev); + fanroot_oid = SYSCTL_ADD_NODE(ctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans", + CTLFLAG_RD, 0, "FCU Fan Information"); + + /* Now we can fill the properties into the allocated struct. */ + sc->sc_nfans = fcu_fill_fan_prop(dev); + + /* Add sysctls for the fans. */ + for (i = 0; i < sc->sc_nfans; i++) { + for (j = 0; j < strlen(sc->sc_fans[i].location); j++) { + sysctl_name[j] = tolower(sc->sc_fans[i].location[j]); + if (isspace(sysctl_name[j])) + sysctl_name[j] = '_'; + } + sysctl_name[j] = 0; + + sc->sc_fans[i].min_rpm = 2400 >> fcu_rpm_shift; + sc->sc_fans[i].max_rpm = 56000 >> fcu_rpm_shift; + fcu_fan_get_rpm(dev, &sc->sc_fans[i], &sc->sc_fans[i].setpoint); + + oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid), + OID_AUTO, sysctl_name, CTLFLAG_RD, 0, + "Fan Information"); + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "minrpm", + CTLTYPE_INT | CTLFLAG_RD, + &(sc->sc_fans[i].min_rpm), sizeof(cell_t), + "Minimum allowed RPM"); + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "maxrpm", + CTLTYPE_INT | CTLFLAG_RD, + &(sc->sc_fans[i].max_rpm), sizeof(cell_t), + "Maximum allowed RPM"); + /* I use i to pass the fan id. */ + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, "rpm", + CTLTYPE_INT | CTLFLAG_RW, dev, i, + fcu_fanrpm_sysctl, "I", "Fan RPM"); + } + + /* Dump fan location, type & RPM. */ + if (bootverbose) { + device_printf(dev, "Fans\n"); + for (i = 0; i < sc->sc_nfans; i++) { + device_printf(dev, "Location: %s type: %d ID: %d RPM: %d\n", + sc->sc_fans[i].location, + sc->sc_fans[i].type, sc->sc_fans[i].id, + sc->sc_fans[i].setpoint); + } + } +} diff --git a/sys/powerpc/powermac/kiic.c b/sys/powerpc/powermac/kiic.c index c01987a7981..0b13190aa09 100644 --- a/sys/powerpc/powermac/kiic.c +++ b/sys/powerpc/powermac/kiic.c @@ -250,7 +250,7 @@ static void kiic_writereg(struct kiic_softc *sc, u_int reg, u_int val) { bus_write_4(sc->sc_reg, sc->sc_regstep * reg, val); - DELAY(10); /* register access delay */ + DELAY(100); /* register access delay */ } static u_int diff --git a/sys/powerpc/aim/platform_chrp.c b/sys/powerpc/powermac/platform_powermac.c similarity index 72% rename from sys/powerpc/aim/platform_chrp.c rename to sys/powerpc/powermac/platform_powermac.c index a49b520eb6d..d495065b1b4 100644 --- a/sys/powerpc/aim/platform_chrp.c +++ b/sys/powerpc/powermac/platform_powermac.c @@ -55,38 +55,41 @@ __FBSDID("$FreeBSD$"); extern void *ap_pcpu; #endif -static int chrp_probe(platform_t); -void chrp_mem_regions(platform_t, struct mem_region **phys, int *physsz, +static int powermac_probe(platform_t); +void powermac_mem_regions(platform_t, struct mem_region **phys, int *physsz, struct mem_region **avail, int *availsz); -static u_long chrp_timebase_freq(platform_t, struct cpuref *cpuref); -static int chrp_smp_first_cpu(platform_t, struct cpuref *cpuref); -static int chrp_smp_next_cpu(platform_t, struct cpuref *cpuref); -static int chrp_smp_get_bsp(platform_t, struct cpuref *cpuref); -static int chrp_smp_start_cpu(platform_t, struct pcpu *cpu); +static u_long powermac_timebase_freq(platform_t, struct cpuref *cpuref); +static int powermac_smp_first_cpu(platform_t, struct cpuref *cpuref); +static int powermac_smp_next_cpu(platform_t, struct cpuref *cpuref); +static int powermac_smp_get_bsp(platform_t, struct cpuref *cpuref); +static int powermac_smp_start_cpu(platform_t, struct pcpu *cpu); +static void powermac_reset(platform_t); -static platform_method_t chrp_methods[] = { - PLATFORMMETHOD(platform_probe, chrp_probe), - PLATFORMMETHOD(platform_mem_regions, chrp_mem_regions), - PLATFORMMETHOD(platform_timebase_freq, chrp_timebase_freq), +static platform_method_t powermac_methods[] = { + PLATFORMMETHOD(platform_probe, powermac_probe), + PLATFORMMETHOD(platform_mem_regions, powermac_mem_regions), + PLATFORMMETHOD(platform_timebase_freq, powermac_timebase_freq), - PLATFORMMETHOD(platform_smp_first_cpu, chrp_smp_first_cpu), - PLATFORMMETHOD(platform_smp_next_cpu, chrp_smp_next_cpu), - PLATFORMMETHOD(platform_smp_get_bsp, chrp_smp_get_bsp), - PLATFORMMETHOD(platform_smp_start_cpu, chrp_smp_start_cpu), + PLATFORMMETHOD(platform_smp_first_cpu, powermac_smp_first_cpu), + PLATFORMMETHOD(platform_smp_next_cpu, powermac_smp_next_cpu), + PLATFORMMETHOD(platform_smp_get_bsp, powermac_smp_get_bsp), + PLATFORMMETHOD(platform_smp_start_cpu, powermac_smp_start_cpu), + + PLATFORMMETHOD(platform_reset, powermac_reset), { 0, 0 } }; -static platform_def_t chrp_platform = { - "chrp", - chrp_methods, +static platform_def_t powermac_platform = { + "powermac", + powermac_methods, 0 }; -PLATFORM_DEF(chrp_platform); +PLATFORM_DEF(powermac_platform); static int -chrp_probe(platform_t plat) +powermac_probe(platform_t plat) { if (OF_finddevice("/memory") != -1 || OF_finddevice("/memory@0") != -1) return (BUS_PROBE_GENERIC); @@ -95,14 +98,14 @@ chrp_probe(platform_t plat) } void -chrp_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, +powermac_mem_regions(platform_t plat, struct mem_region **phys, int *physsz, struct mem_region **avail, int *availsz) { ofw_mem_regions(phys,physsz,avail,availsz); } static u_long -chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) +powermac_timebase_freq(platform_t plat, struct cpuref *cpuref) { phandle_t phandle; int32_t ticks = -1; @@ -119,7 +122,7 @@ chrp_timebase_freq(platform_t plat, struct cpuref *cpuref) static int -chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) +powermac_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) { cell_t cpuid, res; @@ -139,7 +142,7 @@ chrp_smp_fill_cpuref(struct cpuref *cpuref, phandle_t cpu) } static int -chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) +powermac_smp_first_cpu(platform_t plat, struct cpuref *cpuref) { char buf[8]; phandle_t cpu, dev, root; @@ -175,11 +178,11 @@ chrp_smp_first_cpu(platform_t plat, struct cpuref *cpuref) if (cpu == 0) return (ENOENT); - return (chrp_smp_fill_cpuref(cpuref, cpu)); + return (powermac_smp_fill_cpuref(cpuref, cpu)); } static int -chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) +powermac_smp_next_cpu(platform_t plat, struct cpuref *cpuref) { char buf[8]; phandle_t cpu; @@ -195,11 +198,11 @@ chrp_smp_next_cpu(platform_t plat, struct cpuref *cpuref) if (cpu == 0) return (ENOENT); - return (chrp_smp_fill_cpuref(cpuref, cpu)); + return (powermac_smp_fill_cpuref(cpuref, cpu)); } static int -chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) +powermac_smp_get_bsp(platform_t plat, struct cpuref *cpuref) { ihandle_t inst; phandle_t bsp, chosen; @@ -214,11 +217,11 @@ chrp_smp_get_bsp(platform_t plat, struct cpuref *cpuref) return (ENXIO); bsp = OF_instance_to_package(inst); - return (chrp_smp_fill_cpuref(cpuref, bsp)); + return (powermac_smp_fill_cpuref(cpuref, bsp)); } static int -chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) +powermac_smp_start_cpu(platform_t plat, struct pcpu *pc) { #ifdef SMP phandle_t cpu; @@ -277,3 +280,9 @@ chrp_smp_start_cpu(platform_t plat, struct pcpu *pc) #endif } +static void +powermac_reset(platform_t platform) +{ + OF_reboot(); +} + diff --git a/sys/powerpc/powermac/pmu.c b/sys/powerpc/powermac/pmu.c index 1fa101d9b4f..d641c9c74f5 100644 --- a/sys/powerpc/powermac/pmu.c +++ b/sys/powerpc/powermac/pmu.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -81,6 +82,11 @@ static u_int pmu_adb_send(device_t dev, u_char command_byte, int len, static u_int pmu_adb_autopoll(device_t dev, uint16_t mask); static u_int pmu_poll(device_t dev); +/* + * Power interface + */ + +static void pmu_shutdown(void *xsc, int howto); static void pmu_set_sleepled(void *xsc, int onoff); static int pmu_server_mode(SYSCTL_HANDLER_ARGS); static int pmu_acline_state(SYSCTL_HANDLER_ARGS); @@ -474,6 +480,12 @@ pmu_attach(device_t dev) clock_register(dev, 1000); + /* + * Register power control handler + */ + EVENTHANDLER_REGISTER(shutdown_final, pmu_shutdown, sc, + SHUTDOWN_PRI_LAST); + return (bus_generic_attach(dev)); } @@ -750,6 +762,20 @@ pmu_adb_autopoll(device_t dev, uint16_t mask) return 0; } +static void +pmu_shutdown(void *xsc, int howto) +{ + struct pmu_softc *sc = xsc; + uint8_t cmd[] = {'M', 'A', 'T', 'T'}; + + if (howto & RB_HALT) + pmu_send(sc, PMU_POWER_OFF, 4, cmd, 0, NULL); + else + pmu_send(sc, PMU_RESET_CPU, 0, NULL, 0, NULL); + + for (;;); +} + static void pmu_set_sleepled(void *xsc, int onoff) { diff --git a/sys/powerpc/powermac/smu.c b/sys/powerpc/powermac/smu.c index 7a4fac836b1..28949043bf2 100644 --- a/sys/powerpc/powermac/smu.c +++ b/sys/powerpc/powermac/smu.c @@ -165,6 +165,7 @@ static void smu_manage_fans(device_t smu); static void smu_set_sleepled(void *xdev, int onoff); static int smu_server_mode(SYSCTL_HANDLER_ARGS); static void smu_doorbell_intr(void *xdev); +static void smu_shutdown(void *xdev, int howto); /* where to find the doorbell GPIO */ @@ -391,6 +392,12 @@ smu_attach(device_t dev) */ clock_register(dev, 1000); + /* + * Learn about shutdown events + */ + EVENTHANDLER_REGISTER(shutdown_final, smu_shutdown, dev, + SHUTDOWN_PRI_LAST); + return (bus_generic_attach(dev)); } @@ -1115,6 +1122,25 @@ smu_server_mode(SYSCTL_HANDLER_ARGS) return (smu_run_cmd(smu, &cmd, 1)); } +static void +smu_shutdown(void *xdev, int howto) +{ + device_t smu = xdev; + struct smu_cmd cmd; + + cmd.cmd = SMU_POWER; + if (howto & RB_HALT) + strcpy(cmd.data, "SHUTDOWN"); + else + strcpy(cmd.data, "RESTART"); + + cmd.len = strlen(cmd.data); + + smu_run_cmd(smu, &cmd, 1); + + for (;;); +} + static int smu_gettime(device_t dev, struct timespec *ts) { diff --git a/sys/powerpc/powerpc/bus_machdep.c b/sys/powerpc/powerpc/bus_machdep.c index dfc6beecbc4..2d2f6ee8ed9 100644 --- a/sys/powerpc/powerpc/bus_machdep.c +++ b/sys/powerpc/powerpc/bus_machdep.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); static struct { bus_addr_t addr; bus_size_t size; + int flags; } earlyboot_mappings[MAX_EARLYBOOT_MAPPINGS]; static int earlyboot_map_idx = 0; @@ -72,9 +73,11 @@ __ppc_ba(bus_space_handle_t bsh, bus_size_t ofs) } static int -bs_gen_map(bus_addr_t addr, bus_size_t size __unused, int flags __unused, +bs_gen_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *bshp) { + vm_memattr_t ma; + /* * Record what we did if we haven't enabled the MMU yet. We * will need to remap it as soon as the MMU comes up. @@ -84,10 +87,20 @@ bs_gen_map(bus_addr_t addr, bus_size_t size __unused, int flags __unused, ("%s: too many early boot mapping requests", __func__)); earlyboot_mappings[earlyboot_map_idx].addr = addr; earlyboot_mappings[earlyboot_map_idx].size = size; + earlyboot_mappings[earlyboot_map_idx].flags = flags; earlyboot_map_idx++; *bshp = addr; } else { - *bshp = (bus_space_handle_t)pmap_mapdev(addr,size); + ma = VM_MEMATTR_DEFAULT; + switch (flags) { + case BUS_SPACE_MAP_CACHEABLE: + ma = VM_MEMATTR_CACHEABLE; + break; + case BUS_SPACE_MAP_PREFETCHABLE: + ma = VM_MEMATTR_PREFETCHABLE; + break; + } + *bshp = (bus_space_handle_t)pmap_mapdev_attr(addr, size, ma); } return (0); @@ -98,6 +111,7 @@ bs_remap_earlyboot(void) { int i; vm_offset_t pa, spa; + vm_memattr_t ma; for (i = 0; i < earlyboot_map_idx; i++) { spa = earlyboot_mappings[i].addr; @@ -105,9 +119,19 @@ bs_remap_earlyboot(void) == 0) continue; + ma = VM_MEMATTR_DEFAULT; + switch (earlyboot_mappings[i].flags) { + case BUS_SPACE_MAP_CACHEABLE: + ma = VM_MEMATTR_CACHEABLE; + break; + case BUS_SPACE_MAP_PREFETCHABLE: + ma = VM_MEMATTR_PREFETCHABLE; + break; + } + pa = trunc_page(spa); while (pa < spa + earlyboot_mappings[i].size) { - pmap_kenter(pa,pa); + pmap_kenter_attr(pa, pa, ma); pa += PAGE_SIZE; } } diff --git a/sys/powerpc/powerpc/busdma_machdep.c b/sys/powerpc/powerpc/busdma_machdep.c index 4223dc4713a..f66413fddf8 100644 --- a/sys/powerpc/powerpc/busdma_machdep.c +++ b/sys/powerpc/powerpc/busdma_machdep.c @@ -529,7 +529,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); - } else if ((uintptr_t)*vaddr & (dmat->alignment - 1)) { + } else if (vtophys(*vaddr) & (dmat->alignment - 1)) { printf("bus_dmamem_alloc failed to align memory properly.\n"); } #ifdef NOTYET diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c index 2ca646f005b..a4e397db901 100644 --- a/sys/powerpc/powerpc/exec_machdep.c +++ b/sys/powerpc/powerpc/exec_machdep.c @@ -251,9 +251,9 @@ sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) tf->fixreg[FIRSTARG] = sig; #ifdef COMPAT_FREEBSD32 tf->fixreg[FIRSTARG+2] = (register_t)usfp + - (p->p_sysent->sv_flags & SV_ILP32) ? + ((p->p_sysent->sv_flags & SV_ILP32) ? offsetof(struct sigframe32, sf_uc) : - offsetof(struct sigframe, sf_uc); + offsetof(struct sigframe, sf_uc)); #else tf->fixreg[FIRSTARG+2] = (register_t)usfp + offsetof(struct sigframe, sf_uc); diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c index 5a0ff8cadf5..4b2dbbe9550 100644 --- a/sys/powerpc/powerpc/intr_machdep.c +++ b/sys/powerpc/powerpc/intr_machdep.c @@ -95,6 +95,7 @@ struct powerpc_intr { device_t pic; u_int intline; u_int vector; + u_int cntindex; cpumask_t cpu; enum intr_trigger trig; enum intr_polarity pol; @@ -106,6 +107,7 @@ struct pic { int ipi_irq; }; +static u_int intrcnt_index = 0; static struct mtx intr_table_lock; static struct powerpc_intr *powerpc_intrs[INTR_VECTORS]; static struct pic piclist[MAX_PICS]; @@ -152,6 +154,16 @@ intrcnt_setname(const char *name, int index) MAXCOMLEN, name); } +void +intrcnt_add(const char *name, u_long **countp) +{ + int idx; + + idx = atomic_fetchadd_int(&intrcnt_index, 1); + *countp = &intrcnt[idx]; + intrcnt_setname(name, idx); +} + static struct powerpc_intr * intr_lookup(u_int irq) { @@ -200,8 +212,10 @@ intr_lookup(u_int irq) if (iscan == NULL && i->vector != -1) { powerpc_intrs[i->vector] = i; + i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1); + i->cntp = &intrcnt[i->cntindex]; sprintf(intrname, "irq%u:", i->irq); - intrcnt_setname(intrname, i->vector); + intrcnt_setname(intrname, i->cntindex); nvectors++; } mtx_unlock(&intr_table_lock); @@ -384,8 +398,6 @@ powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, if (error) return (error); - i->cntp = &intrcnt[i->vector]; - enable = 1; } @@ -393,7 +405,7 @@ powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, intr_priority(flags), flags, cookiep); mtx_lock(&intr_table_lock); - intrcnt_setname(i->event->ie_fullname, i->vector); + intrcnt_setname(i->event->ie_fullname, i->cntindex); mtx_unlock(&intr_table_lock); if (!cold) { diff --git a/sys/powerpc/powerpc/mem.c b/sys/powerpc/powerpc/mem.c index e4b70c68d90..b4636ecfce8 100644 --- a/sys/powerpc/powerpc/mem.c +++ b/sys/powerpc/powerpc/mem.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -68,7 +69,21 @@ __FBSDID("$FreeBSD$"); #include -struct mem_range_softc mem_range_softc; +static void ppc_mrinit(struct mem_range_softc *); +static int ppc_mrset(struct mem_range_softc *, struct mem_range_desc *, int *); + +MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); + +static struct mem_range_ops ppc_mem_range_ops = { + ppc_mrinit, + ppc_mrset, + NULL, + NULL +}; +struct mem_range_softc mem_range_softc = { + &ppc_mem_range_ops, + 0, 0, 0 +}; /* ARGSUSED */ int @@ -162,6 +177,8 @@ int memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { + int i; + /* * /dev/mem is the only one that makes sense through this * interface. For /dev/kmem any physaddr we return here @@ -178,10 +195,143 @@ memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, *paddr = offset; + for (i = 0; i < mem_range_softc.mr_ndesc; i++) { + if (!(mem_range_softc.mr_desc[i].mr_flags & MDF_ACTIVE)) + continue; + + if (offset >= mem_range_softc.mr_desc[i].mr_base && + offset < mem_range_softc.mr_desc[i].mr_base + + mem_range_softc.mr_desc[i].mr_len) { + switch (mem_range_softc.mr_desc[i].mr_flags & + MDF_ATTRMASK) { + case MDF_WRITEBACK: + *memattr = VM_MEMATTR_WRITE_BACK; + break; + case MDF_WRITECOMBINE: + *memattr = VM_MEMATTR_WRITE_COMBINING; + break; + case MDF_UNCACHEABLE: + *memattr = VM_MEMATTR_UNCACHEABLE; + break; + case MDF_WRITETHROUGH: + *memattr = VM_MEMATTR_WRITE_THROUGH; + break; + } + + break; + } + } + return (0); } void dev_mem_md_init(void) { + mem_range_softc.mr_op->init(&mem_range_softc); } + +static void +ppc_mrinit(struct mem_range_softc *sc) +{ + sc->mr_cap = 0; + sc->mr_ndesc = 8; /* XXX: Should be dynamically expandable */ + sc->mr_desc = malloc(sc->mr_ndesc * sizeof(struct mem_range_desc), + M_MEMDESC, M_NOWAIT | M_ZERO); + if (sc->mr_desc == NULL) + panic("%s: malloc returns NULL", __func__); +} + +static int +ppc_mrset(struct mem_range_softc *sc, struct mem_range_desc *desc, int *arg) +{ + int i; + + switch(*arg) { + case MEMRANGE_SET_UPDATE: + for (i = 0; i < sc->mr_ndesc; i++) { + if (!sc->mr_desc[i].mr_len) { + sc->mr_desc[i] = *desc; + sc->mr_desc[i].mr_flags |= MDF_ACTIVE; + return (0); + } + if (sc->mr_desc[i].mr_base == desc->mr_base && + sc->mr_desc[i].mr_len == desc->mr_len) + return (EEXIST); + } + return (ENOSPC); + case MEMRANGE_SET_REMOVE: + for (i = 0; i < sc->mr_ndesc; i++) + if (sc->mr_desc[i].mr_base == desc->mr_base && + sc->mr_desc[i].mr_len == desc->mr_len) { + bzero(&sc->mr_desc[i], sizeof(sc->mr_desc[i])); + return (0); + } + return (ENOENT); + default: + return (EOPNOTSUPP); + } + + return (0); +} + +/* + * Operations for changing memory attributes. + * + * This is basically just an ioctl shim for mem_range_attr_get + * and mem_range_attr_set. + */ +/* ARGSUSED */ +int +memioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, + struct thread *td) +{ + int nd, error = 0; + struct mem_range_op *mo = (struct mem_range_op *)data; + struct mem_range_desc *md; + + /* is this for us? */ + if ((cmd != MEMRANGE_GET) && + (cmd != MEMRANGE_SET)) + return (ENOTTY); + + /* any chance we can handle this? */ + if (mem_range_softc.mr_op == NULL) + return (EOPNOTSUPP); + + /* do we have any descriptors? */ + if (mem_range_softc.mr_ndesc == 0) + return (ENXIO); + + switch (cmd) { + case MEMRANGE_GET: + nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); + if (nd > 0) { + md = (struct mem_range_desc *) + malloc(nd * sizeof(struct mem_range_desc), + M_MEMDESC, M_WAITOK); + error = mem_range_attr_get(md, &nd); + if (!error) + error = copyout(md, mo->mo_desc, + nd * sizeof(struct mem_range_desc)); + free(md, M_MEMDESC); + } + else + nd = mem_range_softc.mr_ndesc; + mo->mo_arg[0] = nd; + break; + + case MEMRANGE_SET: + md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), + M_MEMDESC, M_WAITOK); + error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); + /* clamp description string */ + md->mr_owner[sizeof(md->mr_owner) - 1] = 0; + if (error == 0) + error = mem_range_attr_set(md, &mo->mo_arg[0]); + free(md, M_MEMDESC); + break; + } + return (error); +} + diff --git a/sys/powerpc/powerpc/mmu_if.m b/sys/powerpc/powerpc/mmu_if.m index d31e54196b2..6f606225392 100644 --- a/sys/powerpc/powerpc/mmu_if.m +++ b/sys/powerpc/powerpc/mmu_if.m @@ -111,6 +111,24 @@ CODE { { return (NULL); } + + static void *mmu_null_mapdev_attr(mmu_t mmu, vm_offset_t pa, + vm_size_t size, vm_memattr_t ma) + { + return MMU_MAPDEV(mmu, pa, size); + } + + static void mmu_null_kenter_attr(mmu_t mmu, vm_offset_t va, + vm_offset_t pa, vm_memattr_t ma) + { + MMU_KENTER(mmu, va, pa); + } + + static void mmu_null_page_set_memattr(mmu_t mmu, vm_page_t m, + vm_memattr_t ma) + { + return; + } }; @@ -747,6 +765,37 @@ METHOD void * mapdev { vm_size_t _size; }; +/** + * @brief Create a kernel mapping for a given physical address range. + * Called by bus code on behalf of device drivers. The mapping does not + * have to be a virtual address: it can be a direct-mapped physical address + * if that is supported by the MMU. + * + * @param _pa start physical address + * @param _size size in bytes of mapping + * @param _attr cache attributes + * + * @retval addr address of mapping. + */ +METHOD void * mapdev_attr { + mmu_t _mmu; + vm_offset_t _pa; + vm_size_t _size; + vm_memattr_t _attr; +} DEFAULT mmu_null_mapdev_attr; + +/** + * @brief Change cache control attributes for a page. Should modify all + * mappings for that page. + * + * @param _m page to modify + * @param _ma new cache control attributes + */ +METHOD void page_set_memattr { + mmu_t _mmu; + vm_page_t _pg; + vm_memattr_t _ma; +} DEFAULT mmu_null_page_set_memattr; /** * @brief Remove the mapping created by mapdev. Called when a driver @@ -787,6 +836,19 @@ METHOD void kenter { vm_offset_t _pa; }; +/** + * @brief Map a wired page into kernel virtual address space + * + * @param _va mapping virtual address + * @param _pa mapping physical address + * @param _ma mapping cache control attributes + */ +METHOD void kenter_attr { + mmu_t _mmu; + vm_offset_t _va; + vm_offset_t _pa; + vm_memattr_t _ma; +} DEFAULT mmu_null_kenter_attr; /** * @brief Determine if the given physical address range has been direct-mapped. diff --git a/sys/powerpc/powerpc/mp_machdep.c b/sys/powerpc/powerpc/mp_machdep.c index 19b46a9e634..9086db5299c 100644 --- a/sys/powerpc/powerpc/mp_machdep.c +++ b/sys/powerpc/powerpc/mp_machdep.c @@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include @@ -57,9 +59,9 @@ extern struct pcpu __pcpu[MAXCPU]; volatile static int ap_awake; volatile static u_int ap_letgo; -volatile static uint32_t ap_decr; volatile static u_quad_t ap_timebase; static u_int ipi_msg_cnt[32]; +static struct mtx ap_boot_mtx; void machdep_ap_bootstrap(void) @@ -76,19 +78,21 @@ machdep_ap_bootstrap(void) ; /* Initialize DEC and TB, sync with the BSP values */ - decr_ap_init(); mttb(ap_timebase); - __asm __volatile("mtdec %0" :: "r"(ap_decr)); + decr_ap_init(); - atomic_add_int(&ap_awake, 1); + /* Serialize console output and AP count increment */ + mtx_lock_spin(&ap_boot_mtx); + ap_awake++; printf("SMP: AP CPU #%d launched\n", PCPU_GET(cpuid)); + mtx_unlock_spin(&ap_boot_mtx); /* Initialize curthread */ PCPU_SET(curthread, PCPU_GET(idlethread)); PCPU_SET(curpcb, curthread->td_pcb); - /* Let the DEC and external interrupts go */ - mtmsr(mfmsr() | PSL_EE); + /* Start per-CPU event timers. */ + cpu_initclocks_ap(); /* Announce ourselves awake, and enter the scheduler */ sched_throw(NULL); @@ -203,6 +207,8 @@ cpu_mp_unleash(void *dummy) if (mp_ncpus <= 1) return; + mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); + cpus = 0; smp_cpus = 0; SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { @@ -235,7 +241,6 @@ cpu_mp_unleash(void *dummy) ap_awake = 1; /* Provide our current DEC and TB values for APs */ - __asm __volatile("mfdec %0" : "=r"(ap_decr)); ap_timebase = mftb() + 10; __asm __volatile("msync; isync"); @@ -305,6 +310,10 @@ powerpc_ipi_handler(void *arg) atomic_clear_int(&stopped_cpus, self); CTR1(KTR_SMP, "%s: IPI_STOP (restart)", __func__); break; + case IPI_HARDCLOCK: + CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__); + hardclockintr(); + break; } } diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c index 400856375db..2b5c60792db 100644 --- a/sys/powerpc/powerpc/platform.c +++ b/sys/powerpc/powerpc/platform.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -104,6 +105,15 @@ platform_smp_start_cpu(struct pcpu *cpu) return (PLATFORM_SMP_START_CPU(plat_obj, cpu)); } +/* + * Reset back to firmware. + */ +void +cpu_reset() +{ + PLATFORM_RESET(plat_obj); +} + /* * Platform install routines. Highest priority wins, using the same * algorithm as bus attachment. diff --git a/sys/powerpc/powerpc/platform_if.m b/sys/powerpc/powerpc/platform_if.m index 600d14656a5..07e49bc884c 100644 --- a/sys/powerpc/powerpc/platform_if.m +++ b/sys/powerpc/powerpc/platform_if.m @@ -161,3 +161,10 @@ METHOD int smp_start_cpu { struct pcpu *_cpu; }; +/** + * @brief Reset system + */ +METHOD void reset { + platform_t _plat; +}; + diff --git a/sys/powerpc/powerpc/pmap_dispatch.c b/sys/powerpc/powerpc/pmap_dispatch.c index dd9468579ea..fe104293ab2 100644 --- a/sys/powerpc/powerpc/pmap_dispatch.c +++ b/sys/powerpc/powerpc/pmap_dispatch.c @@ -433,6 +433,22 @@ pmap_mapdev(vm_offset_t pa, vm_size_t size) return (MMU_MAPDEV(mmu_obj, pa, size)); } +void * +pmap_mapdev_attr(vm_offset_t pa, vm_size_t size, vm_memattr_t attr) +{ + + CTR4(KTR_PMAP, "%s(%#x, %#x, %#x)", __func__, pa, size, attr); + return (MMU_MAPDEV_ATTR(mmu_obj, pa, size, attr)); +} + +void +pmap_page_set_memattr(vm_page_t m, vm_memattr_t ma) +{ + + CTR3(KTR_PMAP, "%s(%p, %#x)", __func__, m, ma); + return (MMU_PAGE_SET_MEMATTR(mmu_obj, m, ma)); +} + void pmap_unmapdev(vm_offset_t va, vm_size_t size) { @@ -457,6 +473,14 @@ pmap_kenter(vm_offset_t va, vm_offset_t pa) MMU_KENTER(mmu_obj, va, pa); } +void +pmap_kenter_attr(vm_offset_t va, vm_offset_t pa, vm_memattr_t ma) +{ + + CTR4(KTR_PMAP, "%s(%#x, %#x, %#x)", __func__, va, pa, ma); + MMU_KENTER_ATTR(mmu_obj, va, pa, ma); +} + boolean_t pmap_dev_direct_mapped(vm_offset_t pa, vm_size_t size) { diff --git a/sys/rpc/clnt_dg.c b/sys/rpc/clnt_dg.c index e3fa02c91bf..a01f5988064 100644 --- a/sys/rpc/clnt_dg.c +++ b/sys/rpc/clnt_dg.c @@ -193,6 +193,7 @@ clnt_dg_create( struct rpc_msg call_msg; struct __rpc_sockinfo si; XDR xdrs; + int error; if (svcaddr == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNADDR; @@ -267,7 +268,12 @@ clnt_dg_create( */ cu->cu_closeit = FALSE; cu->cu_socket = so; - soreserve(so, 256*1024, 256*1024); + error = soreserve(so, (u_long)sendsz, (u_long)recvsz); + if (error != 0) { + rpc_createerr.cf_stat = RPC_FAILED; + rpc_createerr.cf_error.re_errno = error; + goto err2; + } sb = &so->so_rcv; SOCKBUF_LOCK(&so->so_rcv); diff --git a/sys/rpc/clnt_vc.c b/sys/rpc/clnt_vc.c index 2e5fe41f1b9..9699a8d1fe6 100644 --- a/sys/rpc/clnt_vc.c +++ b/sys/rpc/clnt_vc.c @@ -288,13 +288,19 @@ clnt_vc_create( * Create a client handle which uses xdrrec for serialization * and authnone for authentication. */ + sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); + recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); + error = soreserve(ct->ct_socket, sendsz, recvsz); + if (error != 0) { + if (ct->ct_closeit) { + soclose(ct->ct_socket); + } + goto err; + } cl->cl_refs = 1; cl->cl_ops = &clnt_vc_ops; cl->cl_private = ct; cl->cl_auth = authnone_create(); - sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz); - recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz); - soreserve(ct->ct_socket, sendsz, recvsz); SOCKBUF_LOCK(&ct->ct_socket->so_rcv); soupcall_set(ct->ct_socket, SO_RCV, clnt_vc_soupcall, ct); diff --git a/sys/rpc/replay.c b/sys/rpc/replay.c index d82fc2086ef..1bd5378d9fb 100644 --- a/sys/rpc/replay.c +++ b/sys/rpc/replay.c @@ -90,8 +90,10 @@ void replay_setsize(struct replay_cache *rc, size_t newmaxsize) { + mtx_lock(&rc->rc_lock); rc->rc_maxsize = newmaxsize; replay_prune(rc); + mtx_unlock(&rc->rc_lock); } void @@ -111,8 +113,12 @@ replay_alloc(struct replay_cache *rc, { struct replay_cache_entry *rce; + mtx_assert(&rc->rc_lock, MA_OWNED); + rc->rc_count++; rce = malloc(sizeof(*rce), M_RPC, M_NOWAIT|M_ZERO); + if (!rce) + return (NULL); rce->rce_hash = h; rce->rce_msg = *msg; bcopy(addr, &rce->rce_addr, addr->sa_len); @@ -127,6 +133,8 @@ static void replay_free(struct replay_cache *rc, struct replay_cache_entry *rce) { + mtx_assert(&rc->rc_lock, MA_OWNED); + rc->rc_count--; TAILQ_REMOVE(&rc->rc_cache[rce->rce_hash], rce, rce_link); TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink); @@ -141,26 +149,25 @@ static void replay_prune(struct replay_cache *rc) { struct replay_cache_entry *rce; - bool_t freed_one; - if (rc->rc_count >= REPLAY_MAX || rc->rc_size > rc->rc_maxsize) { - freed_one = FALSE; - do { - /* - * Try to free an entry. Don't free in-progress entries - */ - TAILQ_FOREACH_REVERSE(rce, &rc->rc_all, - replay_cache_list, rce_alllink) { - if (rce->rce_repmsg.rm_xid) { - replay_free(rc, rce); - freed_one = TRUE; - break; - } - } - } while (freed_one - && (rc->rc_count >= REPLAY_MAX - || rc->rc_size > rc->rc_maxsize)); - } + mtx_assert(&rc->rc_lock, MA_OWNED); + + if (rc->rc_count < REPLAY_MAX && rc->rc_size <= rc->rc_maxsize) + return; + + do { + /* + * Try to free an entry. Don't free in-progress entries. + */ + TAILQ_FOREACH_REVERSE(rce, &rc->rc_all, replay_cache_list, + rce_alllink) { + if (rce->rce_repmsg.rm_xid) + break; + } + if (rce) + replay_free(rc, rce); + } while (rce && (rc->rc_count >= REPLAY_MAX + || rc->rc_size > rc->rc_maxsize)); } enum replay_state diff --git a/sys/rpc/rpc_com.h b/sys/rpc/rpc_com.h index e50e513f567..290a289e3a4 100644 --- a/sys/rpc/rpc_com.h +++ b/sys/rpc/rpc_com.h @@ -111,10 +111,6 @@ extern struct netbuf *__rpc_uaddr2taddr_af(int, const char *); extern int __rpc_seman2socktype(int); extern int __rpc_socktype2seman(int); extern int __rpc_sockisbound(struct socket*); -extern const char *__rpc_inet_ntop(int af, const void * __restrict src, - char * __restrict dst, socklen_t size); -extern int __rpc_inet_pton(int af, const char * __restrict src, - void * __restrict dst); extern int bindresvport(struct socket *so, struct sockaddr *sa); struct xucred; diff --git a/sys/rpc/rpc_generic.c b/sys/rpc/rpc_generic.c index f15ad28f294..1c6aa821123 100644 --- a/sys/rpc/rpc_generic.c +++ b/sys/rpc/rpc_generic.c @@ -63,6 +63,8 @@ __FBSDID("$FreeBSD$"); #include +extern u_long sb_max_adj; /* not defined in socketvar.h */ + #if __FreeBSD_version < 700000 #define strrchr rindex #endif @@ -113,9 +115,8 @@ u_int /*ARGSUSED*/ __rpc_get_t_size(int af, int proto, int size) { - int maxsize, defsize; + int defsize; - maxsize = 256 * 1024; /* XXX */ switch (proto) { case IPPROTO_TCP: defsize = 64 * 1024; /* XXX */ @@ -131,7 +132,7 @@ __rpc_get_t_size(int af, int proto, int size) return defsize; /* Check whether the value is within the upper max limit */ - return (size > maxsize ? (u_int)maxsize : (u_int)size); + return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size); } /* @@ -306,7 +307,7 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) switch (af) { case AF_INET: sin = nbuf->buf; - if (__rpc_inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) + if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) == NULL) return NULL; port = ntohs(sin->sin_port); @@ -318,7 +319,7 @@ __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) #ifdef INET6 case AF_INET6: sin6 = nbuf->buf; - if (__rpc_inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) + if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) == NULL) return NULL; port = ntohs(sin6->sin6_port); @@ -396,7 +397,7 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr) memset(sin, 0, sizeof *sin); sin->sin_family = AF_INET; sin->sin_port = htons(port); - if (__rpc_inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { + if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { free(sin, M_RPC); free(ret, M_RPC); ret = NULL; @@ -414,7 +415,7 @@ __rpc_uaddr2taddr_af(int af, const char *uaddr) memset(sin6, 0, sizeof *sin6); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); - if (__rpc_inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { + if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { free(sin6, M_RPC); free(ret, M_RPC); ret = NULL; diff --git a/sys/security/audit/audit_bsm_klib.c b/sys/security/audit/audit_bsm_klib.c index c8d40356cfe..f26f86cabc9 100644 --- a/sys/security/audit/audit_bsm_klib.c +++ b/sys/security/audit/audit_bsm_klib.c @@ -548,7 +548,7 @@ audit_canon_path(struct thread *td, char *path, char *cpath) * the supplied buffer being overflowed. Check to see if this is the * case. */ - if (sbuf_overflowed(&sbf) != 0) { + if (sbuf_error(&sbf) != 0) { cpath[0] = '\0'; return; } diff --git a/sys/security/mac/mac_framework.c b/sys/security/mac/mac_framework.c index 1f43c0278f7..fa069280dcc 100644 --- a/sys/security/mac/mac_framework.c +++ b/sys/security/mac/mac_framework.c @@ -94,10 +94,12 @@ __FBSDID("$FreeBSD$"); SDT_PROVIDER_DEFINE(mac); SDT_PROVIDER_DEFINE(mac_framework); -SDT_PROBE_DEFINE2(mac, kernel, policy, modevent, "int", +SDT_PROBE_DEFINE2(mac, kernel, policy, modevent, modevent, "int", "struct mac_policy_conf *mpc"); -SDT_PROBE_DEFINE1(mac, kernel, policy, register, "struct mac_policy_conf *"); -SDT_PROBE_DEFINE1(mac, kernel, policy, unregister, "struct mac_policy_conf *"); +SDT_PROBE_DEFINE1(mac, kernel, policy, register, register, + "struct mac_policy_conf *"); +SDT_PROBE_DEFINE1(mac, kernel, policy, unregister, unregister, + "struct mac_policy_conf *"); /* * Root sysctl node for all MAC and MAC policy controls. diff --git a/sys/security/mac/mac_internal.h b/sys/security/mac/mac_internal.h index 39fc4042beb..72444772ab2 100644 --- a/sys/security/mac/mac_internal.h +++ b/sys/security/mac/mac_internal.h @@ -75,27 +75,27 @@ SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */ #define MAC_CHECK_PROBE_DEFINE4(name, arg0, arg1, arg2, arg3) \ SDT_PROBE_DEFINE5(mac_framework, kernel, name, mac_check_err, \ - "int", arg0, arg1, arg2, arg3); \ + mac-check-ok, "int", arg0, arg1, arg2, arg3); \ SDT_PROBE_DEFINE5(mac_framework, kernel, name, mac_check_ok, \ - "int", arg0, arg1, arg2, arg3); + mac-check-ok, "int", arg0, arg1, arg2, arg3); #define MAC_CHECK_PROBE_DEFINE3(name, arg0, arg1, arg2) \ SDT_PROBE_DEFINE4(mac_framework, kernel, name, mac_check_err, \ - "int", arg0, arg1, arg2); \ + mac-check-err, "int", arg0, arg1, arg2); \ SDT_PROBE_DEFINE4(mac_framework, kernel, name, mac_check_ok, \ - "int", arg0, arg1, arg2); + mac-check-ok, "int", arg0, arg1, arg2); #define MAC_CHECK_PROBE_DEFINE2(name, arg0, arg1) \ SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac_check_err, \ - "int", arg0, arg1); \ + mac-check-err, "int", arg0, arg1); \ SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac_check_ok, \ - "int", arg0, arg1); + mac-check-ok, "int", arg0, arg1); #define MAC_CHECK_PROBE_DEFINE1(name, arg0) \ SDT_PROBE_DEFINE2(mac_framework, kernel, name, mac_check_err, \ - "int", arg0); \ + mac-check-err, "int", arg0); \ SDT_PROBE_DEFINE2(mac_framework, kernel, name, mac_check_ok, \ - "int", arg0); + mac-check-ok, "int", arg0); #define MAC_CHECK_PROBE4(name, error, arg0, arg1, arg2, arg3) do { \ if (error) { \ @@ -117,9 +117,9 @@ SDT_PROVIDER_DECLARE(mac_framework); /* Entry points to MAC. */ #define MAC_GRANT_PROBE_DEFINE2(name, arg0, arg1) \ SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac_grant_err, \ - "int", arg0, arg1); \ + mac-grant-err, "int", arg0, arg1); \ SDT_PROBE_DEFINE3(mac_framework, kernel, name, mac_grant_ok, \ - "INT", arg0, arg1); + mac-grant-ok, "INT", arg0, arg1); #define MAC_GRANT_PROBE2(name, error, arg0, arg1) do { \ if (error) { \ diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c index dcd29aa23ec..c4f305bbc9d 100644 --- a/sys/security/mac/mac_vfs.c +++ b/sys/security/mac/mac_vfs.c @@ -637,6 +637,8 @@ mac_vnode_check_open(struct ucred *cred, struct vnode *vp, accmode_t accmode) ASSERT_VOP_LOCKED(vp, "mac_vnode_check_open"); MAC_POLICY_CHECK(vnode_check_open, cred, vp, vp->v_label, accmode); + MAC_CHECK_PROBE3(vnode_check_open, error, cred, vp, accmode); + return (error); } diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC index 1e0a0f26d2c..6bbd4e14f24 100644 --- a/sys/sparc64/conf/GENERIC +++ b/sys/sparc64/conf/GENERIC @@ -56,7 +56,6 @@ options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) @@ -185,7 +184,7 @@ device nge # NatSemi DP83820 gigabit Ethernet device re # RealTek 8139C+/8169/8169S/8110S device rl # RealTek 8129/8139 device sf # Adaptec AIC-6915 (``Starfire'') -#device sis # Silicon Integrated Systems SiS 900/SiS 7016 +device sis # Silicon Integrated Systems SiS 900/SiS 7016 device sk # SysKonnect SK-984x & SK-982x gigabit Ethernet device ste # Sundance ST201 (D-Link DFE-550TX) device stge # Sundance/Tamarack TC9021 gigabit Ethernet diff --git a/sys/sparc64/include/asm.h b/sys/sparc64/include/asm.h index 8182fe77fe7..dea06c547f9 100644 --- a/sys/sparc64/include/asm.h +++ b/sys/sparc64/include/asm.h @@ -76,7 +76,7 @@ _ALIGN_TEXT /* - * Define a function entry point. + * Define function entry and alternate entry points. * * The compiler produces #function for the .type pseudo-op, but the '#' * character has special meaning in cpp macros, so we use @function like @@ -86,12 +86,19 @@ * value. Since this is difficult to predict and its expected that * assembler code is already optimized, we leave it out. */ + +#define _ALTENTRY(x) \ + .globl CNAME(x) ; \ + .type CNAME(x),@function ; \ +CNAME(x): + #define _ENTRY(x) \ _START_ENTRY ; \ .globl CNAME(x) ; \ .type CNAME(x),@function ; \ CNAME(x): +#define ALTENTRY(x) _ALTENTRY(x) #define ENTRY(x) _ENTRY(x) #define END(x) .size x, . - x diff --git a/sys/sparc64/include/elf.h b/sys/sparc64/include/elf.h index 2a666705d0f..0618434231b 100644 --- a/sys/sparc64/include/elf.h +++ b/sys/sparc64/include/elf.h @@ -84,8 +84,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 diff --git a/sys/sparc64/include/endian.h b/sys/sparc64/include/endian.h index 17447844ac4..2ca467e409f 100644 --- a/sys/sparc64/include/endian.h +++ b/sys/sparc64/include/endian.h @@ -69,18 +69,20 @@ #define __is_constant(x) 0 #endif -#define __bswap16_const(x) ((((x) >> 8) & 0xff) | \ - (((x) << 8) & 0xff00)) -#define __bswap32_const(x) ((((x) >> 24) & 0xff) | \ - (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | \ - (((x) << 24) & 0xff000000)) -#define __bswap64_const(x) ((((x) >> 56) & 0xff) | \ - (((x) >> 40) & 0xff00) | (((x) >> 24) & 0xff0000) | \ - (((x) >> 8) & 0xff000000) | \ - (((x) << 8) & ((__uint64_t)0xff << 32)) | \ - (((x) << 24) & ((__uint64_t)0xff << 40)) | \ - (((x) << 40) & ((__uint64_t)0xff << 48)) | \ - (((x) << 56) & ((__uint64_t)0xff << 56))) +#define __bswap16_const(x) ((((__uint16_t)(x) >> 8) & 0xff) | \ + (((__uint16_t)(x) << 8) & 0xff00)) +#define __bswap32_const(x) ((((__uint32_t)(x) >> 24) & 0xff) | \ + (((__uint32_t)(x) >> 8) & 0xff00) | \ + (((__uint32_t)(x)<< 8) & 0xff0000) | \ + (((__uint32_t)(x) << 24) & 0xff000000)) +#define __bswap64_const(x) ((((__uint64_t)(x) >> 56) & 0xff) | \ + (((__uint64_t)(x) >> 40) & 0xff00) | \ + (((__uint64_t)(x) >> 24) & 0xff0000) | \ + (((__uint64_t)(x) >> 8) & 0xff000000) | \ + (((__uint64_t)(x) << 8) & ((__uint64_t)0xff << 32)) | \ + (((__uint64_t)(x) << 24) & ((__uint64_t)0xff << 40)) | \ + (((__uint64_t)(x) << 40) & ((__uint64_t)0xff << 48)) | \ + (((__uint64_t)(x) << 56) & ((__uint64_t)0xff << 56))) static __inline __uint16_t __bswap16_var(__uint16_t _x) diff --git a/sys/sparc64/include/intr_machdep.h b/sys/sparc64/include/intr_machdep.h index 254ac78a90b..158b5b6017a 100644 --- a/sys/sparc64/include/intr_machdep.h +++ b/sys/sparc64/include/intr_machdep.h @@ -47,7 +47,6 @@ #define PIL_STOP 5 /* stop cpu ipi */ #define PIL_PREEMPT 6 /* preempt idle thread cpu ipi */ #define PIL_HARDCLOCK 7 /* hardclock broadcast */ -#define PIL_STATCLOCK 8 /* statclock broadcast */ #define PIL_FILTER 12 /* filter interrupts */ #define PIL_FAST 13 /* fast interrupts */ #define PIL_TICK 14 /* tick interrupts */ diff --git a/sys/sparc64/include/md_var.h b/sys/sparc64/include/md_var.h index 8f064e7961e..8503b431e2e 100644 --- a/sys/sparc64/include/md_var.h +++ b/sys/sparc64/include/md_var.h @@ -58,6 +58,8 @@ struct md_utrap *utrap_hold(struct md_utrap *ut); cpu_block_copy_t spitfire_block_copy; cpu_block_zero_t spitfire_block_zero; +cpu_block_copy_t zeus_block_copy; +cpu_block_zero_t zeus_block_zero; extern cpu_block_copy_t *cpu_block_copy; extern cpu_block_zero_t *cpu_block_zero; diff --git a/sys/sparc64/include/smp.h b/sys/sparc64/include/smp.h index 3812431c143..3ca8e038044 100644 --- a/sys/sparc64/include/smp.h +++ b/sys/sparc64/include/smp.h @@ -59,7 +59,6 @@ #define IPI_RENDEZVOUS PIL_RENDEZVOUS #define IPI_PREEMPT PIL_PREEMPT #define IPI_HARDCLOCK PIL_HARDCLOCK -#define IPI_STATCLOCK PIL_STATCLOCK #define IPI_STOP PIL_STOP #define IPI_STOP_HARD PIL_STOP diff --git a/sys/sparc64/include/tick.h b/sys/sparc64/include/tick.h index 979e93f826c..201a3e65a82 100644 --- a/sys/sparc64/include/tick.h +++ b/sys/sparc64/include/tick.h @@ -29,7 +29,7 @@ #ifndef _MACHINE_TICK_H_ #define _MACHINE_TICK_H_ -extern u_int hardclock_use_stick; +extern u_int tick_et_use_stick; void tick_clear(u_int cpu_impl); void tick_stop(u_int cpu_impl); diff --git a/sys/sparc64/pci/schizo.c b/sys/sparc64/pci/schizo.c index ae0d9a0a8a0..f34666789d3 100644 --- a/sys/sparc64/pci/schizo.c +++ b/sys/sparc64/pci/schizo.c @@ -849,7 +849,7 @@ schizo_pci_bus(void *arg) fatal = 1; if ((status & (PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT | PCIM_STATUS_RTABORT | - PCIM_STATUS_PERRREPORT)) != 0 || + PCIM_STATUS_MDPERR)) != 0 || (csr & (SCZ_PCI_CTRL_BUS_UNUS | TOM_PCI_CTRL_DTO_ERR | STX_PCI_CTRL_TTO_ERR | STX_PCI_CTRL_RTRY_ERR | SCZ_PCI_CTRL_SBH_ERR | STX_PCI_CTRL_SERR)) != 0 || diff --git a/sys/sparc64/sparc64/bus_machdep.c b/sys/sparc64/sparc64/bus_machdep.c index 0bf9b2e4b61..0f0df0791ca 100644 --- a/sys/sparc64/sparc64/bus_machdep.c +++ b/sys/sparc64/sparc64/bus_machdep.c @@ -182,11 +182,8 @@ busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) static void dflt_lock(void *arg, bus_dma_lock_op_t op) { -#ifdef INVARIANTS + panic("driver error: busdma dflt_lock called"); -#else - printf("DRIVER_ERROR: busdma dflt_lock called\n"); -#endif } /* @@ -631,9 +628,18 @@ nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, if (flags & BUS_DMA_ZERO) mflags |= M_ZERO; - if ((dmat->dt_maxsize <= PAGE_SIZE)) { + /* + * XXX: + * (dmat->dt_alignment < dmat->dt_maxsize) is just a quick hack; the + * exact alignment guarantees of malloc need to be nailed down, and + * the code below should be rewritten to take that into account. + * + * In the meantime, we'll warn the user if malloc gets it wrong. + */ + if (dmat->dt_maxsize <= PAGE_SIZE && + dmat->dt_alignment < dmat->dt_maxsize) *vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags); - } else { + else { /* * XXX use contigmalloc until it is merged into this * facility and handles multi-seg allocations. Nobody @@ -646,6 +652,8 @@ nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, } if (*vaddr == NULL) return (ENOMEM); + if (vtophys(*vaddr) % dmat->dt_alignment) + printf("%s: failed to align memory properly.\n", __func__); return (0); } @@ -657,11 +665,11 @@ static void nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) { - if ((dmat->dt_maxsize <= PAGE_SIZE)) + if (dmat->dt_maxsize <= PAGE_SIZE && + dmat->dt_alignment < dmat->dt_maxsize) free(vaddr, M_DEVBUF); - else { + else contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF); - } } struct bus_dma_methods nexus_dma_methods = { diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c index 8ddf4763b1c..e4d5a06b87e 100644 --- a/sys/sparc64/sparc64/elf_machdep.c +++ b/sys/sparc64/sparc64/elf_machdep.c @@ -132,8 +132,8 @@ void elf64_dump_thread(struct thread *td __unused, void *dst __unused, size_t *off __unused) { -} +} /* * The following table holds for each relocation type: @@ -155,6 +155,7 @@ elf64_dump_thread(struct thread *td __unused, void *dst __unused, #define _RF_G 0x10000000 /* GOT offset */ #define _RF_B 0x08000000 /* Load address relative */ #define _RF_U 0x04000000 /* Unaligned */ +#define _RF_X 0x02000000 /* Bare symbols, needs proc */ #define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ #define _RF_RS(s) ( (s) & 0xff) /* right shift */ static const int reloc_target_flags[] = { @@ -167,10 +168,10 @@ static const int reloc_target_flags[] = { _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HI22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 13 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LO10 */ _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */ _RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */ _RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */ @@ -189,36 +190,36 @@ static const int reloc_target_flags[] = { _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */ _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PCPLT22 */ _RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PCPLT10 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 10 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 11 */ - _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* 64 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 11 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(64) | _RF_RS(0), /* 64 */ _RF_S|_RF_A|/*extra*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(42), /* HH22 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(32), /* HM10 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* LM22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(42), /* HH22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(32), /* HM10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* LM22 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(42), /* PC_HH22 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(32), /* PC_HM10 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC_LM22 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP16 */ _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP19 */ _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 7 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 5 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 6 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 7 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 5 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* 6 */ _RF_S|_RF_A|_RF_P| _RF_SZ(64) | _RF_RS(0), /* DISP64 */ _RF_A| _RF_SZ(64) | _RF_RS(0), /* PLT64 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HIX22 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LOX10 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(22), /* H44 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(12), /* M44 */ - _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* L44 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(10), /* HIX22 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* LOX10 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(22), /* H44 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(12), /* M44 */ + _RF_S|_RF_A|_RF_X| _RF_SZ(32) | _RF_RS(0), /* L44 */ _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REGISTER */ _RF_S|_RF_A| _RF_U| _RF_SZ(64) | _RF_RS(0), /* UA64 */ _RF_S|_RF_A| _RF_U| _RF_SZ(16) | _RF_RS(0), /* UA16 */ }; #if 0 -static const char *reloc_names[] = { +static const char *const reloc_names[] = { "NONE", "RELOC_8", "RELOC_16", "RELOC_32", "DISP_8", "DISP_16", "DISP_32", "WDISP_30", "WDISP_22", "HI22", "22", "13", "LO10", "GOT10", "GOT13", @@ -238,6 +239,7 @@ static const char *reloc_names[] = { #define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) #define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) #define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_BARE_SYMBOL(t) ((reloc_target_flags[t] & _RF_X) != 0) #define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) #define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) @@ -273,10 +275,9 @@ static const long reloc_target_bitmask[] = { int elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, - int type, elf_lookup_fn lookup) + int type, elf_lookup_fn lookup __unused) { const Elf_Rela *rela; - Elf_Addr value; Elf_Addr *where; if (type != ELF_RELOC_RELA) @@ -286,10 +287,8 @@ elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, if (ELF64_R_TYPE_ID(rela->r_info) != R_SPARC_RELATIVE) return (-1); - value = rela->r_addend + (Elf_Addr)lf->address; - where = (Elf_Addr *)((Elf_Addr)lf->address + rela->r_offset); - - *where = elf_relocaddr(lf, value); + where = (Elf_Addr *)(relocbase + rela->r_offset); + *where = elf_relocaddr(lf, rela->r_addend + relocbase); return (0); } @@ -334,6 +333,8 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, if (addr == 0) return (-1); value += addr; + if (RELOC_BARE_SYMBOL(rtype)) + value = elf_relocaddr(lf, value); } if (rtype == R_SPARC_OLO10) @@ -342,9 +343,8 @@ elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, if (RELOC_PC_RELATIVE(rtype)) value -= (Elf_Addr)where; - if (RELOC_BASE_RELATIVE(rtype)) { + if (RELOC_BASE_RELATIVE(rtype)) value = elf_relocaddr(lf, value + relocbase); - } mask = RELOC_VALUE_BITMASK(rtype); value >>= RELOC_VALUE_RIGHTSHIFT(rtype); diff --git a/sys/sparc64/sparc64/intr_machdep.c b/sys/sparc64/sparc64/intr_machdep.c index 8e610f63951..85712865b1b 100644 --- a/sys/sparc64/sparc64/intr_machdep.c +++ b/sys/sparc64/sparc64/intr_machdep.c @@ -97,8 +97,7 @@ static const char *const pil_names[] = { "stop", /* PIL_STOP */ "preempt", /* PIL_PREEMPT */ "hardclock", /* PIL_HARDCLOCK */ - "statclock", /* PIL_STATCLOCK */ - "stray", "stray", "stray", + "stray", "stray", "stray", "stray", "filter", /* PIL_FILTER */ "fast", /* PIL_FAST */ "tick", /* PIL_TICK */ diff --git a/sys/sparc64/sparc64/iommu.c b/sys/sparc64/sparc64/iommu.c index 9d31303c673..a638e526d77 100644 --- a/sys/sparc64/sparc64/iommu.c +++ b/sys/sparc64/sparc64/iommu.c @@ -874,9 +874,6 @@ iommu_dvmamap_create(bus_dma_tag_t dt, int flags, bus_dmamap_t *mapp) */ maxpre = imin(dt->dt_nsegments, IOMMU_MAX_PRE_SEG); presz = dt->dt_maxsize / maxpre; - KASSERT(presz != 0, ("%s: bogus preallocation size , nsegments = %d, " - "maxpre = %d, maxsize = %lu", __func__, dt->dt_nsegments, maxpre, - dt->dt_maxsize)); for (i = 1; i < maxpre && totsz < IOMMU_MAX_PRE; i++) { currsz = round_io_page(ulmin(presz, IOMMU_MAX_PRE - totsz)); error = iommu_dvma_valloc(dt, is, *mapp, currsz); diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index 70abf63e47d..82643ab4530 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -495,7 +495,6 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) if (cpu_use_vis) { switch (cpu_impl) { case CPU_IMPL_SPARC64: - case CPU_IMPL_SPARC64V: case CPU_IMPL_ULTRASPARCI: case CPU_IMPL_ULTRASPARCII: case CPU_IMPL_ULTRASPARCIIi: @@ -509,6 +508,10 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) cpu_block_copy = spitfire_block_copy; cpu_block_zero = spitfire_block_zero; break; + case CPU_IMPL_SPARC64V: + cpu_block_copy = zeus_block_copy; + cpu_block_zero = zeus_block_zero; + break; } } @@ -587,7 +590,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) * enable them. */ intr_init2(); - wrpr(pil, 0, PIL_TICK); + wrpr(pil, 0, 0); wrpr(pstate, 0, PSTATE_KERNEL); /* @@ -959,7 +962,7 @@ int cpu_idle_wakeup(int cpu) { - return (0); + return (1); } int diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c index 57a2d6f38ac..588a0ca34e2 100644 --- a/sys/sparc64/sparc64/mp_machdep.c +++ b/sys/sparc64/sparc64/mp_machdep.c @@ -98,7 +98,6 @@ __FBSDID("$FreeBSD$"); static ih_func_t cpu_ipi_ast; static ih_func_t cpu_ipi_hardclock; static ih_func_t cpu_ipi_preempt; -static ih_func_t cpu_ipi_statclock; static ih_func_t cpu_ipi_stop; /* @@ -292,7 +291,6 @@ cpu_mp_start(void) intr_setup(PIL_STOP, cpu_ipi_stop, -1, NULL, NULL); intr_setup(PIL_PREEMPT, cpu_ipi_preempt, -1, NULL, NULL); intr_setup(PIL_HARDCLOCK, cpu_ipi_hardclock, -1, NULL, NULL); - intr_setup(PIL_STATCLOCK, cpu_ipi_statclock, -1, NULL, NULL); cpuid_to_mid[curcpu] = PCPU_GET(mid); @@ -320,7 +318,7 @@ ap_start(phandle_t node, u_int mid, u_int cpu_impl) if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0) panic("%s: couldn't determine CPU frequency", __func__); if (clock != PCPU_GET(clock)) - hardclock_use_stick = 1; + tick_et_use_stick = 1; csa = &cpu_start_args; csa->csa_state = 0; @@ -435,6 +433,12 @@ cpu_mp_bootstrap(struct pcpu *pc) */ cache_enable(pc->pc_impl); + /* + * Clear (S)TICK timer(s) (including NPT) and ensure they are stopped. + */ + tick_clear(pc->pc_impl); + tick_stop(pc->pc_impl); + /* Lock the kernel TSB in the TLB. */ pmap_map_tsb(); @@ -447,8 +451,11 @@ cpu_mp_bootstrap(struct pcpu *pc) /* Initialize global registers. */ cpu_setregs(pc); - /* Enable interrupts. */ - wrpr(pil, 0, PIL_TICK); + /* + * Enable interrupts. + * Note that the PIL we be lowered indirectly via sched_throw(NULL) + * when fake spinlock held by the idle thread eventually is released. + */ wrpr(pstate, 0, PSTATE_KERNEL); smp_cpus++; @@ -524,15 +531,18 @@ cpu_ipi_preempt(struct trapframe *tf) static void cpu_ipi_hardclock(struct trapframe *tf) { + struct trapframe *oldframe; + struct thread *td; - hardclockintr(tf); -} - -static void -cpu_ipi_statclock(struct trapframe *tf) -{ - - statclockintr(tf); + critical_enter(); + td = curthread; + td->td_intr_nesting_level++; + oldframe = td->td_intr_frame; + td->td_intr_frame = tf; + hardclockintr(); + td->td_intr_frame = oldframe; + td->td_intr_nesting_level--; + critical_exit(); } static void diff --git a/sys/sparc64/sparc64/nexus.c b/sys/sparc64/sparc64/nexus.c index 192251db30d..4c1379e829e 100644 --- a/sys/sparc64/sparc64/nexus.c +++ b/sys/sparc64/sparc64/nexus.c @@ -258,7 +258,7 @@ nexus_attach(device_t dev) } static device_t -nexus_add_child(device_t dev, int order, const char *name, int unit) +nexus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t cdev; struct nexus_devinfo *ndi; diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c index e158bf481af..b34a07f4821 100644 --- a/sys/sparc64/sparc64/pmap.c +++ b/sys/sparc64/sparc64/pmap.c @@ -833,14 +833,15 @@ pmap_cache_remove(vm_page_t m, vm_offset_t va) m->md.colors[DCACHE_COLOR(va)]); KASSERT((m->flags & PG_FICTITIOUS) == 0, ("pmap_cache_remove: fake page")); - KASSERT(m->md.colors[DCACHE_COLOR(va)] > 0, - ("pmap_cache_remove: no mappings %d <= 0", - m->md.colors[DCACHE_COLOR(va)])); PMAP_STATS_INC(pmap_ncache_remove); if (dcache_color_ignore != 0) return; + KASSERT(m->md.colors[DCACHE_COLOR(va)] > 0, + ("pmap_cache_remove: no mappings %d <= 0", + m->md.colors[DCACHE_COLOR(va)])); + /* * Find the color for this virtual address and note the removal of * the mapping. diff --git a/sys/sparc64/sparc64/support.S b/sys/sparc64/sparc64/support.S index d4ca5d332e8..70241d833a0 100644 --- a/sys/sparc64/sparc64/support.S +++ b/sys/sparc64/sparc64/support.S @@ -661,8 +661,121 @@ ENTRY(spitfire_block_copy) END(spitfire_block_copy) /* - * void spitfire_block_zero(void *dst, size_t len) + * void zeus_block_copy(void *src, void *dst, size_t len) */ +ENTRY(zeus_block_copy) + prefetch [%o0 + (0 * 64)], 0 + + rdpr %pil, %o3 + wrpr %g0, PIL_TICK, %pil + + wr %g0, ASI_BLK_S, %asi + wr %g0, FPRS_FEF, %fprs + + sub PCB_REG, TF_SIZEOF, %o4 + ldx [%o4 + TF_FPRS], %o5 + andcc %o5, FPRS_FEF, %g0 + bz,a,pt %xcc, 1f + nop + stda %f0, [PCB_REG + PCB_UFP + (0 * 64)] %asi + stda %f16, [PCB_REG + PCB_UFP + (1 * 64)] %asi + stda %f32, [PCB_REG + PCB_UFP + (2 * 64)] %asi + stda %f48, [PCB_REG + PCB_UFP + (3 * 64)] %asi + membar #Sync + + andn %o5, FPRS_FEF, %o5 + stx %o5, [%o4 + TF_FPRS] + ldx [PCB_REG + PCB_FLAGS], %o4 + or %o4, PCB_FEF, %o4 + stx %o4, [PCB_REG + PCB_FLAGS] + +1: wrpr %o3, 0, %pil + + ldd [%o0 + (0 * 8)], %f0 + prefetch [%o0 + (1 * 64)], 0 + ldd [%o0 + (1 * 8)], %f2 + prefetch [%o0 + (2 * 64)], 0 + fmovd %f0, %f32 + ldd [%o0 + (2 * 8)], %f4 + prefetch [%o0 + (3 * 64)], 0 + fmovd %f2, %f34 + ldd [%o0 + (3 * 8)], %f6 + prefetch [%o0 + (4 * 64)], 1 + fmovd %f4, %f36 + ldd [%o0 + (4 * 8)], %f8 + prefetch [%o0 + (8 * 64)], 1 + fmovd %f6, %f38 + ldd [%o0 + (5 * 8)], %f10 + prefetch [%o0 + (12 * 64)], 1 + fmovd %f8, %f40 + ldd [%o0 + (6 * 8)], %f12 + prefetch [%o0 + (16 * 64)], 1 + fmovd %f10, %f42 + ldd [%o0 + (7 * 8)], %f14 + ldd [%o0 + (8 * 8)], %f0 + sub %o2, 64, %o2 + add %o0, 64, %o0 + prefetch [%o0 + (19 * 64)], 1 + ba,pt %xcc, 2f + prefetch [%o0 + (23 * 64)], 1 + .align 32 + +2: ldd [%o0 + (1 * 8)], %f2 + fmovd %f12, %f44 + ldd [%o0 + (2 * 8)], %f4 + fmovd %f14, %f46 + stda %f32, [%o1] %asi + ldd [%o0 + (3 * 8)], %f6 + fmovd %f0, %f32 + ldd [%o0 + (4 * 8)], %f8 + fmovd %f2, %f34 + ldd [%o0 + (5 * 8)], %f10 + fmovd %f4, %f36 + ldd [%o0 + (6 * 8)], %f12 + fmovd %f6, %f38 + ldd [%o0 + (7 * 8)], %f14 + fmovd %f8, %f40 + ldd [%o0 + (8 * 8)], %f0 + fmovd %f10, %f42 + sub %o2, 64, %o2 + prefetch [%o0 + (3 * 64)], 0 + add %o1, 64, %o1 + prefetch [%o0 + (24 * 64)], 1 + add %o0, 64, %o0 + cmp %o2, 64 + 8 + bgu,pt %xcc, 2b + prefetch [%o0 + (12 * 64)], 1 + ldd [%o0 + (1 * 8)], %f2 + fsrc1 %f12, %f44 + ldd [%o0 + (2 * 8)], %f4 + fsrc1 %f14, %f46 + stda %f32, [%o1] %asi + ldd [%o0 + (3 * 8)], %f6 + fsrc1 %f0, %f32 + ldd [%o0 + (4 * 8)], %f8 + fsrc1 %f2, %f34 + ldd [%o0 + (5 * 8)], %f10 + fsrc1 %f4, %f36 + ldd [%o0 + (6 * 8)], %f12 + fsrc1 %f6, %f38 + ldd [%o0 + (7 * 8)], %f14 + fsrc1 %f8, %f40 + add %o1, 64, %o1 + fsrc1 %f10, %f42 + fsrc1 %f12, %f44 + fsrc1 %f14, %f46 + stda %f32, [%o1] %asi + membar #Sync + + retl + wr %g0, 0, %fprs +END(zeus_block_copy) + +/* + * void spitfire_block_zero(void *dst, size_t len) + * void zeus_block_zero(void *dst, size_t len) + */ +ALTENTRY(zeus_block_zero) ENTRY(spitfire_block_zero) rdpr %pil, %o3 wrpr %g0, PIL_TICK, %pil diff --git a/sys/sparc64/sparc64/tick.c b/sys/sparc64/sparc64/tick.c index 7d693c7afaa..82c24a54cf2 100644 --- a/sys/sparc64/sparc64/tick.c +++ b/sys/sparc64/sparc64/tick.c @@ -74,9 +74,9 @@ static int adjust_ticks = 0; SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_ticks, CTLFLAG_RD, &adjust_ticks, 0, "total number of tick interrupts with adjustment"); -u_int hardclock_use_stick = 0; -SYSCTL_INT(_machdep_tick, OID_AUTO, hardclock_use_stick, CTLFLAG_RD, - &hardclock_use_stick, 0, "hardclock uses STICK instead of TICK timer"); +u_int tick_et_use_stick = 0; +SYSCTL_INT(_machdep_tick, OID_AUTO, tick_et_use_stick, CTLFLAG_RD, + &tick_et_use_stick, 0, "tick event timer uses STICK instead of TICK"); static struct timecounter stick_tc; static struct timecounter tick_tc; @@ -96,9 +96,9 @@ static int tick_et_start(struct eventtimer *et, static int tick_et_stop(struct eventtimer *et); static void tick_intr(struct trapframe *tf); static void tick_intr_bbwar(struct trapframe *tf); -static inline void tick_hardclock_common(struct trapframe *tf, u_long tick, - u_long adj); static inline void tick_process(struct trapframe *tf); +static inline void tick_process_periodic(struct trapframe *tf, u_long tick, + u_long tick_increment, u_long adj); static void stick_intr(struct trapframe *tf); static uint64_t @@ -127,7 +127,7 @@ cpu_initclocks(void) * Given that the STICK timers typically are driven at rather low * frequencies they shouldn't be used except when really necessary. */ - if (hardclock_use_stick != 0) { + if (tick_et_use_stick != 0) { intr_setup(PIL_TICK, stick_intr, -1, NULL, NULL); /* * We don't provide a CPU ticker as long as the frequency @@ -180,11 +180,11 @@ cpu_initclocks(void) #endif tc_init(&stick_tc); } - tick_et.et_name = hardclock_use_stick ? "stick" : "tick"; + tick_et.et_name = tick_et_use_stick ? "stick" : "tick"; tick_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; tick_et.et_quality = 1000; - tick_et.et_frequency = hardclock_use_stick ? sclock : clock; + tick_et.et_frequency = tick_et_use_stick ? sclock : clock; tick_et.et_min_period.sec = 0; tick_et.et_min_period.frac = 0x00010000LLU << 32; /* To be safe. */ tick_et.et_max_period.sec = 3600 * 24; /* No practical limit. */ @@ -203,6 +203,7 @@ tick_process(struct trapframe *tf) struct trapframe *oldframe; struct thread *td; + critical_enter(); if (tick_et.et_active) { td = curthread; oldframe = td->td_intr_frame; @@ -210,13 +211,14 @@ tick_process(struct trapframe *tf) tick_et.et_event_cb(&tick_et, tick_et.et_arg); td->td_intr_frame = oldframe; } + critical_exit(); } /* * NB: the sequence of reading the (S)TICK register, calculating the value * of the next tick and writing it to the (S)TICK_COMPARE register must not * be interrupted, not even by an IPI, otherwise a value that is in the past - * could be written in the worst case, causing hardclock to stop. + * could be written in the worst case, causing the periodic timer to stop. */ static void @@ -225,18 +227,18 @@ tick_intr(struct trapframe *tf) u_long adj, tick, tick_increment; register_t s; - critical_enter(); - adj = PCPU_GET(tickadj); - tick_increment = PCPU_GET(tickincrement); s = intr_disable(); - tick = rd(tick); - if (tick_increment != 0) + tick_increment = PCPU_GET(tickincrement); + if (tick_increment != 0) { + adj = PCPU_GET(tickadj); + tick = rd(tick); wr(tick_cmpr, tick + tick_increment - adj, 0); - else - wr(tick_cmpr, 1L << 63, 0); - intr_restore(s); - tick_hardclock_common(tf, tick, adj); - critical_exit(); + intr_restore(s); + tick_process_periodic(tf, tick, tick_increment, adj); + } else { + intr_restore(s); + tick_process(tf); + } } static void @@ -245,18 +247,18 @@ tick_intr_bbwar(struct trapframe *tf) u_long adj, tick, tick_increment; register_t s; - critical_enter(); - adj = PCPU_GET(tickadj); - tick_increment = PCPU_GET(tickincrement); s = intr_disable(); - tick = rd(tick); - if (tick_increment != 0) + tick_increment = PCPU_GET(tickincrement); + if (tick_increment != 0) { + adj = PCPU_GET(tickadj); + tick = rd(tick); wrtickcmpr(tick + tick_increment - adj, 0); - else - wrtickcmpr(1L << 63, 0); - intr_restore(s); - tick_hardclock_common(tf, tick, adj); - critical_exit(); + intr_restore(s); + tick_process_periodic(tf, tick, tick_increment, adj); + } else { + intr_restore(s); + tick_process(tf); + } } static void @@ -265,28 +267,28 @@ stick_intr(struct trapframe *tf) u_long adj, stick, tick_increment; register_t s; - critical_enter(); - adj = PCPU_GET(tickadj); - tick_increment = PCPU_GET(tickincrement); s = intr_disable(); - stick = rdstick(); - if (tick_increment != 0) + tick_increment = PCPU_GET(tickincrement); + if (tick_increment != 0) { + adj = PCPU_GET(tickadj); + stick = rdstick(); wrstickcmpr(stick + tick_increment - adj, 0); - else - wrstickcmpr(1L << 63, 0); - intr_restore(s); - tick_hardclock_common(tf, stick, adj); - critical_exit(); + intr_restore(s); + tick_process_periodic(tf, stick, tick_increment, adj); + } else { + intr_restore(s); + tick_process(tf); + } } static inline void -tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj) +tick_process_periodic(struct trapframe *tf, u_long tick, + u_long tick_increment, u_long adj) { - u_long ref, tick_increment; + u_long ref; long delta; int count; - tick_increment = PCPU_GET(tickincrement); ref = PCPU_GET(tickref); delta = tick - ref; count = 0; @@ -297,8 +299,6 @@ tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj) if (adj != 0) adjust_ticks++; count++; - if (tick_increment == 0) - break; } if (count > 0) { adjust_missed += count - 1; @@ -361,11 +361,10 @@ tick_get_timecount_mp(struct timecounter *tc) #endif static int -tick_et_start(struct eventtimer *et, - struct bintime *first, struct bintime *period) +tick_et_start(struct eventtimer *et, struct bintime *first, + struct bintime *period) { - u_long fdiv, div; - u_long base; + u_long base, div, fdiv; register_t s; if (period != NULL) { @@ -387,22 +386,21 @@ tick_et_start(struct eventtimer *et, * on all CPUs to avoid inaccuracies for migrating processes. Leave * out one tick to make sure that it is not missed. */ - critical_enter(); - PCPU_SET(tickadj, 0); s = intr_disable(); - if (hardclock_use_stick != 0) + if (tick_et_use_stick != 0) base = rdstick(); else base = rd(tick); - if (div != 0) + if (div != 0) { + PCPU_SET(tickadj, 0); base = roundup(base, div); + } PCPU_SET(tickref, base); - if (hardclock_use_stick != 0) + if (tick_et_use_stick != 0) wrstickcmpr(base + fdiv, 0); else wrtickcmpr(base + fdiv, 0); intr_restore(s); - critical_exit(); return (0); } diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c index 8ce6970d65d..b9e5d94a534 100644 --- a/sys/sparc64/sparc64/trap.c +++ b/sys/sparc64/sparc64/trap.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_ktr.h" -#include "opt_ktrace.h" #include #include @@ -65,10 +64,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef KTRACE -#include -#include -#endif #include #include diff --git a/sys/sparc64/sparc64/vm_machdep.c b/sys/sparc64/sparc64/vm_machdep.c index 9dc55c675d6..c550717be4c 100644 --- a/sys/sparc64/sparc64/vm_machdep.c +++ b/sys/sparc64/sparc64/vm_machdep.c @@ -492,10 +492,7 @@ void swi_vm(void *v) { - /* - * Nothing to do here yet - busdma bounce buffers are not yet - * implemented. - */ + /* Nothing to do here - busdma bounce buffers are not implemented. */ } void * @@ -540,7 +537,7 @@ uma_small_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait) } va = (void *)TLB_PHYS_TO_DIRECT(pa); if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0) - bzero(va, PAGE_SIZE); + cpu_block_zero(va, PAGE_SIZE); return (va); } diff --git a/sys/sun4v/conf/GENERIC b/sys/sun4v/conf/GENERIC index f7a4e777428..74fc0366838 100644 --- a/sys/sun4v/conf/GENERIC +++ b/sys/sun4v/conf/GENERIC @@ -57,7 +57,6 @@ options STACK # stack(9) support options SYSVSHM # SYSV-style shared memory options SYSVMSG # SYSV-style message queues options SYSVSEM # SYSV-style semaphores -options P1003_1B_SEMAPHORES # POSIX-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions options AHC_REG_PRETTY_PRINT # Print register bitfields in debug # output. Adds ~128k to driver. diff --git a/sys/sun4v/include/elf.h b/sys/sun4v/include/elf.h index 2a666705d0f..0618434231b 100644 --- a/sys/sun4v/include/elf.h +++ b/sys/sun4v/include/elf.h @@ -84,8 +84,14 @@ __ElfType(Auxinfo); #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ +#define AT_CANARY 16 /* Canary for SSP */ +#define AT_CANARYLEN 17 /* Length of the canary. */ +#define AT_OSRELDATE 18 /* OSRELDATE. */ +#define AT_NCPUS 19 /* Number of CPUs. */ +#define AT_PAGESIZES 20 /* Pagesizes. */ +#define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ -#define AT_COUNT 16 /* Count of defined aux entry types. */ +#define AT_COUNT 22 /* Count of defined aux entry types. */ /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 diff --git a/sys/sun4v/include/endian.h b/sys/sun4v/include/endian.h index 17447844ac4..c28b04fed2c 100644 --- a/sys/sun4v/include/endian.h +++ b/sys/sun4v/include/endian.h @@ -1,122 +1,7 @@ /*- - * Copyright (c) 1987, 1991, 1993 - * The Regents of the University of California. All rights reserved. + * This file is in the public domain. * - * 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. - * - * @(#)endian.h 8.1 (Berkeley) 6/10/93 * $FreeBSD$ */ -#ifndef _MACHINE_ENDIAN_H_ -#define _MACHINE_ENDIAN_H_ - -#include -#include - -/* - * Define the order of 32-bit words in 64-bit words. - */ -#define _QUAD_HIGHWORD 0 -#define _QUAD_LOWWORD 1 - -/* - * Definitions for byte order, according to byte significance from low - * address to high. - */ -#define _LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ -#define _BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ -#define _PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ - -#define _BYTE_ORDER _BIG_ENDIAN - -/* - * Deprecated variants that don't have enough underscores to be useful in more - * strict namespaces. - */ -#if __BSD_VISIBLE -#define LITTLE_ENDIAN _LITTLE_ENDIAN -#define BIG_ENDIAN _BIG_ENDIAN -#define PDP_ENDIAN _PDP_ENDIAN -#define BYTE_ORDER _BYTE_ORDER -#endif - -#if defined(__GNUCLIKE_BUILTIN_CONSTANT_P) && defined(__OPTIMIZE__) -#define __is_constant(x) __builtin_constant_p(x) -#else -#define __is_constant(x) 0 -#endif - -#define __bswap16_const(x) ((((x) >> 8) & 0xff) | \ - (((x) << 8) & 0xff00)) -#define __bswap32_const(x) ((((x) >> 24) & 0xff) | \ - (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | \ - (((x) << 24) & 0xff000000)) -#define __bswap64_const(x) ((((x) >> 56) & 0xff) | \ - (((x) >> 40) & 0xff00) | (((x) >> 24) & 0xff0000) | \ - (((x) >> 8) & 0xff000000) | \ - (((x) << 8) & ((__uint64_t)0xff << 32)) | \ - (((x) << 24) & ((__uint64_t)0xff << 40)) | \ - (((x) << 40) & ((__uint64_t)0xff << 48)) | \ - (((x) << 56) & ((__uint64_t)0xff << 56))) - -static __inline __uint16_t -__bswap16_var(__uint16_t _x) -{ - - return ((_x >> 8) | ((_x << 8) & 0xff00)); -} - -static __inline __uint32_t -__bswap32_var(__uint32_t _x) -{ - - return ((_x >> 24) | ((_x >> 8) & 0xff00) | ((_x << 8) & 0xff0000) | - ((_x << 24) & 0xff000000)); -} - -static __inline __uint64_t -__bswap64_var(__uint64_t _x) -{ - - return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) | - ((_x >> 8) & 0xff000000) | ((_x << 8) & ((__uint64_t)0xff << 32)) | - ((_x << 24) & ((__uint64_t)0xff << 40)) | - ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56))); -} - -#define __bswap16(x) (__is_constant(x) ? __bswap16_const(x) : \ - __bswap16_var(x)) -#define __bswap32(x) (__is_constant(x) ? __bswap32_const(x) : \ - __bswap32_var(x)) -#define __bswap64(x) (__is_constant(x) ? __bswap64_const(x) : \ - __bswap64_var(x)) - -#define __htonl(x) ((__uint32_t)(x)) -#define __htons(x) ((__uint16_t)(x)) -#define __ntohl(x) ((__uint32_t)(x)) -#define __ntohs(x) ((__uint16_t)(x)) - -#endif /* !_MACHINE_ENDIAN_H_ */ +#include diff --git a/sys/sun4v/include/intr_machdep.h b/sys/sun4v/include/intr_machdep.h index 370a5c0e2f4..f686e66f37e 100644 --- a/sys/sun4v/include/intr_machdep.h +++ b/sys/sun4v/include/intr_machdep.h @@ -47,7 +47,6 @@ #define PIL_STOP 5 /* stop cpu ipi */ #define PIL_PREEMPT 6 /* preempt idle thread cpu ipi */ #define PIL_HARDCLOCK 7 /* hardclock broadcast */ -#define PIL_STATCLOCK 8 /* statclock broadcast */ #define PIL_FAST 13 /* fast interrupts */ #define PIL_TICK 14 diff --git a/sys/sun4v/include/smp.h b/sys/sun4v/include/smp.h index 56c50ebbaed..3202089cbf1 100644 --- a/sys/sun4v/include/smp.h +++ b/sys/sun4v/include/smp.h @@ -47,7 +47,6 @@ #define IPI_STOP_HARD PIL_STOP #define IPI_PREEMPT PIL_PREEMPT #define IPI_HARDCLOCK PIL_HARDCLOCK -#define IPI_STATCLOCK PIL_STATCLOCK #define IPI_RETRIES 5000 @@ -83,7 +82,6 @@ void cpu_ipi_ast(struct trapframe *tf); void cpu_ipi_stop(struct trapframe *tf); void cpu_ipi_preempt(struct trapframe *tf); void cpu_ipi_hardclock(struct trapframe *tf); -void cpu_ipi_statclock(struct trapframe *tf); void ipi_all_but_self(u_int ipi); void ipi_cpu(int cpu, u_int ipi); diff --git a/sys/sun4v/sun4v/bus_machdep.c b/sys/sun4v/sun4v/bus_machdep.c index 1282b0e79b9..7246f5f73a2 100644 --- a/sys/sun4v/sun4v/bus_machdep.c +++ b/sys/sun4v/sun4v/bus_machdep.c @@ -181,11 +181,8 @@ busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) static void dflt_lock(void *arg, bus_dma_lock_op_t op) { -#ifdef INVARIANTS + panic("driver error: busdma dflt_lock called"); -#else - printf("DRIVER_ERROR: busdma dflt_lock called\n"); -#endif } /* @@ -647,9 +644,18 @@ nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, if (flags & BUS_DMA_ZERO) mflags |= M_ZERO; - if ((dmat->dt_maxsize <= PAGE_SIZE)) { + /* + * XXX: + * (dmat->dt_alignment < dmat->dt_maxsize) is just a quick hack; the + * exact alignment guarantees of malloc need to be nailed down, and + * the code below should be rewritten to take that into account. + * + * In the meantime, we'll warn the user if malloc gets it wrong. + */ + if (dmat->dt_maxsize <= PAGE_SIZE && + dmat->dt_alignment < dmat->dt_maxsize) *vaddr = malloc(dmat->dt_maxsize, M_DEVBUF, mflags); - } else { + else { /* * XXX use contigmalloc until it is merged into this * facility and handles multi-seg allocations. Nobody @@ -662,6 +668,8 @@ nexus_dmamem_alloc(bus_dma_tag_t dmat, void **vaddr, int flags, } if (*vaddr == NULL) return (ENOMEM); + if ((uintptr_t)*vaddr % dmat->dt_alignment) + printf("%s: failed to align memory properly.\n", __func__); return (0); } @@ -673,11 +681,11 @@ static void nexus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) { - if ((dmat->dt_maxsize <= PAGE_SIZE)) + if (dmat->dt_maxsize <= PAGE_SIZE && + dmat->dt_alignment < dmat->dt_maxsize) free(vaddr, M_DEVBUF); - else { + else contigfree(vaddr, dmat->dt_maxsize, M_DEVBUF); - } } struct bus_dma_methods nexus_dma_methods = { diff --git a/sys/sun4v/sun4v/hviommu.c b/sys/sun4v/sun4v/hviommu.c index 5724d752c0e..78076e372be 100644 --- a/sys/sun4v/sun4v/hviommu.c +++ b/sys/sun4v/sun4v/hviommu.c @@ -513,9 +513,6 @@ hviommu_dvmamap_create(bus_dma_tag_t dt, int flags, bus_dmamap_t *mapp) */ maxpre = imin(dt->dt_nsegments, IOMMU_MAX_PRE_SEG); presz = dt->dt_maxsize / maxpre; - KASSERT(presz != 0, ("hviommu_dvmamap_create: bogus preallocation size " - ", nsegments = %d, maxpre = %d, maxsize = %lu", dt->dt_nsegments, - maxpre, dt->dt_maxsize)); for (i = 1; i < maxpre && totsz < IOMMU_MAX_PRE; i++) { currsz = round_io_page(ulmin(presz, IOMMU_MAX_PRE - totsz)); error = hviommu_dvma_valloc(dt, him, *mapp, currsz); diff --git a/sys/sun4v/sun4v/intr_machdep.c b/sys/sun4v/sun4v/intr_machdep.c index 123493ef5bf..358740237f5 100644 --- a/sys/sun4v/sun4v/intr_machdep.c +++ b/sys/sun4v/sun4v/intr_machdep.c @@ -110,8 +110,7 @@ static char *pil_names[] = { "stop", /* PIL_STOP */ "preempt", /* PIL_PREEMPT */ "hardclock", /* PIL_HARDCLOCK */ - "statclock", /* PIL_STATCLOCK */ - "stray", "stray", "stray", "stray", + "stray", "stray", "stray", "stray", "stray", "fast", /* PIL_FAST */ "tick", /* PIL_TICK */ }; @@ -265,7 +264,6 @@ intr_init(void) intr_handlers[PIL_STOP]= cpu_ipi_stop; intr_handlers[PIL_PREEMPT]= cpu_ipi_preempt; intr_handlers[PIL_HARDCLOCK]= cpu_ipi_hardclock; - intr_handlers[PIL_STATCLOCK]= cpu_ipi_statclock; #endif mtx_init(&intr_table_lock, "intr table", NULL, MTX_SPIN); cpu_intrq_alloc(); diff --git a/sys/sun4v/sun4v/mp_machdep.c b/sys/sun4v/sun4v/mp_machdep.c index 2e9a378d0ac..a9535e34d77 100644 --- a/sys/sun4v/sun4v/mp_machdep.c +++ b/sys/sun4v/sun4v/mp_machdep.c @@ -472,15 +472,18 @@ cpu_ipi_preempt(struct trapframe *tf) void cpu_ipi_hardclock(struct trapframe *tf) { + struct trapframe *oldframe; + struct thread *td; - hardclockintr(tf); -} - -void -cpu_ipi_statclock(struct trapframe *tf) -{ - - statclockintr(tf); + critical_enter(); + td = curthread; + td->td_intr_nesting_level++; + oldframe = td->td_intr_frame; + td->td_intr_frame = tf; + hardclockintr(); + td->td_intr_frame = oldframe; + td->td_intr_nesting_level--; + critical_exit(); } void diff --git a/sys/sun4v/sun4v/nexus.c b/sys/sun4v/sun4v/nexus.c index 2156a2306dc..125b2f71242 100644 --- a/sys/sun4v/sun4v/nexus.c +++ b/sys/sun4v/sun4v/nexus.c @@ -234,7 +234,7 @@ nexus_attach(device_t dev) } static device_t -nexus_add_child(device_t dev, int order, const char *name, int unit) +nexus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t cdev; struct nexus_devinfo *ndi; diff --git a/sys/sun4v/sun4v/trap.c b/sys/sun4v/sun4v/trap.c index d099351e3e6..cfc51350f02 100644 --- a/sys/sun4v/sun4v/trap.c +++ b/sys/sun4v/sun4v/trap.c @@ -42,7 +42,6 @@ #include "opt_ddb.h" #include "opt_ktr.h" -#include "opt_ktrace.h" #include #include @@ -62,10 +61,6 @@ #include #include #include -#ifdef KTRACE -#include -#include -#endif #include diff --git a/sys/sun4v/sun4v/vnex.c b/sys/sun4v/sun4v/vnex.c index 305d0bba7b9..d2554ebf4f4 100644 --- a/sys/sun4v/sun4v/vnex.c +++ b/sys/sun4v/sun4v/vnex.c @@ -204,7 +204,7 @@ vnex_attach(device_t dev) } static device_t -vnex_add_child(device_t dev, int order, const char *name, int unit) +vnex_add_child(device_t dev, u_int order, const char *name, int unit) { device_t cdev; struct vnex_devinfo *vndi; diff --git a/sys/sys/_rmlock.h b/sys/sys/_rmlock.h index e5c68d54732..75a159c1082 100644 --- a/sys/sys/_rmlock.h +++ b/sys/sys/_rmlock.h @@ -45,11 +45,15 @@ LIST_HEAD(rmpriolist,rm_priotracker); struct rmlock { struct lock_object lock_object; - volatile int rm_noreadtoken; + volatile cpumask_t rm_writecpus; LIST_HEAD(,rm_priotracker) rm_activeReaders; - struct mtx rm_lock; - + union { + struct mtx _rm_lock_mtx; + struct sx _rm_lock_sx; + } _rm_lock; }; +#define rm_lock_mtx _rm_lock._rm_lock_mtx +#define rm_lock_sx _rm_lock._rm_lock_sx struct rm_priotracker { struct rm_queue rmp_cpuQueue; /* Must be first */ diff --git a/sys/sys/_task.h b/sys/sys/_task.h index c3f94323ebd..11fd1bc0d09 100644 --- a/sys/sys/_task.h +++ b/sys/sys/_task.h @@ -44,7 +44,6 @@ typedef void task_fn_t(void *context, int pending); struct task { - struct task **ta_running; /* (q) queue's running task pointer */ STAILQ_ENTRY(task) ta_link; /* (q) link for queue */ u_short ta_pending; /* (q) count times queued */ u_short ta_priority; /* (c) Priority */ diff --git a/sys/sys/acl.h b/sys/sys/acl.h index 80a3fe61637..614d01165f5 100644 --- a/sys/sys/acl.h +++ b/sys/sys/acl.h @@ -285,6 +285,8 @@ mode_t acl_posix1e_newfilemode(mode_t cmode, struct acl *acl_alloc(int flags); void acl_free(struct acl *aclp); +void acl_nfs4_trivial_from_mode(struct acl *aclp, + mode_t mode); void acl_nfs4_sync_acl_from_mode(struct acl *aclp, mode_t mode, int file_owner_id); void acl_nfs4_sync_mode_from_acl(mode_t *mode, diff --git a/sys/sys/bio.h b/sys/sys/bio.h index 8b6ff0ec696..c016ee67b90 100644 --- a/sys/sys/bio.h +++ b/sys/sys/bio.h @@ -54,6 +54,7 @@ #define BIO_ERROR 0x01 #define BIO_DONE 0x02 #define BIO_ONQUEUE 0x04 +#define BIO_ORDERED 0x08 #ifdef _KERNEL struct disk; diff --git a/sys/sys/bus.h b/sys/sys/bus.h index 1e01fe836f4..88a0f60cd7e 100644 --- a/sys/sys/bus.h +++ b/sys/sys/bus.h @@ -298,7 +298,7 @@ void root_bus_configure(void); int bus_generic_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r); device_t - bus_generic_add_child(device_t dev, int order, const char *name, + bus_generic_add_child(device_t dev, u_int order, const char *name, int unit); struct resource * bus_generic_alloc_resource(device_t bus, device_t child, int type, @@ -410,7 +410,7 @@ bus_alloc_resource_any(device_t dev, int type, int *rid, u_int flags) * Access functions for device. */ device_t device_add_child(device_t dev, const char *name, int unit); -device_t device_add_child_ordered(device_t dev, int order, +device_t device_add_child_ordered(device_t dev, u_int order, const char *name, int unit); void device_busy(device_t dev); int device_delete_child(device_t dev, device_t child); diff --git a/sys/sys/callout.h b/sys/sys/callout.h index 2d43d1494ae..c0077a89774 100644 --- a/sys/sys/callout.h +++ b/sys/sys/callout.h @@ -96,7 +96,8 @@ int callout_schedule_on(struct callout *, int, int); #define callout_stop(c) _callout_stop_safe(c, 0) int _callout_stop_safe(struct callout *, int); void callout_tick(void); - +int callout_tickstofirst(int limit); +extern void (*callout_new_inserted)(int cpu, int ticks); #endif diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h index f8456d89541..bcb4367f30c 100644 --- a/sys/sys/cdefs.h +++ b/sys/sys/cdefs.h @@ -306,8 +306,8 @@ #endif #if __GNUC_PREREQ__(4, 2) -#define __hidden __attribute((visibility("hidden"))) -#define __exported __attribute((visibility("default"))) +#define __hidden __attribute__((__visibility__("hidden"))) +#define __exported __attribute__((__visibility__("default"))) #else #define __hidden #define __exported diff --git a/sys/sys/conf.h b/sys/sys/conf.h index 6c606011060..5f1ef18144b 100644 --- a/sys/sys/conf.h +++ b/sys/sys/conf.h @@ -263,11 +263,12 @@ struct cdev *make_dev(struct cdevsw *_devsw, int _unit, uid_t _uid, gid_t _gid, struct cdev *make_dev_cred(struct cdevsw *_devsw, int _unit, struct ucred *_cr, uid_t _uid, gid_t _gid, int _perms, const char *_fmt, ...) __printflike(7, 8); -#define MAKEDEV_REF 0x01 -#define MAKEDEV_WHTOUT 0x02 -#define MAKEDEV_NOWAIT 0x04 -#define MAKEDEV_WAITOK 0x08 -#define MAKEDEV_ETERNAL 0x10 +#define MAKEDEV_REF 0x01 +#define MAKEDEV_WHTOUT 0x02 +#define MAKEDEV_NOWAIT 0x04 +#define MAKEDEV_WAITOK 0x08 +#define MAKEDEV_ETERNAL 0x10 +#define MAKEDEV_CHECKNAME 0x20 struct cdev *make_dev_credf(int _flags, struct cdevsw *_devsw, int _unit, struct ucred *_cr, uid_t _uid, gid_t _gid, int _mode, diff --git a/sys/sys/copyright.h b/sys/sys/copyright.h index 62a4ac9d920..b70782da085 100644 --- a/sys/sys/copyright.h +++ b/sys/sys/copyright.h @@ -27,7 +27,7 @@ /* Copyrights macros */ - + /* FreeBSD */ #define COPYRIGHT_FreeBSD \ "Copyright (c) 1992-2010 The FreeBSD Project.\n" diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index c6584949fe3..31cefd1eb12 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -52,7 +52,7 @@ /* XXX these should be defined per controller (or drive) elsewhere, not here! */ #if defined(__i386__) || defined(__amd64__) || defined(__arm__) || \ - defined(__ia64__) || defined(__powerpc__) + defined(__ia64__) || defined(__powerpc__) || defined(__mips__) #define LABELSECTOR 1 /* sector containing label */ #define LABELOFFSET 0 /* offset of label in sector */ #endif diff --git a/sys/sys/dtrace_bsd.h b/sys/sys/dtrace_bsd.h index a14a1a160f3..2eded7b689a 100644 --- a/sys/sys/dtrace_bsd.h +++ b/sys/sys/dtrace_bsd.h @@ -37,6 +37,7 @@ struct trapframe; struct thread; struct vattr; struct vnode; +struct reg; /* * Cyclic clock function type definition used to hook the cyclic @@ -71,6 +72,14 @@ typedef void (*dtrace_doubletrap_func_t)(void); extern dtrace_invop_func_t dtrace_invop_func; extern dtrace_doubletrap_func_t dtrace_doubletrap_func; +/* Pid provider hooks */ +typedef int (*dtrace_fasttrap_probe_ptr_t)(struct reg *); +extern dtrace_fasttrap_probe_ptr_t dtrace_fasttrap_probe_ptr; +typedef int (*dtrace_pid_probe_ptr_t)(struct reg *); +extern dtrace_pid_probe_ptr_t dtrace_pid_probe_ptr; +typedef int (*dtrace_return_probe_ptr_t)(struct reg *); +extern dtrace_return_probe_ptr_t dtrace_return_probe_ptr; + /* Virtual time hook function type. */ typedef void (*dtrace_vtime_switch_func_t)(struct thread *); diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index 5d43634d132..1e1154f3896 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -388,7 +388,7 @@ typedef struct { #define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING and less than DT_LOOS follow the rules for the interpretation of the d_un union - as follows: even == 'd_ptr', even == 'd_val' + as follows: even == 'd_ptr', odd == 'd_val' or none */ #define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to pre-initialization functions. */ @@ -471,6 +471,7 @@ typedef struct { #define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */ #define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */ #define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */ +#define DF_1_LOADFLTR 0x00000010 /* Immediate loading of filtees */ #define DF_1_NOOPEN 0x00000040 /* Do not allow loading on dlopen() */ #define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */ diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 8c95c36e687..140ab2e6df5 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -115,7 +115,8 @@ int exec_unregister(const struct execsw *); __CONCAT(name,_modevent), \ (void *)& execsw_arg \ }; \ - DECLARE_MODULE(name, __CONCAT(name,_mod), SI_SUB_EXEC, SI_ORDER_ANY) + DECLARE_MODULE_TIED(name, __CONCAT(name,_mod), SI_SUB_EXEC, \ + SI_ORDER_ANY) #endif #endif diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h new file mode 100644 index 00000000000..b1f3ba8f889 --- /dev/null +++ b/sys/sys/gpio.h @@ -0,0 +1,97 @@ +/* $NetBSD: gpio.h,v 1.7 2009/09/25 20:27:50 mbalmer Exp $ */ +/* $OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $ */ +/*- + * Copyright (c) 2009, Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ + * + */ + +/* + * Copyright (c) 2009 Marc Balmer + * Copyright (c) 2004 Alexander Yurchenko + * + * Permission to use, copy, modify, and 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. + */ + +#ifndef __GPIO_H__ +#define __GPIO_H__ + +#include + +/* GPIO pin states */ +#define GPIO_PIN_LOW 0x00 /* low level (logical 0) */ +#define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */ + +/* Max name length of a pin */ +#define GPIOMAXNAME 64 + +/* GPIO pin configuration flags */ +#define GPIO_PIN_INPUT 0x0001 /* input direction */ +#define GPIO_PIN_OUTPUT 0x0002 /* output direction */ +#define GPIO_PIN_OPENDRAIN 0x0004 /* open-drain output */ +#define GPIO_PIN_PUSHPULL 0x0008 /* push-pull output */ +#define GPIO_PIN_TRISTATE 0x0010 /* output disabled */ +#define GPIO_PIN_PULLUP 0x0020 /* internal pull-up enabled */ +#define GPIO_PIN_PULLDOWN 0x0040 /* internal pull-down enabled */ +#define GPIO_PIN_INVIN 0x0080 /* invert input */ +#define GPIO_PIN_INVOUT 0x0100 /* invert output */ +#define GPIO_PIN_PULSATE 0x0200 /* pulsate in hardware */ + +struct gpio_pin { + uint32_t gp_pin; /* pin number */ + char gp_name[GPIOMAXNAME]; /* human-readable name */ + uint32_t gp_caps; /* capabilities */ + uint32_t gp_flags; /* current flags */ +}; + +/* GPIO pin request (read/write/toggle) */ +struct gpio_req { + uint32_t gp_pin; /* pin number */ + uint32_t gp_value; /* value */ +}; + +/* + * ioctls + */ +#define GPIOMAXPIN _IOR('G', 0, int) +#define GPIOGETCONFIG _IOWR('G', 1, struct gpio_pin) +#define GPIOSETCONFIG _IOW('G', 2, struct gpio_pin) +#define GPIOGET _IOWR('G', 3, struct gpio_req) +#define GPIOSET _IOW('G', 4, struct gpio_req) +#define GPIOTOGGLE _IOWR('G', 5, struct gpio_req) + +#endif /* __GPIO_H__ */ diff --git a/sys/sys/gpt.h b/sys/sys/gpt.h index a3e39f23d7f..aa0a582310d 100644 --- a/sys/sys/gpt.h +++ b/sys/sys/gpt.h @@ -65,6 +65,9 @@ struct gpt_ent { uint64_t ent_lba_end; uint64_t ent_attr; #define GPT_ENT_ATTR_PLATFORM (1ULL << 0) +#define GPT_ENT_ATTR_BOOTME (1ULL << 59) +#define GPT_ENT_ATTR_BOOTONCE (1ULL << 58) +#define GPT_ENT_ATTR_BOOTFAILED (1ULL << 57) uint16_t ent_name[36]; /* UTF-16. */ }; diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h index 8c183ad70cb..b54815fc62c 100644 --- a/sys/sys/imgact.h +++ b/sys/sys/imgact.h @@ -71,6 +71,10 @@ struct image_params { char *execpath; unsigned long execpathp; char *freepath; + unsigned long canary; + int canarylen; + unsigned long pagesizes; + int pagesizeslen; }; #ifdef _KERNEL diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index b5aa473e737..9f8810c9f30 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -73,10 +73,6 @@ struct ktr_header { if (KTRCHECKDRAIN(td)) \ ktruserret(td); \ } while (0) -#define KTRPROCEXIT(td) do { \ - if (KTRCHECKDRAIN(td)) \ - ktrprocexit(td); \ -} while (0) /* * ktrace record types @@ -195,8 +191,6 @@ struct stat; #define KTRFAC_DROP 0x20000000 /* last event was dropped */ #ifdef _KERNEL -extern struct mtx ktrace_mtx; - void ktrnamei(char *); void ktrcsw(int, int); void ktrpsig(int, sig_t, sigset_t *, int); @@ -204,7 +198,9 @@ void ktrgenio(int, enum uio_rw, struct uio *, int); void ktrsyscall(int, int narg, register_t args[]); void ktrsysctl(int *name, u_int namelen); void ktrsysret(int, int, register_t); +void ktrprocexec(struct proc *, struct ucred **, struct vnode **); void ktrprocexit(struct thread *); +void ktrprocfork(struct proc *, struct proc *); void ktruserret(struct thread *); void ktrstruct(const char *, void *, size_t); #define ktrsockaddr(s) \ diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h index 98840a51988..93fe1de1964 100644 --- a/sys/sys/link_elf.h +++ b/sys/sys/link_elf.h @@ -92,6 +92,7 @@ __BEGIN_DECLS typedef int (*__dl_iterate_hdr_callback)(struct dl_phdr_info *, size_t, void *); extern int dl_iterate_phdr(__dl_iterate_hdr_callback, void *); +int _rtld_addr_phdr(const void *, struct dl_phdr_info *); __END_DECLS diff --git a/sys/sys/lock.h b/sys/sys/lock.h index 85d8bb824cd..7ad9c58c15d 100644 --- a/sys/sys/lock.h +++ b/sys/sys/lock.h @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from BSDI $Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp Exp $ + * from BSDI Id: mutex.h,v 2.7.2.35 2000/04/27 03:10:26 cp * $FreeBSD$ */ diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h index 545dfa26abd..4c3a272abde 100644 --- a/sys/sys/lockmgr.h +++ b/sys/sys/lockmgr.h @@ -73,7 +73,10 @@ void _lockmgr_assert(struct lock *lk, int what, const char *file, int line); #endif void _lockmgr_disown(struct lock *lk, const char *file, int line); +void lockallowrecurse(struct lock *lk); +void lockallowshare(struct lock *lk); void lockdestroy(struct lock *lk); +void lockdisablerecurse(struct lock *lk); void lockinit(struct lock *lk, int prio, const char *wmesg, int timo, int flags); #ifdef DDB diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 95a44a4aecf..654f1450b5e 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -903,6 +903,7 @@ struct mbuf *m_unshare(struct mbuf *, int how); #define PACKET_TAG_IPOPTIONS 27 /* Saved IP options */ #define PACKET_TAG_CARP 28 /* CARP info */ #define PACKET_TAG_IPSEC_NAT_T_PORTS 29 /* two uint16_t */ +#define PACKET_TAG_ND_OUTGOING 30 /* ND outgoing */ /* Specific cookies and tags. */ diff --git a/sys/sys/mman.h b/sys/sys/mman.h index 12c013383de..379ed14b72b 100644 --- a/sys/sys/mman.h +++ b/sys/sys/mman.h @@ -90,6 +90,7 @@ * Extended flags */ #define MAP_NOCORE 0x00020000 /* dont include these pages in a coredump */ +#define MAP_PREFAULT_READ 0x00040000 /* prefault mapping for reading */ #endif /* __BSD_VISIBLE */ #if __POSIX_VISIBLE >= 199309 diff --git a/sys/sys/module.h b/sys/sys/module.h index 2abad63f9ec..782770a73df 100644 --- a/sys/sys/module.h +++ b/sys/sys/module.h @@ -125,13 +125,26 @@ struct mod_metadata { */ #define MODULE_KERNEL_MAXVER (roundup(__FreeBSD_version, 100000) - 1) -#define DECLARE_MODULE(name, data, sub, order) \ +#define DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, maxver) \ MODULE_DEPEND(name, kernel, __FreeBSD_version, \ - __FreeBSD_version, MODULE_KERNEL_MAXVER); \ + __FreeBSD_version, maxver); \ MODULE_METADATA(_md_##name, MDT_MODULE, &data, #name); \ SYSINIT(name##module, sub, order, module_register_init, &data); \ struct __hack +#define DECLARE_MODULE(name, data, sub, order) \ + DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, MODULE_KERNEL_MAXVER) + +/* + * The module declared with DECLARE_MODULE_TIED can only be loaded + * into the kernel with exactly the same __FreeBSD_version. + * + * Use it for modules that use kernel interfaces that are not stable + * even on STABLE/X branches. + */ +#define DECLARE_MODULE_TIED(name, data, sub, order) \ + DECLARE_MODULE_WITH_MAXVER(name, data, sub, order, __FreeBSD_version) + #define MODULE_VERSION(module, version) \ static struct mod_version _##module##_version = { \ version \ diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 20dcf641c7b..be605b482f3 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -56,7 +56,7 @@ typedef struct fsid { int32_t val[2]; } fsid_t; /* filesystem id type */ struct fid { u_short fid_len; /* length of data in bytes */ - u_short fid_reserved; /* force longword alignment */ + u_short fid_data0; /* force longword alignment */ char fid_data[MAXFIDSZ]; /* data (variable length) */ }; @@ -730,7 +730,8 @@ void vfs_msync(struct mount *, int); int vfs_busy(struct mount *, int); int vfs_export /* process mount export info */ (struct mount *, struct export_args *); -int vfs_allocate_syncvnode(struct mount *); +void vfs_allocate_syncvnode(struct mount *); +void vfs_deallocate_syncvnode(struct mount *); int vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions); void vfs_getnewfsid(struct mount *); struct cdev *vfs_getrootfsid(struct mount *); @@ -740,6 +741,8 @@ int vfs_modevent(module_t, int, void *); void vfs_mount_error(struct mount *, const char *, ...); void vfs_mountroot(void); /* mount our root filesystem */ void vfs_mountedfrom(struct mount *, const char *from); +void vfs_oexport_conv(const struct oexport_args *oexp, + struct export_args *exp); void vfs_ref(struct mount *); void vfs_rel(struct mount *); struct mount *vfs_mount_alloc(struct vnode *, struct vfsconf *, const char *, diff --git a/sys/sys/mutex.h b/sys/sys/mutex.h index 929bf439722..5800f8043fa 100644 --- a/sys/sys/mutex.h +++ b/sys/sys/mutex.h @@ -251,8 +251,11 @@ void _thread_lock_flags(struct thread *, int, const char *, int); #define _rel_spin_lock(mp) do { \ if (mtx_recursed((mp))) \ (mp)->mtx_recurse--; \ - else \ + else { \ + LOCKSTAT_PROFILE_RELEASE_LOCK(LS_MTX_SPIN_UNLOCK_RELEASE, \ + mp); \ (mp)->mtx_lock = MTX_UNOWNED; \ + } \ spinlock_exit(); \ } while (0) #endif /* SMP */ diff --git a/sys/sys/param.h b/sys/sys/param.h index 7e781d2f526..ea64e399d06 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 900016 /* Master, propagated to newvers */ +#define __FreeBSD_version 900023 /* Master, propagated to newvers */ #ifndef LOCORE #include @@ -73,7 +73,7 @@ #include #define MAXCOMLEN 19 /* max command name remembered */ -#define MAXINTERP 32 /* max interpreter file name length */ +#define MAXINTERP PATH_MAX /* max interpreter file name length */ #define MAXLOGNAME 17 /* max login name length (incl. NUL) */ #define MAXUPRC CHILD_MAX /* max simultaneous processes */ #define NCARGS ARG_MAX /* max bytes for an exec function */ diff --git a/sys/sys/pcpu.h b/sys/sys/pcpu.h index 7d510c9ae7f..75017d6c6bc 100644 --- a/sys/sys/pcpu.h +++ b/sys/sys/pcpu.h @@ -44,24 +44,10 @@ /* * Define a set for pcpu data. - * - * We don't use SET_DECLARE because it defines the set as 'a' when we - * want 'aw'. gcc considers uninitialized data in a separate section - * writable, and there is no generic zero initializer that works for - * structs and scalars. */ extern uintptr_t *__start_set_pcpu; extern uintptr_t *__stop_set_pcpu; -__asm__( -#ifdef __arm__ - ".section set_pcpu, \"aw\", %progbits\n" -#else - ".section set_pcpu, \"aw\", @progbits\n" -#endif - "\t.p2align " __XSTRING(CACHE_LINE_SHIFT) "\n" - "\t.previous"); - /* * Array of dynamic pcpu base offsets. Indexed by id. */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 336279ea02a..02f228c910f 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -205,6 +205,7 @@ struct thread { TAILQ_ENTRY(thread) td_runq; /* (t) Run queue. */ TAILQ_ENTRY(thread) td_slpq; /* (t) Sleep queue. */ TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */ + LIST_ENTRY(thread) td_hash; /* (d) Hash chain. */ struct cpuset *td_cpuset; /* (t) CPU affinity mask. */ struct seltd *td_sel; /* Select queue/channel. */ struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */ @@ -262,7 +263,8 @@ struct thread { struct ksiginfo td_dbgksi; /* (c) ksi reflected to debugger. */ int td_ng_outbound; /* (k) Thread entered ng from above. */ struct osd td_osd; /* (k) Object specific data. */ -#define td_endzero td_base_pri + struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ +#define td_endzero td_rqindex /* Copied during fork1() or thread_sched_upcall(). */ #define td_startcopy td_endzero @@ -351,7 +353,7 @@ do { \ #define TDF_NEEDRESCHED 0x00010000 /* Thread needs to yield. */ #define TDF_NEEDSIGCHK 0x00020000 /* Thread may need signal delivery. */ #define TDF_NOLOAD 0x00040000 /* Ignore during load avg calculations. */ -#define TDF_UNUSED19 0x00080000 /* Thread is sleeping on a umtx. */ +#define TDF_UNUSED19 0x00080000 /* --available-- */ #define TDF_THRWAKEUP 0x00100000 /* Libthr thread must not suspend itself. */ #define TDF_UNUSED21 0x00200000 /* --available-- */ #define TDF_SWAPINREQ 0x00400000 /* Swapin request due to wakeup. */ @@ -765,6 +767,10 @@ MALLOC_DECLARE(M_ZOMBIE); #define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash]) extern LIST_HEAD(pidhashhead, proc) *pidhashtbl; extern u_long pidhash; +#define TIDHASH(tid) (&tidhashtbl[(tid) & tidhash]) +extern LIST_HEAD(tidhashhead, thread) *tidhashtbl; +extern u_long tidhash; +extern struct rwlock tidhash_lock; #define PGRPHASH(pgid) (&pgrphashtbl[(pgid) & pgrphash]) extern LIST_HEAD(pgrphashhead, pgrp) *pgrphashtbl; @@ -836,7 +842,10 @@ void setsugid(struct proc *p); int sigonstack(size_t sp); void sleepinit(void); void stopevent(struct proc *, u_int, u_int); +struct thread *tdfind(lwpid_t, pid_t); void threadinit(void); +void tidhash_add(struct thread *); +void tidhash_remove(struct thread *); void cpu_idle(int); int cpu_idle_wakeup(int); extern void (*cpu_idle_hook)(void); /* Hook to machdep CPU idler. */ diff --git a/sys/sys/rmlock.h b/sys/sys/rmlock.h index 9766f670d2a..ef5776bcec3 100644 --- a/sys/sys/rmlock.h +++ b/sys/sys/rmlock.h @@ -33,6 +33,7 @@ #define _SYS_RMLOCK_H_ #include +#include #include #include @@ -43,6 +44,7 @@ */ #define RM_NOWITNESS 0x00000001 #define RM_RECURSE 0x00000002 +#define RM_SLEEPABLE 0x00000004 void rm_init(struct rmlock *rm, const char *name); void rm_init_flags(struct rmlock *rm, const char *name, int opts); @@ -53,14 +55,15 @@ void rm_sysinit_flags(void *arg); void _rm_wlock_debug(struct rmlock *rm, const char *file, int line); void _rm_wunlock_debug(struct rmlock *rm, const char *file, int line); -void _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, - const char *file, int line); +int _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, + int trylock, const char *file, int line); void _rm_runlock_debug(struct rmlock *rm, struct rm_priotracker *tracker, const char *file, int line); void _rm_wlock(struct rmlock *rm); void _rm_wunlock(struct rmlock *rm); -void _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker); +int _rm_rlock(struct rmlock *rm, struct rm_priotracker *tracker, + int trylock); void _rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker); /* @@ -74,14 +77,17 @@ void _rm_runlock(struct rmlock *rm, struct rm_priotracker *tracker); #define rm_wlock(rm) _rm_wlock_debug((rm), LOCK_FILE, LOCK_LINE) #define rm_wunlock(rm) _rm_wunlock_debug((rm), LOCK_FILE, LOCK_LINE) #define rm_rlock(rm,tracker) \ - _rm_rlock_debug((rm),(tracker), LOCK_FILE, LOCK_LINE ) + ((void)_rm_rlock_debug((rm),(tracker), 0, LOCK_FILE, LOCK_LINE )) +#define rm_try_rlock(rm,tracker) \ + _rm_rlock_debug((rm),(tracker), 1, LOCK_FILE, LOCK_LINE ) #define rm_runlock(rm,tracker) \ _rm_runlock_debug((rm), (tracker), LOCK_FILE, LOCK_LINE ) #else -#define rm_wlock(rm) _rm_wlock((rm)) -#define rm_wunlock(rm) _rm_wunlock((rm)) -#define rm_rlock(rm,tracker) _rm_rlock((rm),(tracker)) -#define rm_runlock(rm,tracker) _rm_runlock((rm), (tracker)) +#define rm_wlock(rm) _rm_wlock((rm)) +#define rm_wunlock(rm) _rm_wunlock((rm)) +#define rm_rlock(rm,tracker) ((void)_rm_rlock((rm),(tracker), 0)) +#define rm_try_rlock(rm,tracker) _rm_rlock((rm),(tracker), 1) +#define rm_runlock(rm,tracker) _rm_runlock((rm), (tracker)) #endif struct rm_args { diff --git a/sys/sys/sbuf.h b/sys/sys/sbuf.h index fce24beeed1..eeb38140da5 100644 --- a/sys/sys/sbuf.h +++ b/sys/sys/sbuf.h @@ -33,12 +33,17 @@ #include +struct sbuf; +typedef int (sbuf_drain_func)(void *, const char *, int); + /* * Structure definition */ struct sbuf { char *s_buf; /* storage buffer */ - void *s_unused; /* binary compatibility. */ + sbuf_drain_func *s_drain_func; /* drain function */ + void *s_drain_arg; /* user-supplied drain argument */ + int s_error; /* current error code */ int s_size; /* size of storage buffer */ int s_len; /* current length of string */ #define SBUF_FIXEDLEN 0x00000000 /* fixed length buffer (default) */ @@ -46,7 +51,6 @@ struct sbuf { #define SBUF_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */ #define SBUF_DYNAMIC 0x00010000 /* s_buf must be freed */ #define SBUF_FINISHED 0x00020000 /* set by sbuf_finish() */ -#define SBUF_OVERFLOWED 0x00040000 /* sbuf overflowed */ #define SBUF_DYNSTRUCT 0x00080000 /* sbuf must be freed */ int s_flags; /* flags */ }; @@ -69,9 +73,10 @@ int sbuf_printf(struct sbuf *, const char *, ...) int sbuf_vprintf(struct sbuf *, const char *, __va_list) __printflike(2, 0); int sbuf_putc(struct sbuf *, int); +void sbuf_set_drain(struct sbuf *, sbuf_drain_func *, void *); int sbuf_trim(struct sbuf *); -int sbuf_overflowed(struct sbuf *); -void sbuf_finish(struct sbuf *); +int sbuf_error(struct sbuf *); +int sbuf_finish(struct sbuf *); char *sbuf_data(struct sbuf *); int sbuf_len(struct sbuf *); int sbuf_done(struct sbuf *); diff --git a/sys/sys/sched.h b/sys/sys/sched.h index d0ebffd5684..f9c88c50296 100644 --- a/sys/sys/sched.h +++ b/sys/sys/sched.h @@ -111,7 +111,7 @@ void sched_preempt(struct thread *td); void sched_add(struct thread *td, int flags); void sched_clock(struct thread *td); void sched_rem(struct thread *td); -void sched_tick(void); +void sched_tick(int cnt); void sched_relinquish(struct thread *td); struct thread *sched_choose(void); void sched_idletd(void *); @@ -173,7 +173,7 @@ static void name ## _add_proc(void *dummy __unused) \ #name, CTLTYPE_LONG|CTLFLAG_RD|CTLFLAG_MPSAFE, \ ptr, 0, sysctl_dpcpu_long, "LU", descr); \ } \ -SYSINIT(name, SI_SUB_RUN_SCHEDULER, SI_ORDER_ANY, name ## _add_proc, NULL); +SYSINIT(name, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE, name ## _add_proc, NULL); #define SCHED_STAT_DEFINE(name, descr) \ DPCPU_DEFINE(unsigned long, name); \ diff --git a/sys/sys/sdt.h b/sys/sys/sdt.h index eeae665c141..d9031023c4c 100644 --- a/sys/sys/sdt.h +++ b/sys/sys/sdt.h @@ -31,33 +31,66 @@ #ifndef _SYS_SDT_H #define _SYS_SDT_H -/* Stub these for the time being. */ -#define DTRACE_PROBE(name) -#define DTRACE_PROBE1(name, type1, arg1) -#define DTRACE_PROBE2(name, type1, arg1, type2, arg2) -#define DTRACE_PROBE3(name, type1, arg1, type2, arg2, type3, arg3) -#define DTRACE_PROBE4(name, type1, arg1, type2, arg2, type3, arg3, type4, arg4) - #ifndef _KERNEL -/* The promise of things to come. Worlds to explore. People to meet. Things to do. */ +#define _DTRACE_VERSION 1 -#else +#define DTRACE_PROBE(prov, name) { \ + extern void __dtrace_##prov##___##name(void); \ + __dtrace_##prov##___##name(); \ +} + +#define DTRACE_PROBE1(prov, name, arg1) { \ + extern void __dtrace_##prov##___##name(unsigned long); \ + __dtrace_##prov##___##name((unsigned long)arg1); \ +} + +#define DTRACE_PROBE2(prov, name, arg1, arg2) { \ + extern void __dtrace_##prov##___##name(unsigned long, \ + unsigned long); \ + __dtrace_##prov##___##name((unsigned long)arg1, \ + (unsigned long)arg2); \ +} + +#define DTRACE_PROBE3(prov, name, arg1, arg2, arg3) { \ + extern void __dtrace_##prov##___##name(unsigned long, \ + unsigned long, unsigned long); \ + __dtrace_##prov##___##name((unsigned long)arg1, \ + (unsigned long)arg2, (unsigned long)arg3); \ +} + +#define DTRACE_PROBE4(prov, name, arg1, arg2, arg3, arg4) { \ + extern void __dtrace_##prov##___##name(unsigned long, \ + unsigned long, unsigned long, unsigned long); \ + __dtrace_##prov##___##name((unsigned long)arg1, \ + (unsigned long)arg2, (unsigned long)arg3, \ + (unsigned long)arg4); \ +} + +#define DTRACE_PROBE5(prov, name, arg1, arg2, arg3, arg4, arg5) { \ + extern void __dtrace_##prov##___##name(unsigned long, \ + unsigned long, unsigned long, unsigned long, unsigned long);\ + __dtrace_##prov##___##name((unsigned long)arg1, \ + (unsigned long)arg2, (unsigned long)arg3, \ + (unsigned long)arg4, (unsigned long)arg5); \ +} + +#else /* _KERNEL */ #ifndef KDTRACE_HOOKS #define SDT_PROVIDER_DEFINE(prov) #define SDT_PROVIDER_DECLARE(prov) -#define SDT_PROBE_DEFINE(prov, mod, func, name) +#define SDT_PROBE_DEFINE(prov, mod, func, name, sname) #define SDT_PROBE_DECLARE(prov, mod, func, name) #define SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE_ARGTYPE(prov, mod, func, name, num, type) -#define SDT_PROBE_DEFINE1(prov, mod, func, name, arg0) -#define SDT_PROBE_DEFINE2(prov, mod, func, name, arg0, arg1) -#define SDT_PROBE_DEFINE3(prov, mod, func, name, arg0, arg1, arg2) -#define SDT_PROBE_DEFINE4(prov, mod, func, name, arg0, arg1, arg2, arg3) -#define SDT_PROBE_DEFINE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) +#define SDT_PROBE_DEFINE1(prov, mod, func, name, sname, arg0) +#define SDT_PROBE_DEFINE2(prov, mod, func, name, sname, arg0, arg1) +#define SDT_PROBE_DEFINE3(prov, mod, func, name, sname, arg0, arg1, arg2) +#define SDT_PROBE_DEFINE4(prov, mod, func, name, sname, arg0, arg1, arg2, arg3) +#define SDT_PROBE_DEFINE5(prov, mod, func, name, sname, arg0, arg1, arg2, arg3, arg4) #define SDT_PROBE1(prov, mod, func, name, arg0) #define SDT_PROBE2(prov, mod, func, name, arg0, arg1) @@ -135,10 +168,10 @@ struct sdt_provider { #define SDT_PROVIDER_DECLARE(prov) \ extern struct sdt_provider sdt_provider_##prov[1] -#define SDT_PROBE_DEFINE(prov, mod, func, name) \ +#define SDT_PROBE_DEFINE(prov, mod, func, name, sname) \ struct sdt_probe sdt_##prov##_##mod##_##func##_##name[1] = { \ { sizeof(struct sdt_probe), 0, sdt_provider_##prov, \ - { NULL, NULL }, { NULL, NULL }, #mod, #func, #name, 0, 0 } \ + { NULL, NULL }, { NULL, NULL }, #mod, #func, #sname, 0, 0 } \ }; \ SYSINIT(sdt_##prov##_##mod##_##func##_##name##_init, SI_SUB_KDTRACE, \ SI_ORDER_SECOND + 1, sdt_probe_register, \ @@ -168,30 +201,30 @@ struct sdt_provider { SI_SUB_KDTRACE, SI_ORDER_SECOND + 2, sdt_argtype_deregister, \ sdt_##prov##_##mod##_##func##_##name##num ) -#define SDT_PROBE_DEFINE1(prov, mod, func, name, arg0) \ - SDT_PROBE_DEFINE(prov, mod, func, name); \ +#define SDT_PROBE_DEFINE1(prov, mod, func, name, sname, arg0) \ + SDT_PROBE_DEFINE(prov, mod, func, name, sname); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0) -#define SDT_PROBE_DEFINE2(prov, mod, func, name, arg0, arg1) \ - SDT_PROBE_DEFINE(prov, mod, func, name); \ +#define SDT_PROBE_DEFINE2(prov, mod, func, name, sname, arg0, arg1) \ + SDT_PROBE_DEFINE(prov, mod, func, name, sname); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1) -#define SDT_PROBE_DEFINE3(prov, mod, func, name, arg0, arg1, arg2) \ - SDT_PROBE_DEFINE(prov, mod, func, name); \ +#define SDT_PROBE_DEFINE3(prov, mod, func, name, sname, arg0, arg1, arg2)\ + SDT_PROBE_DEFINE(prov, mod, func, name, sname); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2) -#define SDT_PROBE_DEFINE4(prov, mod, func, name, arg0, arg1, arg2, arg3) \ - SDT_PROBE_DEFINE(prov, mod, func, name); \ +#define SDT_PROBE_DEFINE4(prov, mod, func, name, sname, arg0, arg1, arg2, arg3) \ + SDT_PROBE_DEFINE(prov, mod, func, name, sname); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3) -#define SDT_PROBE_DEFINE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) \ - SDT_PROBE_DEFINE(prov, mod, func, name); \ +#define SDT_PROBE_DEFINE5(prov, mod, func, name, sname, arg0, arg1, arg2, arg3, arg4) \ + SDT_PROBE_DEFINE(prov, mod, func, name, sname); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1); \ SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2); \ diff --git a/sys/sys/signal.h b/sys/sys/signal.h index a7ca96e37d2..85116430fcc 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -266,6 +266,7 @@ typedef struct __siginfo { /* codes for SIGTRAP */ #define TRAP_BRKPT 1 /* Process breakpoint. */ #define TRAP_TRACE 2 /* Process trace trap. */ +#define TRAP_DTRACE 3 /* DTrace induced trap. */ /* codes for SIGCHLD */ #define CLD_EXITED 1 /* Child has exited */ @@ -338,6 +339,7 @@ struct sigaction { #define SI_MESGQ 0x10005 /* Signal generated by arrival of a */ /* message on an empty message queue. */ #define SI_KERNEL 0x10006 +#define SI_LWP 0x10007 /* Signal sent by thr_kill */ #endif #if __BSD_VISIBLE #define SI_UNDEFINED 0 diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index bd6d9da907a..f5abae686ae 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -294,6 +294,13 @@ ksiginfo_copy(ksiginfo_t *src, ksiginfo_t *dst) (dst)->ksi_flags = (src->ksi_flags & KSI_COPYMASK); } +static __inline void +ksiginfo_set_sigev(ksiginfo_t *dst, struct sigevent *sigev) +{ + dst->ksi_signo = sigev->sigev_signo; + dst->ksi_value = sigev->sigev_value; +} + struct pgrp; struct proc; struct sigio; @@ -331,7 +338,6 @@ void pgsigio(struct sigio **sigiop, int sig, int checkctty); void pgsignal(struct pgrp *pgrp, int sig, int checkctty, ksiginfo_t *ksi); int postsig(int sig); void psignal(struct proc *p, int sig); -int psignal_event(struct proc *p, struct sigevent *sigev, ksiginfo_t *ksi); int ptracestop(struct thread *td, int sig); void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *retmask); struct sigacts *sigacts_alloc(void); @@ -340,6 +346,7 @@ void sigacts_free(struct sigacts *ps); struct sigacts *sigacts_hold(struct sigacts *ps); int sigacts_shared(struct sigacts *ps); void sigexit(struct thread *td, int sig) __dead2; +int sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **); int sig_ffs(sigset_t *set); void siginit(struct proc *p); void signotify(struct thread *td); @@ -349,6 +356,8 @@ void sigqueue_flush(struct sigqueue *queue); void sigqueue_init(struct sigqueue *queue, struct proc *p); void sigqueue_take(ksiginfo_t *ksi); void tdksignal(struct thread *td, int sig, ksiginfo_t *ksi); +int tdsendsignal(struct proc *p, struct thread *td, int sig, + ksiginfo_t *ksi); void tdsigcleanup(struct thread *td); void tdsignal(struct thread *td, int sig); void trapsignal(struct thread *td, ksiginfo_t *ksi); diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index 889908315d2..6d6578b68ab 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -234,17 +234,6 @@ struct xsocket { } \ } while (0) -#define sotryfree(so) do { \ - ACCEPT_LOCK_ASSERT(); \ - SOCK_LOCK_ASSERT(so); \ - if ((so)->so_count == 0) \ - sofree(so); \ - else { \ - SOCK_UNLOCK(so); \ - ACCEPT_UNLOCK(); \ - } \ -} while(0) - /* * In sorwakeup() and sowwakeup(), acquire the socket buffer lock to * avoid a non-atomic test-and-wakeup. However, sowakeup is diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 2af2467da3b..4c1c4839cc8 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -62,9 +62,6 @@ #define SIOCSIFBRDADDR _IOW('i', 19, struct ifreq) /* set broadcast addr */ #define OSIOCGIFCONF _IOWR('i', 20, struct ifconf) /* get ifnet list */ #define SIOCGIFCONF _IOWR('i', 36, struct ifconf) /* get ifnet list */ -#if defined (__amd64__) -#define SIOCGIFCONF32 _IOWR('i', 36, struct ifconf32) /* get ifnet list */ -#endif #define OSIOCGIFNETMASK _IOWR('i', 21, struct ifreq) /* get net addr mask */ #define SIOCGIFNETMASK _IOWR('i', 37, struct ifreq) /* get net addr mask */ #define SIOCSIFNETMASK _IOW('i', 22, struct ifreq) /* set net addr mask */ diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index e7371f247a4..64e36064521 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 209579 2010-06-28 18:06:46Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 211998 2010-08-30 14:24:44Z kib */ #define SYS_syscall 0 @@ -277,6 +277,7 @@ #define SYS_freebsd4_sendfile 336 #define SYS_kldsym 337 #define SYS_jail 338 +#define SYS_nnpfs_syscall 339 #define SYS_sigprocmask 340 #define SYS_sigsuspend 341 #define SYS_freebsd4_sigaction 342 @@ -306,6 +307,7 @@ #define SYS_extattr_delete_fd 373 #define SYS___setugid 374 #define SYS_eaccess 376 +#define SYS_afs3_syscall 377 #define SYS_nmount 378 #define SYS___mac_get_proc 384 #define SYS___mac_set_proc 385 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 8c8d1351bee..645b113cc27 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: head/sys/kern/syscalls.master 209579 2010-06-28 18:06:46Z kib +# created from FreeBSD: head/sys/kern/syscalls.master 211998 2010-08-30 14:24:44Z kib MIASM = \ syscall.o \ exit.o \ @@ -226,6 +226,7 @@ MIASM = \ freebsd4_sendfile.o \ kldsym.o \ jail.o \ + nnpfs_syscall.o \ sigprocmask.o \ sigsuspend.o \ freebsd4_sigaction.o \ @@ -255,6 +256,7 @@ MIASM = \ extattr_delete_fd.o \ __setugid.o \ eaccess.o \ + afs3_syscall.o \ nmount.o \ __mac_get_proc.o \ __mac_set_proc.o \ diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 1ee49cab246..fbfd6e84202 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -710,6 +710,9 @@ void sysctl_lock(void); void sysctl_unlock(void); int sysctl_wire_old_buffer(struct sysctl_req *req, size_t len); +struct sbuf; +struct sbuf *sbuf_new_for_sysctl(struct sbuf *, char *, int, + struct sysctl_req *); #else /* !_KERNEL */ #include diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h index 4754f54a483..e726fcebde2 100644 --- a/sys/sys/sysent.h +++ b/sys/sys/sysent.h @@ -42,7 +42,8 @@ struct ksiginfo; typedef int sy_call_t(struct thread *, void *); /* Used by the machine dependent syscall() code. */ -typedef void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *); +typedef void (*systrace_probe_func_t)(u_int32_t, int, struct sysent *, void *, + int); /* * Used by loaded syscalls to convert arguments to a DTrace array diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 5f86f3d8314..e1b35fe1ded 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 209579 2010-06-28 18:06:46Z kib + * created from FreeBSD: head/sys/kern/syscalls.master 211998 2010-08-30 14:24:44Z kib */ #ifndef _SYS_SYSPROTO_H_ @@ -933,6 +933,13 @@ struct kldsym_args { struct jail_args { char jail_l_[PADL_(struct jail *)]; struct jail * jail; char jail_r_[PADR_(struct jail *)]; }; +struct nnpfs_syscall_args { + char operation_l_[PADL_(int)]; int operation; char operation_r_[PADR_(int)]; + char a_pathP_l_[PADL_(char *)]; char * a_pathP; char a_pathP_r_[PADR_(char *)]; + char a_opcode_l_[PADL_(int)]; int a_opcode; char a_opcode_r_[PADR_(int)]; + char a_paramsP_l_[PADL_(void *)]; void * a_paramsP; char a_paramsP_r_[PADR_(void *)]; + char a_followSymlinks_l_[PADL_(int)]; int a_followSymlinks; char a_followSymlinks_r_[PADR_(int)]; +}; struct sigprocmask_args { char how_l_[PADL_(int)]; int how; char how_r_[PADR_(int)]; char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)]; @@ -1068,6 +1075,15 @@ struct eaccess_args { char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)]; char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; }; +struct afs3_syscall_args { + char syscall_l_[PADL_(long)]; long syscall; char syscall_r_[PADR_(long)]; + char parm1_l_[PADL_(long)]; long parm1; char parm1_r_[PADR_(long)]; + char parm2_l_[PADL_(long)]; long parm2; char parm2_r_[PADR_(long)]; + char parm3_l_[PADL_(long)]; long parm3; char parm3_r_[PADR_(long)]; + char parm4_l_[PADL_(long)]; long parm4; char parm4_r_[PADR_(long)]; + char parm5_l_[PADL_(long)]; long parm5; char parm5_r_[PADR_(long)]; + char parm6_l_[PADL_(long)]; long parm6; char parm6_r_[PADR_(long)]; +}; struct nmount_args { char iovp_l_[PADL_(struct iovec *)]; struct iovec * iovp; char iovp_r_[PADR_(struct iovec *)]; char iovcnt_l_[PADL_(unsigned int)]; unsigned int iovcnt; char iovcnt_r_[PADR_(unsigned int)]; @@ -1858,6 +1874,7 @@ int sched_rr_get_interval(struct thread *, struct sched_rr_get_interval_args *); int utrace(struct thread *, struct utrace_args *); int kldsym(struct thread *, struct kldsym_args *); int jail(struct thread *, struct jail_args *); +int nnpfs_syscall(struct thread *, struct nnpfs_syscall_args *); int sigprocmask(struct thread *, struct sigprocmask_args *); int sigsuspend(struct thread *, struct sigsuspend_args *); int sigpending(struct thread *, struct sigpending_args *); @@ -1885,6 +1902,7 @@ int extattr_get_fd(struct thread *, struct extattr_get_fd_args *); int extattr_delete_fd(struct thread *, struct extattr_delete_fd_args *); int __setugid(struct thread *, struct __setugid_args *); int eaccess(struct thread *, struct eaccess_args *); +int afs3_syscall(struct thread *, struct afs3_syscall_args *); int nmount(struct thread *, struct nmount_args *); int __mac_get_proc(struct thread *, struct __mac_get_proc_args *); int __mac_set_proc(struct thread *, struct __mac_set_proc_args *); @@ -2529,6 +2547,7 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_freebsd4_sendfile AUE_SENDFILE #define SYS_AUE_kldsym AUE_NULL #define SYS_AUE_jail AUE_JAIL +#define SYS_AUE_nnpfs_syscall AUE_NULL #define SYS_AUE_sigprocmask AUE_SIGPROCMASK #define SYS_AUE_sigsuspend AUE_SIGSUSPEND #define SYS_AUE_freebsd4_sigaction AUE_SIGACTION @@ -2558,6 +2577,7 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_extattr_delete_fd AUE_EXTATTR_DELETE_FD #define SYS_AUE___setugid AUE_NULL #define SYS_AUE_eaccess AUE_EACCESS +#define SYS_AUE_afs3_syscall AUE_NULL #define SYS_AUE_nmount AUE_NMOUNT #define SYS_AUE___mac_get_proc AUE_NULL #define SYS_AUE___mac_set_proc AUE_NULL diff --git a/sys/sys/systm.h b/sys/sys/systm.h index f913887a0cd..39e9e8cf09b 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -46,7 +46,7 @@ #include /* for people using printf mainly */ extern int cold; /* nonzero if we are doing a cold boot */ -extern int rebooting; /* boot() has been called. */ +extern int rebooting; /* kern_reboot() has been called. */ extern const char *panicstr; /* panic message */ extern char version[]; /* system version */ extern char copyright[]; /* system copyright */ @@ -237,20 +237,22 @@ void realitexpire(void *); int sysbeep(int hertz, int period); void hardclock(int usermode, uintfptr_t pc); +void hardclock_anycpu(int cnt, int usermode); void hardclock_cpu(int usermode); +void hardclock_sync(int cpu); void softclock(void *); void statclock(int usermode); void profclock(int usermode, uintfptr_t pc); -void timer1clock(int usermode, uintfptr_t pc); -void timer2clock(int usermode, uintfptr_t pc); -int hardclockintr(struct trapframe *frame); -int statclockintr(struct trapframe *frame); +int hardclockintr(void); void startprofclock(struct proc *); void stopprofclock(struct proc *); void cpu_startprofclock(void); void cpu_stopprofclock(void); +void cpu_idleclock(void); +void cpu_activeclock(void); +extern int cpu_disable_deep_sleep; int cr_cansee(struct ucred *u1, struct ucred *u2); int cr_canseesocket(struct ucred *cred, struct socket *so); @@ -289,6 +291,7 @@ void cpu_initclocks_ap(void); void usrinfoinit(void); /* Finalize the world */ +void kern_reboot(int) __dead2; void shutdown_nice(int); /* Timeouts */ diff --git a/sys/sys/taskqueue.h b/sys/sys/taskqueue.h index 2490deb3c0f..bf2e4ee31d0 100644 --- a/sys/sys/taskqueue.h +++ b/sys/sys/taskqueue.h @@ -56,6 +56,7 @@ int taskqueue_start_threads(struct taskqueue **tqp, int count, int pri, int taskqueue_enqueue(struct taskqueue *queue, struct task *task); void taskqueue_drain(struct taskqueue *queue, struct task *task); void taskqueue_free(struct taskqueue *queue); +void taskqueue_run(struct taskqueue *queue); void taskqueue_block(struct taskqueue *queue); void taskqueue_unblock(struct taskqueue *queue); int taskqueue_member(struct taskqueue *queue, struct thread *td); @@ -74,7 +75,6 @@ void taskqueue_thread_enqueue(void *context); (task)->ta_priority = (priority); \ (task)->ta_func = (func); \ (task)->ta_context = (context); \ - (task)->ta_running = NULL; \ } while (0) /* diff --git a/sys/sys/time.h b/sys/sys/time.h index 1039c2216de..82bbd97f06d 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -90,6 +90,25 @@ bintime_sub(struct bintime *bt, const struct bintime *bt2) bt->sec -= bt2->sec; } +static __inline void +bintime_mul(struct bintime *bt, u_int x) +{ + uint64_t p1, p2; + + p1 = (bt->frac & 0xffffffffull) * x; + p2 = (bt->frac >> 32) * x + (p1 >> 32); + bt->sec *= x; + bt->sec += (p2 >> 32); + bt->frac = (p2 << 32) | (p1 & 0xffffffffull); +} + +#define bintime_clear(a) ((a)->sec = (a)->frac = 0) +#define bintime_isset(a) ((a)->sec || (a)->frac) +#define bintime_cmp(a, b, cmp) \ + (((a)->sec == (b)->sec) ? \ + ((a)->frac cmp (b)->frac) : \ + ((a)->sec cmp (b)->sec)) + /*- * Background information: * diff --git a/sys/sys/timeet.h b/sys/sys/timeet.h index bc713d68ed3..87392a29a64 100644 --- a/sys/sys/timeet.h +++ b/sys/sys/timeet.h @@ -83,8 +83,8 @@ struct eventtimer { }; extern struct mtx et_eventtimers_mtx; -#define ET_LOCK() mtx_lock_spin(&et_eventtimers_mtx) -#define ET_UNLOCK() mtx_unlock_spin(&et_eventtimers_mtx) +#define ET_LOCK() mtx_lock(&et_eventtimers_mtx) +#define ET_UNLOCK() mtx_unlock(&et_eventtimers_mtx) /* Driver API */ int et_register(struct eventtimer *et); diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h index d5a818b4c0e..dc1dea408c6 100644 --- a/sys/sys/timetc.h +++ b/sys/sys/timetc.h @@ -65,11 +65,16 @@ struct timecounter { }; extern struct timecounter *timecounter; +extern int tc_min_ticktock_freq; /* + * Minimal tc_ticktock() call frequency, + * required to handle counter wraps. + */ u_int64_t tc_getfrequency(void); void tc_init(struct timecounter *tc); void tc_setclock(struct timespec *ts); -void tc_ticktock(void); +void tc_ticktock(int cnt); +void cpu_tick_calibration(void); #ifdef SYSCTL_DECL SYSCTL_DECL(_kern_timecounter); diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h index 70e3ef7e283..378308de820 100644 --- a/sys/sys/unistd.h +++ b/sys/sys/unistd.h @@ -68,7 +68,7 @@ #define _POSIX_PRIORITY_SCHEDULING 200112L #define _POSIX_RAW_SOCKETS 200112L #define _POSIX_REALTIME_SIGNALS 200112L -#define _POSIX_SEMAPHORES -1 +#define _POSIX_SEMAPHORES 200112L #define _POSIX_SHARED_MEMORY_OBJECTS 200112L #define _POSIX_SPORADIC_SERVER -1 #define _POSIX_SYNCHRONIZED_IO -1 diff --git a/sys/sys/user.h b/sys/sys/user.h index 50fc96d95e7..b32ca04989b 100644 --- a/sys/sys/user.h +++ b/sys/sys/user.h @@ -85,7 +85,7 @@ */ #define KI_NSPARE_INT 9 #define KI_NSPARE_LONG 12 -#define KI_NSPARE_PTR 7 +#define KI_NSPARE_PTR 6 #ifndef _KERNEL #ifndef KINFO_PROC_SIZE @@ -188,6 +188,7 @@ struct kinfo_proc { struct pcb *ki_pcb; /* kernel virtual addr of pcb */ void *ki_kstack; /* kernel virtual addr of stack */ void *ki_udata; /* User convenience pointer */ + struct thread *ki_tdaddr; /* address of thread */ /* * When adding new variables, take space for pointers from the * front of ki_spareptrs, and longs from the end of ki_sparelongs. diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index c38d645462e..e82f8ea54d6 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -419,10 +419,8 @@ extern struct vattr va_null; /* predefined null vattr structure */ #define VI_UNLOCK(vp) mtx_unlock(&(vp)->v_interlock) #define VI_MTX(vp) (&(vp)->v_interlock) -#define VN_LOCK_AREC(vp) \ - ((vp)->v_vnlock->lock_object.lo_flags |= LO_RECURSABLE) -#define VN_LOCK_ASHARE(vp) \ - ((vp)->v_vnlock->lock_object.lo_flags &= ~LK_NOSHARE) +#define VN_LOCK_AREC(vp) lockallowrecurse((vp)->v_vnlock) +#define VN_LOCK_ASHARE(vp) lockallowshare((vp)->v_vnlock) #endif /* _KERNEL */ diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk index 86c6bdc522e..3fdea0a24c1 100644 --- a/sys/tools/vnode_if.awk +++ b/sys/tools/vnode_if.awk @@ -355,8 +355,8 @@ while ((getline < srcfile) > 0) { printc("};"); printc("\n"); - printc("SDT_PROBE_DEFINE2(vfs, vop, " name ", entry, \"struct vnode *\", \"struct " name "_args *\");\n"); - printc("SDT_PROBE_DEFINE3(vfs, vop, " name ", return, \"struct vnode *\", \"struct " name "_args *\", \"int\");\n"); + printc("SDT_PROBE_DEFINE2(vfs, vop, " name ", entry, entry, \"struct vnode *\", \"struct " name "_args *\");\n"); + printc("SDT_PROBE_DEFINE3(vfs, vop, " name ", return, return, \"struct vnode *\", \"struct " name "_args *\", \"int\");\n"); # Print out function. printc("\nint\n" uname "_AP(struct " name "_args *a)"); diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 039e436463c..ca4ea0b11d5 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -580,7 +580,7 @@ softdep_get_depcounts(struct mount *mp, * this file is being ported. */ -#define M_SOFTDEP_FLAGS (M_WAITOK | M_USE_RESERVE) +#define M_SOFTDEP_FLAGS (M_WAITOK) #define D_PAGEDEP 0 #define D_INODEDEP 1 @@ -904,8 +904,8 @@ MTX_SYSINIT(softdep_lock, &lk, "Softdep Lock", MTX_DEF); #define ACQUIRE_LOCK(lk) mtx_lock(lk) #define FREE_LOCK(lk) mtx_unlock(lk) -#define BUF_AREC(bp) ((bp)->b_lock.lock_object.lo_flags |= LO_RECURSABLE) -#define BUF_NOREC(bp) ((bp)->b_lock.lock_object.lo_flags &= ~LO_RECURSABLE) +#define BUF_AREC(bp) lockallowrecurse(&(bp)->b_lock) +#define BUF_NOREC(bp) lockdisablerecurse(&(bp)->b_lock) /* * Worklist queue management. @@ -2378,7 +2378,8 @@ remove_from_journal(wk) /* * We emulate a TAILQ to save space in most structures which do not * require TAILQ semantics. Here we must update the tail position - * when removing the tail which is not the final entry. + * when removing the tail which is not the final entry. This works + * only if the worklist linkage are at the beginning of the structure. */ if (ump->softdep_journal_tail == wk) ump->softdep_journal_tail = @@ -2605,7 +2606,7 @@ jremref_write(jremref, jseg, data) inoref_write(&jremref->jr_ref, jseg, rec); } -static void +static void jmvref_write(jmvref, jseg, data) struct jmvref *jmvref; struct jseg *jseg; @@ -2898,17 +2899,18 @@ complete_jseg(jseg) struct worklist *wk; struct jmvref *jmvref; int waiting; - int i; +#ifdef INVARIANTS + int i = 0; +#endif - i = 0; while ((wk = LIST_FIRST(&jseg->js_entries)) != NULL) { WORKLIST_REMOVE(wk); waiting = wk->wk_state & IOWAITING; wk->wk_state &= ~(IOSTARTED | IOWAITING); wk->wk_state |= COMPLETE; - KASSERT(i < jseg->js_cnt, + KASSERT(i++ < jseg->js_cnt, ("handle_written_jseg: overflow %d >= %d", - i, jseg->js_cnt)); + i - 1, jseg->js_cnt)); switch (wk->wk_type) { case D_JADDREF: handle_written_jaddref(WK_JADDREF(wk)); @@ -7492,7 +7494,7 @@ handle_written_sbdep(sbdep, bp) if (inodedep_lookup(mp, fs->fs_sujfree, 0, &inodedep) == 0) panic("handle_written_sbdep: lost inodedep"); /* - * Now that we have a record of this indode in stable store allow it + * Now that we have a record of this inode in stable store allow it * to be written to free up pending work. Inodes may see a lot of * write activity after they are unlinked which we must not hold up. */ @@ -7509,8 +7511,7 @@ handle_written_sbdep(sbdep, bp) } /* - * Mark an inodedep has unlinked and insert it into the in-memory unlinked - * list. + * Mark an inodedep as unlinked and insert it into the in-memory unlinked list. */ static void unlinked_inodedep(mp, inodedep) @@ -7576,7 +7577,7 @@ clear_unlinked_inodedep(inodedep) * link before us, whether it be the superblock or an inode. * Unfortunately the list may change while we're waiting * on the buf lock for either resource so we must loop until - * we lock. the right one. If both the superblock and an + * we lock the right one. If both the superblock and an * inode point to this inode we must clear the inode first * followed by the superblock. */ @@ -9094,7 +9095,7 @@ handle_jwork(wkhd) /* * Handle the bufwait list on an inode when it is safe to release items * held there. This normally happens after an inode block is written but - * may be delayed and handle later if there are pending journal items that + * may be delayed and handled later if there are pending journal items that * are not yet safe to be released. */ static struct freefile * @@ -9464,7 +9465,7 @@ handle_written_indirdep(indirdep, bp, bpp) indirdep->ir_state |= ATTACHED; /* * Move allocindirs with written pointers to the completehd if - * the the indirdep's pointer is not yet written. Otherwise + * the indirdep's pointer is not yet written. Otherwise * free them here. */ while ((aip = LIST_FIRST(&indirdep->ir_writehd)) != 0) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index c099732398f..94951e45b97 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -318,7 +318,7 @@ ffs_mount(struct mount *mp) fs->fs_fsmnt); if (fs->fs_flags & FS_SUJ) printf( -"WARNING: Forced mount will invalidated journal contents\n"); +"WARNING: Forced mount will invalidate journal contents\n"); return (EPERM); } } @@ -362,7 +362,7 @@ ffs_mount(struct mount *mp) * Soft updates is incompatible with "async", * so if we are doing softupdates stop the user * from setting the async flag in an update. - * Softdep_mount() clears it in an initial mount + * Softdep_mount() clears it in an initial mount * or ro->rw remount. */ if (mp->mnt_flag & MNT_SOFTDEP) { @@ -387,7 +387,7 @@ ffs_mount(struct mount *mp) mp->mnt_flag |= MNT_NFS4ACLS; MNT_IUNLOCK(mp); } - + /* * If this is a snapshot request, take the snapshot. */ @@ -463,6 +463,7 @@ static int ffs_cmount(struct mntarg *ma, void *data, int flags) { struct ufs_args args; + struct export_args exp; int error; if (data == NULL) @@ -470,9 +471,10 @@ ffs_cmount(struct mntarg *ma, void *data, int flags) error = copyin(data, &args, sizeof args); if (error) return (error); + vfs_oexport_conv(&args.export, &exp); ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); - ma = mount_arg(ma, "export", &args.export, sizeof args.export); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); error = kernel_mount(ma, flags); return (error); @@ -720,8 +722,7 @@ ffs_mountfs(devvp, mp, td) if (ronly || (mp->mnt_flag & MNT_FORCE) || ((fs->fs_flags & (FS_SUJ | FS_NEEDSFSCK)) == 0 && (fs->fs_flags & FS_DOSOFTDEP))) { - printf( -"WARNING: %s was not properly dismounted\n", + printf("WARNING: %s was not properly dismounted\n", fs->fs_fsmnt); } else { printf( @@ -729,7 +730,7 @@ ffs_mountfs(devvp, mp, td) fs->fs_fsmnt); if (fs->fs_flags & FS_SUJ) printf( -"WARNING: Forced mount will invalidated journal contents\n"); +"WARNING: Forced mount will invalidate journal contents\n"); error = EPERM; goto out; } @@ -840,7 +841,7 @@ ffs_mountfs(devvp, mp, td) mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; nmp = NULL; - if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 || + if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 || (nmp = vfs_getvfs(&mp->mnt_stat.f_fsid))) { if (nmp) vfs_rel(nmp); @@ -873,8 +874,7 @@ ffs_mountfs(devvp, mp, td) MNT_IUNLOCK(mp); #else - printf( -"WARNING: %s: ACLs flag on fs but no ACLs support\n", + printf("WARNING: %s: ACLs flag on fs but no ACLs support\n", mp->mnt_stat.f_mntonname); #endif } @@ -1501,6 +1501,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) /* * FFS supports recursive locking. */ + lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); VN_LOCK_AREC(vp); vp->v_data = ip; vp->v_bufobj.bo_bsize = fs->fs_bsize; @@ -1518,7 +1519,6 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags) } #endif - lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); if (ffs_flags & FFSV_FORCEINSMQ) vp->v_vflag |= VV_FORCEINSMQ; error = insmntque(vp, mp); @@ -1682,7 +1682,7 @@ ffs_sbupdate(mp, waitfor, suspended) int i, size, error, allerror = 0; if (fs->fs_ronly == 1 && - (mp->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) != + (mp->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) != (MNT_RDONLY | MNT_UPDATE)) panic("ffs_sbupdate: write read-only filesystem"); /* @@ -1836,7 +1836,7 @@ ffs_backgroundwritedone(struct buf *bp) * * Note that we set B_CACHE here, indicating that buffer is * fully valid and thus cacheable. This is true even of NFS - * now so we set it generally. This could be set either here + * now so we set it generally. This could be set either here * or in biodone() since the I/O is synchronous. We put it * here. */ @@ -1885,7 +1885,7 @@ ffs_bufwrite(struct buf *bp) * This optimization eats a lot of memory. If we have a page * or buffer shortfall we can't do it. */ - if (dobkgrdwrite && (bp->b_xflags & BX_BKGRDWRITE) && + if (dobkgrdwrite && (bp->b_xflags & BX_BKGRDWRITE) && (bp->b_flags & B_ASYNC) && !vm_page_count_severe() && !buf_dirty_count_severe()) { @@ -1927,7 +1927,7 @@ ffs_bufwrite(struct buf *bp) bundirty(bp); #else bundirty(bp); -#endif +#endif /* * Initiate write on the copy, release the original to diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h index e863b961c62..42c4cfe60c4 100644 --- a/sys/ufs/ffs/fs.h +++ b/sys/ufs/ffs/fs.h @@ -661,7 +661,7 @@ lbn_level(ufs_lbn_t lbn) /* * Size of the segment record header. There is at most one for each disk - * block n the journal. The segment header is followed by an array of + * block in the journal. The segment header is followed by an array of * records. fsck depends on the first element in each record being 'op' * and the second being 'ino'. Segments may span multiple disk blocks but * the header is present on each. diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h index 23afbf789a1..f584e91f37a 100644 --- a/sys/ufs/ffs/softdep.h +++ b/sys/ufs/ffs/softdep.h @@ -107,6 +107,15 @@ * * The ONWORKLIST flag shows whether the structure is currently linked * onto a worklist. + * + * The UNLINK* flags track the progress of updating the on-disk linked + * list of active but unlinked inodes. When an inode is first unlinked + * it is marked as UNLINKED. When its on-disk di_freelink has been + * written its UNLINKNEXT flags is set. When its predecessor in the + * list has its di_freelink pointing at us its UNLINKPREV is set. + * When the on-disk list can reach it from the superblock, its + * UNLINKONLIST flag is set. Once all of these flags are set, it + * is safe to let its last name be removed. */ #define ATTACHED 0x000001 #define UNDONE 0x000002 @@ -353,20 +362,22 @@ struct bmsafemap { * or fragment is allocated from a cylinder group. Its state is set to * DEPCOMPLETE when its cylinder group map is written. It is converted to * an allocdirect or allocindir allocation once the allocator calls the - * appropriate setup function. + * appropriate setup function. It will initially be linked onto a bmsafemap + * list. Once converted it can be linked onto the lists described for + * allocdirect or allocindir as described below. */ struct newblk { - struct worklist nb_list; + struct worklist nb_list; /* See comment above. */ # define nb_state nb_list.wk_state - LIST_ENTRY(newblk) nb_hash; /* hashed lookup */ - LIST_ENTRY(newblk) nb_deps; /* bmsafemap's list of newblks */ + LIST_ENTRY(newblk) nb_hash; /* Hashed lookup. */ + LIST_ENTRY(newblk) nb_deps; /* Bmsafemap's list of newblks. */ struct jnewblk *nb_jnewblk; /* New block journal entry. */ - struct bmsafemap *nb_bmsafemap;/* cylgrp dep (if pending) */ - struct freefrag *nb_freefrag; /* fragment to be freed (if any) */ + struct bmsafemap *nb_bmsafemap;/* Cylgrp dep (if pending). */ + struct freefrag *nb_freefrag; /* Fragment to be freed (if any). */ struct indirdephd nb_indirdeps; /* Children indirect blocks. */ - struct workhead nb_newdirblk; /* dir block to notify when written */ + struct workhead nb_newdirblk; /* Dir block to notify when written. */ struct workhead nb_jwork; /* Journal work pending. */ - ufs2_daddr_t nb_newblkno; /* new value of block pointer */ + ufs2_daddr_t nb_newblkno; /* New value of block pointer. */ }; /* @@ -517,16 +528,16 @@ struct freeblks { /* * A "freework" structure handles the release of a tree of blocks or a single * block. Each indirect block in a tree is allocated its own freework - * structure so that the indrect block may be freed only when all of its + * structure so that the indirect block may be freed only when all of its * children are freed. In this way we enforce the rule that an allocated * block must have a valid path to a root that is journaled. Each child * block acquires a reference and when the ref hits zero the parent ref * is decremented. If there is no parent the freeblks ref is decremented. */ struct freework { - struct worklist fw_list; + struct worklist fw_list; /* Delayed worklist. */ # define fw_state fw_list.wk_state - LIST_ENTRY(freework) fw_next; /* Queue for freeblksk. */ + LIST_ENTRY(freework) fw_next; /* Queue for freeblk list. */ struct freeblks *fw_freeblks; /* Root of operation. */ struct freework *fw_parent; /* Parent indirect. */ ufs2_daddr_t fw_blkno; /* Our block #. */ @@ -545,7 +556,7 @@ struct freework { * to be freed as well. */ struct freedep { - struct worklist fd_list; + struct worklist fd_list; /* Delayed worklist. */ struct freework *fd_freework; /* Parent freework. */ }; @@ -705,10 +716,10 @@ struct newdirblk { * so they may easily be queued in-order on the inodedep. */ struct inoref { - struct worklist if_list; + struct worklist if_list; /* Journal pending or jseg entries. */ # define if_state if_list.wk_state TAILQ_ENTRY(inoref) if_deps; /* Links for inodedep. */ - struct jsegdep *if_jsegdep; + struct jsegdep *if_jsegdep; /* Will track our journal record. */ off_t if_diroff; /* Directory offset. */ ino_t if_ino; /* Inode number. */ ino_t if_parent; /* Parent inode number. */ @@ -731,8 +742,8 @@ struct inoref { * ultimately released when the file is freed or the link is dropped again. */ struct jaddref { - struct inoref ja_ref; -# define ja_list ja_ref.if_list /* Journal pending or jseg entries. */ + struct inoref ja_ref; /* see inoref above. */ +# define ja_list ja_ref.if_list /* Jrnl pending, id_inowait, dm_jwork.*/ # define ja_state ja_ref.if_list.wk_state LIST_ENTRY(jaddref) ja_bmdeps; /* Links for bmsafemap. */ union { @@ -754,21 +765,28 @@ struct jaddref { * may proceed as normal. */ struct jremref { - struct inoref jr_ref; -# define jr_list jr_ref.if_list /* Journal pending or jseg entries. */ + struct inoref jr_ref; /* see inoref above. */ +# define jr_list jr_ref.if_list /* Linked to softdep_journal_pending. */ # define jr_state jr_ref.if_list.wk_state - LIST_ENTRY(jremref) jr_deps; /* Links for pagdep. */ + LIST_ENTRY(jremref) jr_deps; /* Links for dirrem. */ struct dirrem *jr_dirrem; /* Back pointer to dirrem. */ }; +/* + * A "jmvref" structure tracks a name relocations within the same + * directory block that occur as a result of directory compaction. + * It prevents the updated directory entry from being written to disk + * until the journal entry is written. Once the journal has been + * written the compacted directory may be written to disk. + */ struct jmvref { - struct worklist jm_list; - LIST_ENTRY(jmvref) jm_deps; - struct pagedep *jm_pagedep; - ino_t jm_parent; - ino_t jm_ino; - off_t jm_oldoff; - off_t jm_newoff; + struct worklist jm_list; /* Linked to softdep_journal_pending. */ + LIST_ENTRY(jmvref) jm_deps; /* Jmvref on pagedep. */ + struct pagedep *jm_pagedep; /* Back pointer to pagedep. */ + ino_t jm_parent; /* Containing directory inode number. */ + ino_t jm_ino; /* Inode number of our entry. */ + off_t jm_oldoff; /* Our old offset in directory. */ + off_t jm_newoff; /* Our new offset in directory. */ }; /* @@ -780,36 +798,37 @@ struct jmvref { * write the jnewblk structure is maintained to prevent the bitmaps from * reaching the disk. Ultimately the jnewblk structure will be passed * to the free routine as the in memory cg is modified back to the free - * state at which time it can be released. + * state at which time it can be released. It may be held on any of the + * fx_jwork, fw_jwork, fb_jwork, ff_jwork, nb_jwork, or ir_jwork lists. */ struct jnewblk { - struct worklist jn_list; + struct worklist jn_list; /* See lists above. */ # define jn_state jn_list.wk_state - struct jsegdep *jn_jsegdep; - LIST_ENTRY(jnewblk) jn_deps; /* All jnewblks on bmsafemap */ - struct newblk *jn_newblk; - ino_t jn_ino; - ufs_lbn_t jn_lbn; - ufs2_daddr_t jn_blkno; - int jn_oldfrags; - int jn_frags; + struct jsegdep *jn_jsegdep; /* Will track our journal record. */ + LIST_ENTRY(jnewblk) jn_deps; /* Jnewblks on sm_jnewblkhd. */ + struct newblk *jn_newblk; /* Back pointer to newblk. */ + ino_t jn_ino; /* Ino to which allocated. */ + ufs_lbn_t jn_lbn; /* Lbn to which allocated. */ + ufs2_daddr_t jn_blkno; /* Blkno allocated */ + int jn_oldfrags; /* Previous fragments when extended. */ + int jn_frags; /* Number of fragments. */ }; /* * A "jfreeblk" structure tracks the journal write for freeing a block * or tree of blocks. The block pointer must not be cleared in the inode - * or indirect prior to the jfreeblk being written. + * or indirect prior to the jfreeblk being written to the journal. */ struct jfreeblk { - struct worklist jf_list; + struct worklist jf_list; /* Linked to softdep_journal_pending. */ # define jf_state jf_list.wk_state - struct jsegdep *jf_jsegdep; - struct freeblks *jf_freeblks; - LIST_ENTRY(jfreeblk) jf_deps; - ino_t jf_ino; - ufs_lbn_t jf_lbn; - ufs2_daddr_t jf_blkno; - int jf_frags; + struct jsegdep *jf_jsegdep; /* Will track our journal record. */ + struct freeblks *jf_freeblks; /* Back pointer to freeblks. */ + LIST_ENTRY(jfreeblk) jf_deps; /* Jfreeblk on fb_jfreeblkhd. */ + ino_t jf_ino; /* Ino from which blocks freed. */ + ufs_lbn_t jf_lbn; /* Lbn from which blocks freed. */ + ufs2_daddr_t jf_blkno; /* Blkno being freed. */ + int jf_frags; /* Number of frags being freed. */ }; /* @@ -818,14 +837,14 @@ struct jfreeblk { * freeblks operation. */ struct jfreefrag { - struct worklist fr_list; + struct worklist fr_list; /* Linked to softdep_journal_pending. */ # define fr_state fr_list.wk_state - struct jsegdep *fr_jsegdep; - struct freefrag *fr_freefrag; - ino_t fr_ino; - ufs_lbn_t fr_lbn; - ufs2_daddr_t fr_blkno; - int fr_frags; + struct jsegdep *fr_jsegdep; /* Will track our journal record. */ + struct freefrag *fr_freefrag; /* Back pointer to freefrag. */ + ino_t fr_ino; /* Ino from which frag freed. */ + ufs_lbn_t fr_lbn; /* Lbn from which frag freed. */ + ufs2_daddr_t fr_blkno; /* Blkno being freed. */ + int fr_frags; /* Size of frag being freed. */ }; /* @@ -835,42 +854,45 @@ struct jfreefrag { * is complete and the truncated inode is fsync'd. */ struct jtrunc { - struct worklist jt_list; - struct jsegdep *jt_jsegdep; - ino_t jt_ino; - off_t jt_size; - int jt_extsize; + struct worklist jt_list; /* Linked to softdep_journal_pending. */ + struct jsegdep *jt_jsegdep; /* Will track our journal record. */ + ino_t jt_ino; /* Ino being truncated. */ + off_t jt_size; /* Final file size. */ + int jt_extsize; /* Final extent size. */ }; /* * A "jsegdep" structure tracks a single reference to a written journal * segment so the journal space can be reclaimed when all dependencies - * have been written. + * have been written. It can hang off of id_inowait, dm_jwork, da_jwork, + * nb_jwork, ff_jwork, or fb_jwork lists. */ struct jsegdep { - struct worklist jd_list; + struct worklist jd_list; /* See above for lists. */ # define jd_state jd_list.wk_state - struct jseg *jd_seg; + struct jseg *jd_seg; /* Our journal record. */ }; /* * A "jseg" structure contains all of the journal records written in a - * single disk write. jaddref and jremref structures are linked into + * single disk write. The jaddref and jremref structures are linked into * js_entries so thay may be completed when the write completes. The - * js_deps array contains as many entries as there are ref counts to - * reduce the number of allocations required per journal write to one. + * js_entries also include the write dependency structures: jmvref, + * jnewblk, jfreeblk, jfreefrag, and jtrunc. The js_refs field counts + * the number of entries on the js_entries list. Thus there is a single + * jseg entry to describe each journal write. */ struct jseg { struct worklist js_list; /* b_deps link for journal */ # define js_state js_list.wk_state struct workhead js_entries; /* Entries awaiting write */ - TAILQ_ENTRY(jseg) js_next; + TAILQ_ENTRY(jseg) js_next; /* List of all unfinished segments. */ struct jblocks *js_jblocks; /* Back pointer to block/seg list */ struct buf *js_buf; /* Buffer while unwritten */ - uint64_t js_seq; - int js_size; /* Allocated size in bytes */ - int js_cnt; /* Total items allocated */ - int js_refs; /* Count of items pending completion */ + uint64_t js_seq; /* Journal record sequence number. */ + int js_size; /* Size of journal record in bytes. */ + int js_cnt; /* Total items allocated. */ + int js_refs; /* Count of js_entries items. */ }; /* @@ -878,10 +900,11 @@ struct jseg { * superblock writes. This makes sure the superblock is always pointing at * the first possible unlinked inode for the suj recovery process. If a * block write completes and we discover a new head is available the buf - * is dirtied and the dep is kept. + * is dirtied and the dep is kept. See the description of the UNLINK* + * flags above for more details. */ struct sbdep { struct worklist sb_list; /* b_dep linkage */ struct fs *sb_fs; /* Filesystem pointer within buf. */ - struct ufsmount *sb_ump; + struct ufsmount *sb_ump; /* Our mount structure */ }; diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h index d5669179dac..03edd7314b8 100644 --- a/sys/ufs/ufs/ufsmount.h +++ b/sys/ufs/ufs/ufsmount.h @@ -40,7 +40,7 @@ */ struct ufs_args { char *fspec; /* block special device to mount */ - struct export_args export; /* network export information */ + struct oexport_args export; /* network export information */ }; #ifdef _KERNEL diff --git a/sys/vm/memguard.c b/sys/vm/memguard.c index c3d93e06200..3cf935c27eb 100644 --- a/sys/vm/memguard.c +++ b/sys/vm/memguard.c @@ -247,9 +247,13 @@ SYSINIT(memguard, SI_SUB_KLD, SI_ORDER_ANY, memguard_sysinit, NULL); static u_long * v2sizep(vm_offset_t va) { + vm_paddr_t pa; struct vm_page *p; - p = PHYS_TO_VM_PAGE(pmap_kextract(va)); + pa = pmap_kextract(va); + if (pa == 0) + panic("MemGuard detected double-free of %p", (void *)va); + p = PHYS_TO_VM_PAGE(pa); KASSERT(p->wire_count != 0 && p->queue == PQ_NONE, ("MEMGUARD: Expected wired page %p in vtomgfifo!", p)); return ((u_long *)&p->pageq.tqe_next); @@ -399,6 +403,31 @@ memguard_free(void *ptr) vm_map_unlock(memguard_map); } +/* + * Re-allocate an allocation that was originally guarded. + */ +void * +memguard_realloc(void *addr, unsigned long size, struct malloc_type *mtp, + int flags) +{ + void *newaddr; + u_long old_size; + + /* + * Allocate the new block. Force the allocation to be guarded + * as the original may have been guarded through random + * chance, and that should be preserved. + */ + if ((newaddr = memguard_alloc(size, flags)) == NULL) + return (NULL); + + /* Copy over original contents. */ + old_size = *v2sizep(trunc_page((uintptr_t)addr)); + bcopy(addr, newaddr, min(size, old_size)); + memguard_free(addr); + return (newaddr); +} + int memguard_cmp(struct malloc_type *mtp, unsigned long size) { diff --git a/sys/vm/memguard.h b/sys/vm/memguard.h index ba7c2f1b427..25238b420d2 100644 --- a/sys/vm/memguard.h +++ b/sys/vm/memguard.h @@ -38,6 +38,7 @@ struct vm_map; unsigned long memguard_fudge(unsigned long, unsigned long); void memguard_init(struct vm_map *); void *memguard_alloc(unsigned long, int); +void *memguard_realloc(void *, unsigned long, struct malloc_type *, int); void memguard_free(void *); int memguard_cmp(struct malloc_type *, unsigned long); int is_memguard_addr(void *); @@ -45,6 +46,7 @@ int is_memguard_addr(void *); #define memguard_fudge(size, xxx) (size) #define memguard_init(map) do { } while (0) #define memguard_alloc(size, flags) NULL +#define memguard_realloc(a, s, mtp, f) NULL #define memguard_free(addr) do { } while (0) #define memguard_cmp(mtp, size) 0 #define is_memguard_addr(addr) 0 diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c index b359bd47829..bea235af8b6 100644 --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -1460,8 +1460,8 @@ swap_pager_putpages(vm_object_t object, vm_page_t *m, int count, * Completion routine for asynchronous reads and writes from/to swap. * Also called manually by synchronous code to finish up a bp. * - * For READ operations, the pages are PG_BUSY'd. For WRITE operations, - * the pages are vm_page_t->busy'd. For READ operations, we PG_BUSY + * For READ operations, the pages are VPO_BUSY'd. For WRITE operations, + * the pages are vm_page_t->busy'd. For READ operations, we VPO_BUSY * unbusy all pages except the 'main' request page. For WRITE * operations, we vm_page_t->busy'd unbusy all pages ( we can do this * because we marked them all VM_PAGER_PEND on return from putpages ). diff --git a/sys/vm/uma.h b/sys/vm/uma.h index 2076d3bd0b6..241cabca86a 100644 --- a/sys/vm/uma.h +++ b/sys/vm/uma.h @@ -452,11 +452,35 @@ int uma_zone_set_obj(uma_zone_t zone, struct vm_object *obj, int size); * * Arguments: * zone The zone to limit + * nitems The requested upper limit on the number of items allowed * * Returns: - * Nothing + * int The effective value of nitems after rounding up based on page size */ -void uma_zone_set_max(uma_zone_t zone, int nitems); +int uma_zone_set_max(uma_zone_t zone, int nitems); + +/* + * Obtains the effective limit on the number of items in a zone + * + * Arguments: + * zone The zone to obtain the effective limit from + * + * Return: + * 0 No limit + * int The effective limit of the zone + */ +int uma_zone_get_max(uma_zone_t zone); + +/* + * Obtains the approximate current number of items allocated from a zone + * + * Arguments: + * zone The zone to obtain the current allocation count from + * + * Return: + * int The approximate current number of items allocated from the zone + */ +int uma_zone_get_cur(uma_zone_t zone); /* * The following two routines (uma_zone_set_init/fini) diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index 2dcd14fdd1a..43e37036dd2 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -2517,6 +2517,10 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata) CTR2(KTR_UMA, "uma_zfree_arg thread %x zone %s", curthread, zone->uz_name); + /* uma_zfree(..., NULL) does nothing, to match free(9). */ + if (item == NULL) + return; + if (zone->uz_dtor) zone->uz_dtor(item, zone->uz_size, udata); @@ -2782,7 +2786,7 @@ zone_free_item(uma_zone_t zone, void *item, void *udata, } /* See uma.h */ -void +int uma_zone_set_max(uma_zone_t zone, int nitems) { uma_keg_t keg; @@ -2792,8 +2796,48 @@ uma_zone_set_max(uma_zone_t zone, int nitems) keg->uk_maxpages = (nitems / keg->uk_ipers) * keg->uk_ppera; if (keg->uk_maxpages * keg->uk_ipers < nitems) keg->uk_maxpages += keg->uk_ppera; - + nitems = keg->uk_maxpages * keg->uk_ipers; ZONE_UNLOCK(zone); + + return (nitems); +} + +/* See uma.h */ +int +uma_zone_get_max(uma_zone_t zone) +{ + int nitems; + uma_keg_t keg; + + ZONE_LOCK(zone); + keg = zone_first_keg(zone); + nitems = keg->uk_maxpages * keg->uk_ipers; + ZONE_UNLOCK(zone); + + return (nitems); +} + +/* See uma.h */ +int +uma_zone_get_cur(uma_zone_t zone) +{ + int64_t nitems; + u_int i; + + ZONE_LOCK(zone); + nitems = zone->uz_allocs - zone->uz_frees; + CPU_FOREACH(i) { + /* + * See the comment in sysctl_vm_zone_stats() regarding the + * safety of accessing the per-cpu caches. With the zone lock + * held, it is safe, but can potentially result in stale data. + */ + nitems += zone->uz_cpu[i].uc_allocs - + zone->uz_cpu[i].uc_frees; + } + ZONE_UNLOCK(zone); + + return (nitems < 0 ? 0 : nitems); } /* See uma.h */ @@ -3157,36 +3201,16 @@ sysctl_vm_zone_stats(SYSCTL_HANDLER_ARGS) uma_keg_t kz; uma_zone_t z; uma_keg_t k; - char *buffer; - int buflen, count, error, i; + int count, error, i; + + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); - mtx_lock(&uma_mtx); -restart: - mtx_assert(&uma_mtx, MA_OWNED); count = 0; + mtx_lock(&uma_mtx); LIST_FOREACH(kz, &uma_kegs, uk_link) { LIST_FOREACH(z, &kz->uk_zones, uz_link) count++; } - mtx_unlock(&uma_mtx); - - buflen = sizeof(ush) + count * (sizeof(uth) + sizeof(ups) * - (mp_maxid + 1)) + 1; - buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO); - - mtx_lock(&uma_mtx); - i = 0; - LIST_FOREACH(kz, &uma_kegs, uk_link) { - LIST_FOREACH(z, &kz->uk_zones, uz_link) - i++; - } - if (i > count) { - free(buffer, M_TEMP); - goto restart; - } - count = i; - - sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN); /* * Insert stream header. @@ -3195,11 +3219,7 @@ restart: ush.ush_version = UMA_STREAM_VERSION; ush.ush_maxcpus = (mp_maxid + 1); ush.ush_count = count; - if (sbuf_bcat(&sbuf, &ush, sizeof(ush)) < 0) { - mtx_unlock(&uma_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &ush, sizeof(ush)); LIST_FOREACH(kz, &uma_kegs, uk_link) { LIST_FOREACH(z, &kz->uk_zones, uz_link) { @@ -3232,12 +3252,7 @@ restart: uth.uth_frees = z->uz_frees; uth.uth_fails = z->uz_fails; uth.uth_sleeps = z->uz_sleeps; - if (sbuf_bcat(&sbuf, &uth, sizeof(uth)) < 0) { - ZONE_UNLOCK(z); - mtx_unlock(&uma_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &uth, sizeof(uth)); /* * While it is not normally safe to access the cache * bucket pointers while not on the CPU that owns the @@ -3262,21 +3277,14 @@ restart: ups.ups_allocs = cache->uc_allocs; ups.ups_frees = cache->uc_frees; skip: - if (sbuf_bcat(&sbuf, &ups, sizeof(ups)) < 0) { - ZONE_UNLOCK(z); - mtx_unlock(&uma_mtx); - error = ENOMEM; - goto out; - } + (void)sbuf_bcat(&sbuf, &ups, sizeof(ups)); } ZONE_UNLOCK(z); } } mtx_unlock(&uma_mtx); - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); -out: - free(buffer, M_TEMP); + error = sbuf_finish(&sbuf); + sbuf_delete(&sbuf); return (error); } diff --git a/sys/vm/vm_kern.c b/sys/vm/vm_kern.c index 0b840a4764b..ae85db335eb 100644 --- a/sys/vm/vm_kern.c +++ b/sys/vm/vm_kern.c @@ -354,11 +354,7 @@ kmem_back(vm_map_t map, vm_offset_t addr, vm_size_t size, int flags) vm_page_t m; int pflags; - /* - * XXX the map must be locked for write on entry, but there's - * no easy way to assert that. - */ - + KASSERT(vm_map_locked(map), ("kmem_back: map %p is not locked", map)); offset = addr - VM_MIN_KERNEL_ADDRESS; vm_object_reference(kmem_object); vm_map_insert(map, kmem_object, offset, addr, addr + size, diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index c4089c611e9..40c317d93a6 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -128,6 +128,7 @@ static int vm_map_zinit(void *mem, int ize, int flags); static void vm_map_zfini(void *mem, int size); static void _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t min, vm_offset_t max); +static void vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map); static void vm_map_entry_dispose(vm_map_t map, vm_map_entry_t entry); #ifdef INVARIANTS static void vm_map_zdtor(void *mem, int size, void *arg); @@ -338,15 +339,11 @@ vmspace_dofree(struct vmspace *vm) void vmspace_free(struct vmspace *vm) { - int refcnt; if (vm->vm_refcnt == 0) panic("vmspace_free: attempt to free already freed vmspace"); - do - refcnt = vm->vm_refcnt; - while (!atomic_cmpset_int(&vm->vm_refcnt, refcnt, refcnt - 1)); - if (refcnt == 1) + if (atomic_fetchadd_int(&vm->vm_refcnt, -1) == 1) vmspace_dofree(vm); } @@ -454,30 +451,29 @@ _vm_map_lock(vm_map_t map, const char *file, int line) map->timestamp++; } +static void +vm_map_process_deferred(void) +{ + struct thread *td; + vm_map_entry_t entry; + + td = curthread; + + while ((entry = td->td_map_def_user) != NULL) { + td->td_map_def_user = entry->next; + vm_map_entry_deallocate(entry, FALSE); + } +} + void _vm_map_unlock(vm_map_t map, const char *file, int line) { - vm_map_entry_t free_entry, entry; - vm_object_t object; - - free_entry = map->deferred_freelist; - map->deferred_freelist = NULL; if (map->system_map) _mtx_unlock_flags(&map->system_mtx, 0, file, line); - else + else { _sx_xunlock(&map->lock, file, line); - - while (free_entry != NULL) { - entry = free_entry; - free_entry = free_entry->next; - - if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) { - object = entry->object.vm_object; - vm_object_deallocate(object); - } - - vm_map_entry_dispose(map, entry); + vm_map_process_deferred(); } } @@ -497,8 +493,10 @@ _vm_map_unlock_read(vm_map_t map, const char *file, int line) if (map->system_map) _mtx_unlock_flags(&map->system_mtx, 0, file, line); - else + else { _sx_sunlock(&map->lock, file, line); + vm_map_process_deferred(); + } } int @@ -548,6 +546,7 @@ _vm_map_lock_upgrade(vm_map_t map, const char *file, int line) if (!_sx_try_upgrade(&map->lock, file, line)) { last_timestamp = map->timestamp; _sx_sunlock(&map->lock, file, line); + vm_map_process_deferred(); /* * If the map's timestamp does not change while the * map is unlocked, then the upgrade succeeds. @@ -624,19 +623,37 @@ _vm_map_assert_locked_read(vm_map_t map, const char *file, int line) #endif /* - * vm_map_unlock_and_wait: + * _vm_map_unlock_and_wait: + * + * Atomically releases the lock on the specified map and puts the calling + * thread to sleep. The calling thread will remain asleep until either + * vm_map_wakeup() is performed on the map or the specified timeout is + * exceeded. + * + * WARNING! This function does not perform deferred deallocations of + * objects and map entries. Therefore, the calling thread is expected to + * reacquire the map lock after reawakening and later perform an ordinary + * unlock operation, such as vm_map_unlock(), before completing its + * operation on the map. */ int -vm_map_unlock_and_wait(vm_map_t map, int timo) +_vm_map_unlock_and_wait(vm_map_t map, int timo, const char *file, int line) { mtx_lock(&map_sleep_mtx); - vm_map_unlock(map); - return (msleep(&map->root, &map_sleep_mtx, PDROP | PVM, "vmmaps", timo)); + if (map->system_map) + _mtx_unlock_flags(&map->system_mtx, 0, file, line); + else + _sx_xunlock(&map->lock, file, line); + return (msleep(&map->root, &map_sleep_mtx, PDROP | PVM, "vmmaps", + timo)); } /* * vm_map_wakeup: + * + * Awaken any threads that have slept on the map using + * vm_map_unlock_and_wait(). */ void vm_map_wakeup(vm_map_t map) @@ -644,8 +661,8 @@ vm_map_wakeup(vm_map_t map) /* * Acquire and release map_sleep_mtx to prevent a wakeup() - * from being performed (and lost) between the vm_map_unlock() - * and the msleep() in vm_map_unlock_and_wait(). + * from being performed (and lost) between the map unlock + * and the msleep() in _vm_map_unlock_and_wait(). */ mtx_lock(&map_sleep_mtx); mtx_unlock(&map_sleep_mtx); @@ -699,7 +716,6 @@ _vm_map_init(vm_map_t map, pmap_t pmap, vm_offset_t min, vm_offset_t max) map->flags = 0; map->root = NULL; map->timestamp = 0; - map->deferred_freelist = NULL; } void @@ -1143,6 +1159,9 @@ vm_map_insert(vm_map_t map, vm_object_t object, vm_ooffset_t offset, } charged: + /* Expand the kernel pmap, if necessary. */ + if (map == kernel_map && end > kernel_vm_end) + pmap_growkernel(end); if (object != NULL) { /* * OBJ_ONEMAPPING must be cleared unless this mapping @@ -1279,7 +1298,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length, vm_offset_t *addr) /* OUT */ { vm_map_entry_t entry; - vm_offset_t end, st; + vm_offset_t st; /* * Request must fit within min/max VM address and must avoid @@ -1293,7 +1312,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length, /* Empty tree means wide open address space. */ if (map->root == NULL) { *addr = start; - goto found; + return (0); } /* @@ -1303,7 +1322,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length, map->root = vm_map_entry_splay(start, map->root); if (start + length <= map->root->start) { *addr = start; - goto found; + return (0); } /* @@ -1314,7 +1333,7 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length, st = (start > map->root->end) ? start : map->root->end; if (length <= map->root->end + map->root->adj_free - st) { *addr = st; - goto found; + return (0); } /* With max_free, can immediately tell if no solution. */ @@ -1332,22 +1351,13 @@ vm_map_findspace(vm_map_t map, vm_offset_t start, vm_size_t length, entry = entry->left; else if (entry->adj_free >= length) { *addr = entry->end; - goto found; + return (0); } else entry = entry->right; } /* Can't get here, so panic if we do. */ panic("vm_map_findspace: max_free corrupt"); - -found: - /* Expand the kernel pmap, if necessary. */ - if (map == kernel_map) { - end = round_page(*addr + length); - if (end > kernel_vm_end) - pmap_growkernel(end); - } - return (0); } int @@ -2602,6 +2612,15 @@ vm_map_entry_unwire(vm_map_t map, vm_map_entry_t entry) entry->wired_count = 0; } +static void +vm_map_entry_deallocate(vm_map_entry_t entry, boolean_t system_map) +{ + + if ((entry->eflags & MAP_ENTRY_IS_SUB_MAP) == 0) + vm_object_deallocate(entry->object.vm_object); + uma_zfree(system_map ? kmapentzone : mapentzone, entry); +} + /* * vm_map_entry_delete: [ internal use only ] * @@ -2656,6 +2675,12 @@ vm_map_entry_delete(vm_map_t map, vm_map_entry_t entry) VM_OBJECT_UNLOCK(object); } else entry->object.vm_object = NULL; + if (map->system_map) + vm_map_entry_deallocate(entry, TRUE); + else { + entry->next = curthread->td_map_def_user; + curthread->td_map_def_user = entry; + } } /* @@ -2744,8 +2769,6 @@ vm_map_delete(vm_map_t map, vm_offset_t start, vm_offset_t end) * will be set in the wrong object!) */ vm_map_entry_delete(map, entry); - entry->next = map->deferred_freelist; - map->deferred_freelist = entry; entry = next; } return (KERN_SUCCESS); diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index d5c5b511c43..8715b41dc7f 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -185,7 +185,6 @@ struct vm_map { vm_flags_t flags; /* flags for this vm_map */ vm_map_entry_t root; /* Root of a binary search tree */ pmap_t pmap; /* (c) Physical map */ - vm_map_entry_t deferred_freelist; #define min_offset header.start /* (c) */ #define max_offset header.end /* (c) */ }; @@ -237,7 +236,7 @@ struct vmspace { caddr_t vm_taddr; /* (c) user virtual address of text */ caddr_t vm_daddr; /* (c) user virtual address of data */ caddr_t vm_maxsaddr; /* user VA at max stack growth */ - int vm_refcnt; /* number of references */ + volatile int vm_refcnt; /* number of references */ /* * Keep the PMAP last, so that CPU-specific variations of that * structure on a single architecture don't result in offset @@ -267,6 +266,7 @@ vmspace_pmap(struct vmspace *vmspace) void _vm_map_lock(vm_map_t map, const char *file, int line); void _vm_map_unlock(vm_map_t map, const char *file, int line); +int _vm_map_unlock_and_wait(vm_map_t map, int timo, const char *file, int line); void _vm_map_lock_read(vm_map_t map, const char *file, int line); void _vm_map_unlock_read(vm_map_t map, const char *file, int line); int _vm_map_trylock(vm_map_t map, const char *file, int line); @@ -274,11 +274,12 @@ int _vm_map_trylock_read(vm_map_t map, const char *file, int line); int _vm_map_lock_upgrade(vm_map_t map, const char *file, int line); void _vm_map_lock_downgrade(vm_map_t map, const char *file, int line); int vm_map_locked(vm_map_t map); -int vm_map_unlock_and_wait(vm_map_t map, int timo); void vm_map_wakeup(vm_map_t map); #define vm_map_lock(map) _vm_map_lock(map, LOCK_FILE, LOCK_LINE) #define vm_map_unlock(map) _vm_map_unlock(map, LOCK_FILE, LOCK_LINE) +#define vm_map_unlock_and_wait(map, timo) \ + _vm_map_unlock_and_wait(map, timo, LOCK_FILE, LOCK_LINE) #define vm_map_lock_read(map) _vm_map_lock_read(map, LOCK_FILE, LOCK_LINE) #define vm_map_unlock_read(map) _vm_map_unlock_read(map, LOCK_FILE, LOCK_LINE) #define vm_map_trylock(map) _vm_map_trylock(map, LOCK_FILE, LOCK_LINE) diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index bd9f98fd588..80a2d0acf7a 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -579,6 +579,7 @@ munmap(td, uap) * Inform hwpmc if the address range being unmapped contains * an executable region. */ + pkm.pm_address = (uintptr_t) NULL; if (vm_map_lookup_entry(map, addr, &entry)) { for (; entry != &map->header && entry->start < addr + size; @@ -587,16 +588,23 @@ munmap(td, uap) entry->end, VM_PROT_EXECUTE) == TRUE) { pkm.pm_address = (uintptr_t) addr; pkm.pm_size = (size_t) size; - PMC_CALL_HOOK(td, PMC_FN_MUNMAP, - (void *) &pkm); break; } } } #endif - /* returns nothing but KERN_SUCCESS anyway */ vm_map_delete(map, addr, addr + size); + +#ifdef HWPMC_HOOKS + /* downgrade the lock to prevent a LOR with the pmc-sx lock */ + vm_map_lock_downgrade(map); + if (pkm.pm_address != (uintptr_t) NULL) + PMC_CALL_HOOK(td, PMC_FN_MUNMAP, (void *) &pkm); + vm_map_unlock_read(map); +#else vm_map_unlock(map); +#endif + /* vm_map_delete returns nothing but KERN_SUCCESS anyway */ return (0); } @@ -1365,7 +1373,8 @@ vm_mmap_shm(struct thread *td, vm_size_t objsize, { int error; - if ((*maxprotp & VM_PROT_WRITE) == 0 && + if ((*flagsp & MAP_SHARED) != 0 && + (*maxprotp & VM_PROT_WRITE) == 0 && (prot & PROT_WRITE) != 0) return (EACCES); #ifdef MAC @@ -1467,9 +1476,10 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot, */ if (handle == 0) foff = 0; - } else { + } else if (flags & MAP_PREFAULT_READ) + docow = MAP_PREFAULT; + else docow = MAP_PREFAULT_PARTIAL; - } if ((flags & (MAP_ANON|MAP_SHARED)) == 0) docow |= MAP_COPY_ON_WRITE; diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 44b801eb287..d778c992b9b 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -100,6 +100,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_msgbuf.h" #include "opt_vm.h" #include diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index f4109c1136e..3d96d9ec3db 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -701,8 +701,11 @@ vm_pageout_map_deactivate_pages(map, desired) * table pages. */ if (desired == 0 && nothingwired) { - pmap_remove(vm_map_pmap(map), vm_map_min(map), - vm_map_max(map)); + tmpe = map->header.next; + while (tmpe != &map->header) { + pmap_remove(vm_map_pmap(map), tmpe->start, tmpe->end); + tmpe = tmpe->next; + } } vm_map_unlock(map); } diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c index e75c3401acf..26e4981606a 100644 --- a/sys/vm/vm_phys.c +++ b/sys/vm/vm_phys.c @@ -123,12 +123,9 @@ sysctl_vm_phys_free(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; struct vm_freelist *fl; - char *cbuf; - const int cbufsize = vm_nfreelists*(VM_NFREEORDER + 1)*81; int error, flind, oind, pind; - cbuf = malloc(cbufsize, M_TEMP, M_WAITOK | M_ZERO); - sbuf_new(&sbuf, cbuf, cbufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (flind = 0; flind < vm_nfreelists; flind++) { sbuf_printf(&sbuf, "\nFREE LIST %d:\n" "\n ORDER (SIZE) | NUMBER" @@ -149,10 +146,8 @@ sysctl_vm_phys_free(SYSCTL_HANDLER_ARGS) sbuf_printf(&sbuf, "\n"); } } - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(cbuf, M_TEMP); return (error); } @@ -164,12 +159,9 @@ sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; struct vm_phys_seg *seg; - char *cbuf; - const int cbufsize = VM_PHYSSEG_MAX*(VM_NFREEORDER + 1)*81; int error, segind; - cbuf = malloc(cbufsize, M_TEMP, M_WAITOK | M_ZERO); - sbuf_new(&sbuf, cbuf, cbufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (segind = 0; segind < vm_phys_nsegs; segind++) { sbuf_printf(&sbuf, "\nSEGMENT %d:\n\n", segind); seg = &vm_phys_segs[segind]; @@ -180,10 +172,8 @@ sysctl_vm_phys_segs(SYSCTL_HANDLER_ARGS) sbuf_printf(&sbuf, "domain: %d\n", seg->domain); sbuf_printf(&sbuf, "free list: %p\n", seg->free_queues); } - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(cbuf, M_TEMP); return (error); } @@ -195,23 +185,18 @@ static int sysctl_vm_phys_lookup_lists(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; - char *cbuf; - const int cbufsize = (vm_nfreelists + 1) * VM_NDOMAIN * 81; int domain, error, flind, ndomains; ndomains = vm_nfreelists - VM_NFREELIST + 1; - cbuf = malloc(cbufsize, M_TEMP, M_WAITOK | M_ZERO); - sbuf_new(&sbuf, cbuf, cbufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (domain = 0; domain < ndomains; domain++) { sbuf_printf(&sbuf, "\nDOMAIN %d:\n\n", domain); for (flind = 0; flind < vm_nfreelists; flind++) sbuf_printf(&sbuf, " [%d]:\t%p\n", flind, vm_phys_lookup_lists[domain][flind]); } - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(cbuf, M_TEMP); return (error); } #endif diff --git a/sys/vm/vm_reserv.c b/sys/vm/vm_reserv.c index d9e908f62a3..aa8e80f7311 100644 --- a/sys/vm/vm_reserv.c +++ b/sys/vm/vm_reserv.c @@ -180,12 +180,9 @@ sysctl_vm_reserv_partpopq(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; vm_reserv_t rv; - char *cbuf; - const int cbufsize = (VM_NRESERVLEVEL + 1) * 81; int counter, error, level, unused_pages; - cbuf = malloc(cbufsize, M_TEMP, M_WAITOK | M_ZERO); - sbuf_new(&sbuf, cbuf, cbufsize, SBUF_FIXEDLEN); + sbuf_new_for_sysctl(&sbuf, NULL, 128, req); sbuf_printf(&sbuf, "\nLEVEL SIZE NUMBER\n\n"); for (level = -1; level <= VM_NRESERVLEVEL - 2; level++) { counter = 0; @@ -199,10 +196,8 @@ sysctl_vm_reserv_partpopq(SYSCTL_HANDLER_ARGS) sbuf_printf(&sbuf, "%5.5d: %6.6dK, %6.6d\n", level, unused_pages * (PAGE_SIZE / 1024), counter); } - sbuf_finish(&sbuf); - error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf)); + error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); - free(cbuf, M_TEMP); return (error); } diff --git a/sys/x86/cpufreq/est.c b/sys/x86/cpufreq/est.c index 144858c9451..ecca30cf59d 100644 --- a/sys/x86/cpufreq/est.c +++ b/sys/x86/cpufreq/est.c @@ -110,14 +110,16 @@ CTASSERT(EST_MAX_SETTINGS <= MAX_SETTINGS); #define EST_TRANS_LAT 1000 /* - * Frequency (MHz) and voltage (mV) settings. Data from the - * Intel Pentium M Processor Datasheet (Order Number 252612), Table 5. + * Frequency (MHz) and voltage (mV) settings. * * Dothan processors have multiple VID#s with different settings for * each VID#. Since we can't uniquely identify this info * without undisclosed methods from Intel, we can't support newer * processors with this table method. If ACPI Px states are supported, * we get info from them. + * + * Data from the "Intel Pentium M Processor Datasheet", + * Order Number 252612-003, Table 5. */ static freq_info PM17_130[] = { /* 130nm 1.70GHz Pentium M */ @@ -217,7 +219,7 @@ static freq_info PM10_ULV_130[] = { /* * Data from "Intel Pentium M Processor on 90nm Process with - * 2-MB L2 Cache Datasheet", Order Number 302189, Table 5. + * 2-MB L2 Cache Datasheet", Order Number 302189-008, Table 5. */ static freq_info PM_765A_90[] = { /* 90 nm 2.10GHz Pentium M, VID #A */ @@ -985,7 +987,7 @@ est_probe(device_t dev) device_t perf_dev; uint64_t msr; int error, type; - + if (resource_disabled("est", 0)) return (ENXIO); @@ -1125,7 +1127,7 @@ est_acpi_info(device_t dev, freq_info **freqs) if (sets[i].freq > 0) { error = est_set_id16(dev, sets[i].spec[0], strict); if (error != 0) { - if (bootverbose) + if (bootverbose) device_printf(dev, "Invalid freq %u, " "ignored.\n", sets[i].freq); continue; @@ -1221,7 +1223,7 @@ est_msr_info(device_t dev, uint64_t msr, freq_info **freqs) device_printf(dev, "Guessed bus clock (low) of %d MHz\n", bus); if (!bus_speed_ok(bus)) return (EOPNOTSUPP); - + /* Calculate high frequency. */ id = msr >> 32; freq = ((id >> 8) & 0xff) * bus; @@ -1282,14 +1284,14 @@ est_set_id16(device_t dev, uint16_t id16, int need_check) msr = rdmsr(MSR_PERF_CTL); msr = (msr & ~0xffff) | id16; wrmsr(MSR_PERF_CTL, msr); - + /* Wait a short while for the new setting. XXX Is this necessary? */ DELAY(EST_TRANS_LAT); - + if (need_check) { - est_get_id16(&new_id16); + est_get_id16(&new_id16); if (new_id16 != id16) { - if (bootverbose) + if (bootverbose) device_printf(dev, "Invalid id16 (set, cur) " "= (%u, %u)\n", id16, new_id16); ret = ENXIO; diff --git a/sys/x86/isa/atrtc.c b/sys/x86/isa/atrtc.c index 929f7e7dd79..cb24fcc0e4c 100644 --- a/sys/x86/isa/atrtc.c +++ b/sys/x86/isa/atrtc.c @@ -242,15 +242,12 @@ atrtc_attach(device_t dev) { struct atrtc_softc *sc; u_long s; - int i, diag; + int i; sc = device_get_softc(dev); if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, IO_RTC, IO_RTC + 1, 2, RF_ACTIVE))) device_printf(dev,"Warning: Couldn't map I/O.\n"); - diag = rtcin(RTC_DIAG); - if (diag != 0) - printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); atrtc_start(); clock_register(dev, 1000000); bzero(&sc->et, sizeof(struct eventtimer)); diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c index 2c0e7888b5d..5e917c1e7ea 100644 --- a/sys/x86/isa/clock.c +++ b/sys/x86/isa/clock.c @@ -95,7 +95,7 @@ int clkintr_pending; u_int i8254_freq = TIMER_FREQ; TUNABLE_INT("hw.i8254.freq", &i8254_freq); int i8254_max_count; -static int i8254_real_max_count; +static int i8254_timecounter = 1; struct mtx clock_lock; static struct intsrc *i8254_intsrc; @@ -116,10 +116,16 @@ struct attimer_softc { void *intr_handler; struct timecounter tc; struct eventtimer et; - uint32_t intr_period; + int mode; +#define MODE_STOP 0 +#define MODE_PERIODIC 1 +#define MODE_ONESHOT 2 + uint32_t period; }; static struct attimer_softc *attimer_sc = NULL; +static int timer0_period = -2; + /* Values for timerX_state: */ #define RELEASED 0 #define RELEASE_PENDING 1 @@ -129,14 +135,14 @@ static struct attimer_softc *attimer_sc = NULL; static u_char timer2_state; static unsigned i8254_get_timecount(struct timecounter *tc); -static void set_i8254_freq(u_int freq, uint32_t intr_period); +static void set_i8254_freq(int mode, uint32_t period); static int clkintr(void *arg) { struct attimer_softc *sc = (struct attimer_softc *)arg; - if (sc->intr_period != 0) { + if (i8254_timecounter && sc->period != 0) { mtx_lock_spin(&clock_lock); if (i8254_ticked) i8254_ticked = 0; @@ -148,7 +154,7 @@ clkintr(void *arg) mtx_unlock_spin(&clock_lock); } - if (sc && sc->et.et_active) + if (sc && sc->et.et_active && sc->mode != MODE_STOP) sc->et.et_event_cb(&sc->et, sc->et.et_arg); #ifdef DEV_MCA @@ -361,28 +367,43 @@ DELAY(int n) } static void -set_i8254_freq(u_int freq, uint32_t intr_period) +set_i8254_freq(int mode, uint32_t period) { - int new_i8254_real_max_count; + int new_count; mtx_lock_spin(&clock_lock); - i8254_freq = freq; - if (intr_period == 0) - new_i8254_real_max_count = 0x10000; - else { - new_i8254_real_max_count = - min(((uint64_t)i8254_freq * intr_period) >> 32, 0x10000); + if (mode == MODE_STOP) { + if (i8254_timecounter) { + mode = MODE_PERIODIC; + new_count = 0x10000; + } else + new_count = -1; + } else { + new_count = min(((uint64_t)i8254_freq * period + + 0x80000000LLU) >> 32, 0x10000); } - if (new_i8254_real_max_count != i8254_real_max_count) { - i8254_real_max_count = new_i8254_real_max_count; - if (i8254_real_max_count == 0x10000) - i8254_max_count = 0xffff; - else - i8254_max_count = i8254_real_max_count; + if (new_count == timer0_period) + goto out; + i8254_max_count = ((new_count & ~0xffff) != 0) ? 0xffff : new_count; + timer0_period = (mode == MODE_PERIODIC) ? new_count : -1; + switch (mode) { + case MODE_STOP: + outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + outb(TIMER_CNTR0, 0); + outb(TIMER_CNTR0, 0); + break; + case MODE_PERIODIC: outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); - outb(TIMER_CNTR0, i8254_real_max_count & 0xff); - outb(TIMER_CNTR0, i8254_real_max_count >> 8); + outb(TIMER_CNTR0, new_count & 0xff); + outb(TIMER_CNTR0, new_count >> 8); + break; + case MODE_ONESHOT: + outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT); + outb(TIMER_CNTR0, new_count & 0xff); + outb(TIMER_CNTR0, new_count >> 8); + break; } +out: mtx_unlock_spin(&clock_lock); } @@ -390,11 +411,11 @@ static void i8254_restore(void) { - mtx_lock_spin(&clock_lock); - outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); - outb(TIMER_CNTR0, i8254_real_max_count & 0xff); - outb(TIMER_CNTR0, i8254_real_max_count >> 8); - mtx_unlock_spin(&clock_lock); + timer0_period = -2; + if (attimer_sc != NULL) + set_i8254_freq(attimer_sc->mode, attimer_sc->period); + else + set_i8254_freq(0, 0); } #ifndef __amd64__ @@ -428,7 +449,7 @@ i8254_init(void) if (pc98_machine_type & M_8M) i8254_freq = 1996800L; /* 1.9968 MHz */ #endif - set_i8254_freq(i8254_freq, 0); + set_i8254_freq(0, 0); } void @@ -459,11 +480,12 @@ sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS) freq = i8254_freq; error = sysctl_handle_int(oidp, &freq, 0, req); if (error == 0 && req->newptr != NULL) { - if (attimer_sc) { - set_i8254_freq(freq, attimer_sc->intr_period); + i8254_freq = freq; + if (attimer_sc != NULL) { + set_i8254_freq(attimer_sc->mode, attimer_sc->period); attimer_sc->tc.tc_frequency = freq; } else { - set_i8254_freq(freq, 0); + set_i8254_freq(0, 0); } } return (error); @@ -481,7 +503,7 @@ i8254_get_timecount(struct timecounter *tc) uint16_t count; u_int high, low; - if (sc->intr_period == 0) + if (sc->period == 0) return (i8254_max_count - getit()); #ifdef __amd64__ @@ -517,13 +539,19 @@ attimer_start(struct eventtimer *et, { device_t dev = (device_t)et->et_priv; struct attimer_softc *sc = device_get_softc(dev); - - sc->intr_period = period->frac >> 32; - set_i8254_freq(i8254_freq, sc->intr_period); + + if (period != NULL) { + sc->mode = MODE_PERIODIC; + sc->period = period->frac >> 32; + } else { + sc->mode = MODE_ONESHOT; + sc->period = first->frac >> 32; + } if (!sc->intr_en) { i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc); sc->intr_en = 1; } + set_i8254_freq(sc->mode, sc->period); return (0); } @@ -533,8 +561,9 @@ attimer_stop(struct eventtimer *et) device_t dev = (device_t)et->et_priv; struct attimer_softc *sc = device_get_softc(dev); - sc->intr_period = 0; - set_i8254_freq(i8254_freq, sc->intr_period); + sc->mode = MODE_STOP; + sc->period = 0; + set_i8254_freq(sc->mode, sc->period); return (0); } @@ -630,14 +659,18 @@ attimer_attach(device_t dev) i8254_intsrc = intr_lookup_source(0); if (i8254_intsrc != NULL) i8254_pending = i8254_intsrc->is_pic->pic_source_pending; - set_i8254_freq(i8254_freq, 0); - sc->tc.tc_get_timecount = i8254_get_timecount; - sc->tc.tc_counter_mask = 0xffff; - sc->tc.tc_frequency = i8254_freq; - sc->tc.tc_name = "i8254"; - sc->tc.tc_quality = 0; - sc->tc.tc_priv = dev; - tc_init(&sc->tc); + resource_int_value(device_get_name(dev), device_get_unit(dev), + "timecounter", &i8254_timecounter); + set_i8254_freq(0, 0); + if (i8254_timecounter) { + sc->tc.tc_get_timecount = i8254_get_timecount; + sc->tc.tc_counter_mask = 0xffff; + sc->tc.tc_frequency = i8254_freq; + sc->tc.tc_name = "i8254"; + sc->tc.tc_quality = 0; + sc->tc.tc_priv = dev; + tc_init(&sc->tc); + } if (resource_int_value(device_get_name(dev), device_get_unit(dev), "clock", &i) != 0 || i != 0) { sc->intr_rid = 0; @@ -663,6 +696,8 @@ attimer_attach(device_t dev) i8254_intsrc->is_pic->pic_enable_intr(i8254_intsrc); sc->et.et_name = "i8254"; sc->et.et_flags = ET_FLAGS_PERIODIC; + if (!i8254_timecounter) + sc->et.et_flags |= ET_FLAGS_ONESHOT; sc->et.et_quality = 100; sc->et.et_frequency = i8254_freq; sc->et.et_min_period.sec = 0; diff --git a/sys/x86/pci/qpi.c b/sys/x86/pci/qpi.c new file mode 100644 index 00000000000..13151953019 --- /dev/null +++ b/sys/x86/pci/qpi.c @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 2010 Advanced Computing Technologies LLC + * Written by: John H. Baldwin + * 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. + */ + +/* + * This driver provides a psuedo-bus to enumerate the PCI buses + * present on a sytem using a QPI chipset. It creates a qpi0 bus that + * is a child of nexus0 and then creates two Host-PCI bridges as a + * child of that. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include "pcib_if.h" + +struct qpi_device { + int qd_pcibus; +}; + +static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); + +static void +qpi_identify(driver_t *driver, device_t parent) +{ + + /* Check CPUID to ensure this is an i7 CPU of some sort. */ + if (!(cpu_vendor_id == CPU_VENDOR_INTEL && + CPUID_TO_FAMILY(cpu_id) == 0x6 && + (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c))) + return; + + /* PCI config register access is required. */ + if (pci_cfgregopen() == 0) + return; + + /* Add a qpi bus device. */ + if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) + panic("Failed to add qpi bus"); +} + +static int +qpi_probe(device_t dev) +{ + + device_set_desc(dev, "QPI system bus"); + return (BUS_PROBE_SPECIFIC); +} + +/* + * Look for a PCI bus with the specified bus address. If one is found, + * add a pcib device and return 0. Otherwise, return an error code. + */ +static int +qpi_probe_pcib(device_t dev, int bus) +{ + struct qpi_device *qdev; + device_t child; + uint32_t devid; + + /* + * If a PCI bus already exists for this bus number, then + * fail. + */ + if (pci_find_bsf(bus, 0, 0) != NULL) + return (EEXIST); + + /* + * Attempt to read the device id for device 0, function 0 on + * the bus. A value of 0xffffffff means that the bus is not + * present. + */ + devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4); + if (devid == 0xffffffff) + return (ENOENT); + + if ((devid & 0xffff) != 0x8086) { + device_printf(dev, + "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus, + devid & 0xffff); + return (ENXIO); + } + + child = BUS_ADD_CHILD(dev, 0, "pcib", -1); + if (child == NULL) + panic("%s: failed to add pci bus %d", device_get_nameunit(dev), + bus); + qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); + qdev->qd_pcibus = bus; + device_set_ivars(child, qdev); + return (0); +} + +static int +qpi_attach(device_t dev) +{ + int bus; + + /* + * Each processor socket has a dedicated PCI bus counting down from + * 255. We keep probing buses until one fails. + */ + for (bus = 255;; bus--) + if (qpi_probe_pcib(dev, bus) != 0) + break; + + return (bus_generic_attach(dev)); +} + +static int +qpi_print_child(device_t bus, device_t child) +{ + struct qpi_device *qdev; + int retval = 0; + + qdev = device_get_ivars(child); + retval += bus_print_child_header(bus, child); + if (qdev->qd_pcibus != -1) + retval += printf(" pcibus %d", qdev->qd_pcibus); + retval += bus_print_child_footer(bus, child); + + return (retval); +} + +static int +qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + struct qpi_device *qdev; + + qdev = device_get_ivars(child); + switch (which) { + case PCIB_IVAR_BUS: + *result = qdev->qd_pcibus; + break; + default: + return (ENOENT); + } + return (0); +} + +static device_method_t qpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, qpi_identify), + DEVMETHOD(device_probe, qpi_probe), + DEVMETHOD(device_attach, qpi_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, qpi_print_child), + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_read_ivar, qpi_read_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static devclass_t qpi_devclass; + +DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); +DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0); + +static int +qpi_pcib_probe(device_t dev) +{ + + device_set_desc(dev, "QPI Host-PCI bridge"); + return (BUS_PROBE_SPECIFIC); +} + +static int +qpi_pcib_attach(device_t dev) +{ + + device_add_child(dev, "pci", pcib_get_bus(dev)); + return (bus_generic_attach(dev)); +} + +static int +qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) +{ + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = 0; + return (0); + case PCIB_IVAR_BUS: + *result = pcib_get_bus(dev); + return (0); + default: + return (ENOENT); + } +} + +static uint32_t +qpi_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, + u_int reg, int bytes) +{ + + return (pci_cfgregread(bus, slot, func, reg, bytes)); +} + +static void +qpi_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, + u_int reg, uint32_t data, int bytes) +{ + + pci_cfgregwrite(bus, slot, func, reg, data, bytes); +} + +static int +qpi_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, + int *irqs) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, + irqs)); +} + +static int +qpi_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); +} + +static int +qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, + uint32_t *data) +{ + device_t bus; + + bus = device_get_parent(pcib); + return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); +} + +static device_method_t qpi_pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, qpi_pcib_probe), + DEVMETHOD(device_attach, qpi_pcib_attach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* pcib interface */ + DEVMETHOD(pcib_maxslots, pcib_maxslots), + DEVMETHOD(pcib_read_config, qpi_pcib_read_config), + DEVMETHOD(pcib_write_config, qpi_pcib_write_config), + DEVMETHOD(pcib_alloc_msi, qpi_pcib_alloc_msi), + DEVMETHOD(pcib_release_msi, pcib_release_msi), + DEVMETHOD(pcib_alloc_msix, qpi_pcib_alloc_msix), + DEVMETHOD(pcib_release_msix, pcib_release_msix), + DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), + + {0, 0} +}; + +static devclass_t qpi_pcib_devclass; + +DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); +DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0); diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c index 7d19ec110c4..6d7a53b5fdc 100644 --- a/sys/x86/x86/local_apic.c +++ b/sys/x86/x86/local_apic.c @@ -89,6 +89,7 @@ CTASSERT(IPI_STOP < APIC_SPURIOUS_INT); /* Magic IRQ values for the timer and syscalls. */ #define IRQ_TIMER (NUM_IO_INTS + 1) #define IRQ_SYSCALL (NUM_IO_INTS + 2) +#define IRQ_DTRACE_RET (NUM_IO_INTS + 3) /* * Support for local APICs. Local APICs manage interrupts on each @@ -260,7 +261,7 @@ lapic_init(vm_paddr_t addr) lapic_et.et_quality = 600; if (!arat) { lapic_et.et_flags |= ET_FLAGS_C3STOP; - lapic_et.et_quality -= 100; + lapic_et.et_quality -= 200; } lapic_et.et_frequency = 0; /* We don't know frequency yet, so trying to guess. */ @@ -307,6 +308,10 @@ lapic_create(u_int apic_id, int boot_cpu) lapics[apic_id].la_ioint_irqs[IDT_SYSCALL - APIC_IO_INTS] = IRQ_SYSCALL; lapics[apic_id].la_ioint_irqs[APIC_TIMER_INT - APIC_IO_INTS] = IRQ_TIMER; +#ifdef KDTRACE_HOOKS + lapics[apic_id].la_ioint_irqs[IDT_DTRACE_RET - APIC_IO_INTS] = IRQ_DTRACE_RET; +#endif + #ifdef SMP cpu_add(apic_id, boot_cpu); @@ -369,12 +374,13 @@ lapic_setup(int boot) if (la->la_timer_mode != 0) { KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor", lapic_id())); + lapic_timer_stop(); lapic_timer_set_divisor(lapic_timer_divisor); + lapic_timer_enable_intr(); if (la->la_timer_mode == 1) lapic_timer_periodic(la->la_timer_period); else lapic_timer_oneshot(la->la_timer_period); - lapic_timer_enable_intr(); } /* Program error LVT and clear any existing errors. */ @@ -505,12 +511,10 @@ lapic_et_start(struct eventtimer *et, et->et_max_period.frac = ((0xfffffffeLLU << 32) / et->et_frequency) << 32; } - la = &lapics[lapic_id()]; - /* - * Start up the timer on the BSP. The APs will kick off their - * timer during lapic_setup(). - */ + lapic_timer_stop(); lapic_timer_set_divisor(lapic_timer_divisor); + lapic_timer_enable_intr(); + la = &lapics[lapic_id()]; if (period != NULL) { la->la_timer_mode = 1; la->la_timer_period = @@ -526,7 +530,6 @@ lapic_et_start(struct eventtimer *et, la->la_timer_period += et->et_frequency * first->sec; lapic_timer_oneshot(la->la_timer_period); } - lapic_timer_enable_intr(); return (0); } @@ -862,8 +865,9 @@ lapic_timer_stop(void) value = lapic->lvt_timer; value &= ~APIC_LVTT_TM; - value &= ~APIC_LVT_M; + value |= APIC_LVT_M; lapic->lvt_timer = value; + lapic->icr_timer = 0; } static void @@ -1029,6 +1033,10 @@ apic_enable_vector(u_int apic_id, u_int vector) KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); KASSERT(ioint_handlers[vector / 32] != NULL, ("No ISR handler for vector %u", vector)); +#ifdef KDTRACE_HOOKS + KASSERT(vector != IDT_DTRACE_RET, + ("Attempt to overwrite DTrace entry")); +#endif setidt(vector, ioint_handlers[vector / 32], SDT_APIC, SEL_KPL, GSEL_APIC); } @@ -1038,6 +1046,10 @@ apic_disable_vector(u_int apic_id, u_int vector) { KASSERT(vector != IDT_SYSCALL, ("Attempt to overwrite syscall entry")); +#ifdef KDTRACE_HOOKS + KASSERT(vector != IDT_DTRACE_RET, + ("Attempt to overwrite DTrace entry")); +#endif KASSERT(ioint_handlers[vector / 32] != NULL, ("No ISR handler for vector %u", vector)); #ifdef notyet @@ -1061,6 +1073,10 @@ apic_free_vector(u_int apic_id, u_int vector, u_int irq) KASSERT(irq < NUM_IO_INTS, ("Invalid IRQ %u", irq)); KASSERT(lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS] == irq, ("IRQ mismatch")); +#ifdef KDTRACE_HOOKS + KASSERT(vector != IDT_DTRACE_RET, + ("Attempt to overwrite DTrace entry")); +#endif /* * Bind us to the cpu that owned the vector before freeing it so @@ -1093,6 +1109,10 @@ apic_idt_to_irq(u_int apic_id, u_int vector) KASSERT(vector >= APIC_IO_INTS && vector != IDT_SYSCALL && vector <= APIC_IO_INTS + APIC_NUM_IOINTS, ("Vector %u does not map to an IRQ line", vector)); +#ifdef KDTRACE_HOOKS + KASSERT(vector != IDT_DTRACE_RET, + ("Attempt to overwrite DTrace entry")); +#endif irq = lapics[apic_id].la_ioint_irqs[vector - APIC_IO_INTS]; if (irq < 0) irq = 0; @@ -1124,6 +1144,10 @@ DB_SHOW_COMMAND(apic, db_show_apic) irq = lapics[apic_id].la_ioint_irqs[i]; if (irq == -1 || irq == IRQ_SYSCALL) continue; +#ifdef KDTRACE_HOOKS + if (irq == IRQ_DTRACE_RET) + continue; +#endif db_printf("vec 0x%2x -> ", i + APIC_IO_INTS); if (irq == IRQ_TIMER) db_printf("lapic timer\n"); diff --git a/sys/xen/blkif.h b/sys/xen/blkif.h new file mode 100644 index 00000000000..48b71ea7f54 --- /dev/null +++ b/sys/xen/blkif.h @@ -0,0 +1,145 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef __XEN_BLKIF_H__ +#define __XEN_BLKIF_H__ + +#include +#include +#include + +/* Not a real protocol. Used to generate ring structs which contain + * the elements common to all protocols only. This way we get a + * compiler-checkable way to use common struct elements, so we can + * avoid using switch(protocol) in a number of places. */ +struct blkif_common_request { + char dummy; +}; +struct blkif_common_response { + char dummy; +}; + +/* i386 protocol version */ +#pragma pack(push, 4) +struct blkif_x86_32_request { + uint8_t operation; /* BLKIF_OP_??? */ + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t id; /* private guest value, echoed in resp */ + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK]; +}; +struct blkif_x86_32_response { + uint64_t id; /* copied from request */ + uint8_t operation; /* copied from request */ + int16_t status; /* BLKIF_RSP_??? */ +}; +typedef struct blkif_x86_32_request blkif_x86_32_request_t; +typedef struct blkif_x86_32_response blkif_x86_32_response_t; +#pragma pack(pop) + +/* x86_64 protocol version */ +struct blkif_x86_64_request { + uint8_t operation; /* BLKIF_OP_??? */ + uint8_t nr_segments; /* number of segments */ + blkif_vdev_t handle; /* only for read/write requests */ + uint64_t __attribute__((__aligned__(8))) id; + blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK]; +}; +struct blkif_x86_64_response { + uint64_t __attribute__((__aligned__(8))) id; + uint8_t operation; /* copied from request */ + int16_t status; /* BLKIF_RSP_??? */ +}; +typedef struct blkif_x86_64_request blkif_x86_64_request_t; +typedef struct blkif_x86_64_response blkif_x86_64_response_t; + +DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response); +DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response); +DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response); + +/* + * Maximum number of requests that can be active for a given instance + * regardless of the protocol in use, based on the ring size. This constant + * facilitates resource pre-allocation in backend drivers since the size is + * known well in advance of attaching to a front end. + */ +#define BLKIF_MAX_RING_REQUESTS(_sz) \ + MAX(__RING_SIZE((blkif_x86_64_sring_t *)NULL, _sz), \ + MAX(__RING_SIZE((blkif_x86_32_sring_t *)NULL, _sz), \ + __RING_SIZE((blkif_sring_t *)NULL, _sz))) + +/* + * The number of ring pages required to support a given number of requests + * for a given instance regardless of the protocol in use. + */ +#define BLKIF_RING_PAGES(_entries) \ + MAX(__RING_PAGES((blkif_x86_64_sring_t *)NULL, _entries), \ + MAX(__RING_PAGES((blkif_x86_32_sring_t *)NULL, _entries), \ + __RING_PAGES((blkif_sring_t *)NULL, _entries))) + +union blkif_back_rings { + blkif_back_ring_t native; + blkif_common_back_ring_t common; + blkif_x86_32_back_ring_t x86_32; + blkif_x86_64_back_ring_t x86_64; +}; +typedef union blkif_back_rings blkif_back_rings_t; + +enum blkif_protocol { + BLKIF_PROTOCOL_NATIVE = 1, + BLKIF_PROTOCOL_X86_32 = 2, + BLKIF_PROTOCOL_X86_64 = 3, +}; + +static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src) +{ + int i, n = BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK; + dst->operation = src->operation; + dst->nr_segments = src->nr_segments; + dst->handle = src->handle; + dst->id = src->id; + dst->sector_number = src->sector_number; + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->seg[i] = src->seg[i]; +} + +static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src) +{ + int i, n = BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK; + dst->operation = src->operation; + dst->nr_segments = src->nr_segments; + dst->handle = src->handle; + dst->id = src->id; + dst->sector_number = src->sector_number; + barrier(); + if (n > dst->nr_segments) + n = dst->nr_segments; + for (i = 0; i < n; i++) + dst->seg[i] = src->seg[i]; +} + +#endif /* __XEN_BLKIF_H__ */ diff --git a/sys/xen/evtchn/evtchn.c b/sys/xen/evtchn/evtchn.c index f280d127031..3832277f0b9 100644 --- a/sys/xen/evtchn/evtchn.c +++ b/sys/xen/evtchn/evtchn.c @@ -492,15 +492,15 @@ bind_listening_port_to_irqhandler(unsigned int remote_domain, int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain, unsigned int remote_port, const char *devname, - driver_filter_t filter, driver_intr_t handler, - unsigned long irqflags, unsigned int *irqp) + driver_intr_t handler, void *arg, unsigned long irqflags, + unsigned int *irqp) { unsigned int irq; int error; irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port); intr_register_source(&xp->xp_pins[irq].xp_intsrc); - error = intr_add_handler(devname, irq, filter, handler, NULL, + error = intr_add_handler(devname, irq, NULL, handler, arg, irqflags, &xp->xp_pins[irq].xp_cookie); if (error) { unbind_from_irq(irq); diff --git a/sys/xen/gnttab.c b/sys/xen/gnttab.c index ae44e8f6a8f..4ece182c31a 100644 --- a/sys/xen/gnttab.c +++ b/sys/xen/gnttab.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); /* External tools reserve first few grant table entries. */ #define NR_RESERVED_ENTRIES 8 -#define GNTTAB_LIST_END 0xffffffff #define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t)) static grant_ref_t **gnttab_list; @@ -66,7 +65,7 @@ get_free_entries(int count, int *entries) { int ref, error; grant_ref_t head; - + mtx_lock(&gnttab_list_lock); if ((gnttab_free_count < count) && ((error = gnttab_expand(count - gnttab_free_count)) != 0)) { @@ -79,7 +78,7 @@ get_free_entries(int count, int *entries) head = gnttab_entry(head); gnttab_free_head = gnttab_entry(head); gnttab_entry(head) = GNTTAB_LIST_END; - mtx_unlock(&gnttab_list_lock); + mtx_unlock(&gnttab_list_lock); *entries = ref; return (0); @@ -122,7 +121,7 @@ put_free_entry(grant_ref_t ref) gnttab_free_head = ref; gnttab_free_count++; check_free_callbacks(); - mtx_unlock(&gnttab_list_lock); + mtx_unlock(&gnttab_list_lock); } /* @@ -136,7 +135,7 @@ gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly, int error, ref; error = get_free_entries(1, &ref); - + if (unlikely(error)) return (error); @@ -166,9 +165,9 @@ int gnttab_query_foreign_access(grant_ref_t ref) { uint16_t nflags; - + nflags = shared[ref].flags; - + return (nflags & (GTF_reading|GTF_writing)); } @@ -180,7 +179,7 @@ gnttab_end_foreign_access_ref(grant_ref_t ref) nflags = shared[ref].flags; do { if ( (flags = nflags) & (GTF_reading|GTF_writing) ) { - printf("WARNING: g.e. still in use!\n"); + printf("%s: WARNING: g.e. still in use!\n", __func__); return (0); } } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != @@ -201,7 +200,44 @@ gnttab_end_foreign_access(grant_ref_t ref, void *page) else { /* XXX This needs to be fixed so that the ref and page are placed on a list to be freed up later. */ - printf("WARNING: leaking g.e. and page still in use!\n"); + printf("%s: WARNING: leaking g.e. and page still in use!\n", + __func__); + } +} + +void +gnttab_end_foreign_access_references(u_int count, grant_ref_t *refs) +{ + grant_ref_t *last_ref; + grant_ref_t head; + grant_ref_t tail; + + head = GNTTAB_LIST_END; + tail = *refs; + last_ref = refs + count; + while (refs != last_ref) { + + if (gnttab_end_foreign_access_ref(*refs)) { + gnttab_entry(*refs) = head; + head = *refs; + } else { + /* + * XXX This needs to be fixed so that the ref + * is placed on a list to be freed up later. + */ + printf("%s: WARNING: leaking g.e. still in use!\n", + __func__); + count--; + } + refs++; + } + + if (count != 0) { + mtx_lock(&gnttab_list_lock); + gnttab_free_count += count; + gnttab_entry(tail) = gnttab_free_head; + gnttab_free_head = head; + mtx_unlock(&gnttab_list_lock); } } @@ -216,7 +252,7 @@ gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn, return (error); gnttab_grant_foreign_transfer_ref(ref, domid, pfn); - + *result = ref; return (0); } @@ -282,16 +318,16 @@ gnttab_free_grant_references(grant_ref_t head) { grant_ref_t ref; int count = 1; - + if (head == GNTTAB_LIST_END) return; - - mtx_lock(&gnttab_list_lock); + ref = head; while (gnttab_entry(ref) != GNTTAB_LIST_END) { ref = gnttab_entry(ref); count++; } + mtx_lock(&gnttab_list_lock); gnttab_entry(ref) = gnttab_free_head; gnttab_free_head = head; gnttab_free_count += count; @@ -403,7 +439,7 @@ grow_gnttab_list(unsigned int more_frames) check_free_callbacks(); return (0); - + grow_nomem: for ( ; i >= nr_grant_frames; i--) free(gnttab_list[i], M_DEVBUF); @@ -490,7 +526,7 @@ gnttab_map(unsigned int start_idx, unsigned int end_idx) if (shared == NULL) { vm_offset_t area; - + area = kmem_alloc_nofault(kernel_map, PAGE_SIZE * max_nr_grant_frames()); KASSERT(area, ("can't allocate VM space for grant table")); @@ -502,7 +538,7 @@ gnttab_map(unsigned int start_idx, unsigned int end_idx) ((vm_paddr_t)frames[i]) << PAGE_SHIFT | PG_RW | PG_V); free(frames, M_DEVBUF); - + return (0); } @@ -517,7 +553,7 @@ gnttab_resume(void) int gnttab_suspend(void) -{ +{ int i; for (i = 0; i < nr_grant_frames; i++) @@ -532,7 +568,8 @@ gnttab_suspend(void) static vm_paddr_t resume_frames; -static int gnttab_map(unsigned int start_idx, unsigned int end_idx) +static int +gnttab_map(unsigned int start_idx, unsigned int end_idx) { struct xen_add_to_physmap xatp; unsigned int i = end_idx; @@ -552,7 +589,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) if (shared == NULL) { vm_offset_t area; - + area = kmem_alloc_nofault(kernel_map, PAGE_SIZE * max_nr_grant_frames()); KASSERT(area, ("can't allocate VM space for grant table")); @@ -643,10 +680,10 @@ gnttab_init() if (gnttab_list[i] == NULL) goto ini_nomem; } - + if (gnttab_resume()) return (ENODEV); - + nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) @@ -670,4 +707,3 @@ ini_nomem: } MTX_SYSINIT(gnttab, &gnttab_list_lock, "GNTTAB LOCK", MTX_DEF); -//SYSINIT(gnttab, SI_SUB_PSEUDO, SI_ORDER_FIRST, gnttab_init, NULL); diff --git a/sys/xen/gnttab.h b/sys/xen/gnttab.h index 8348af5351f..1741ec33872 100644 --- a/sys/xen/gnttab.h +++ b/sys/xen/gnttab.h @@ -43,6 +43,8 @@ #include #include +#define GNTTAB_LIST_END GRANT_REF_INVALID + struct gnttab_free_callback { struct gnttab_free_callback *next; void (*fn)(void *); @@ -74,6 +76,13 @@ int gnttab_end_foreign_access_ref(grant_ref_t ref); */ void gnttab_end_foreign_access(grant_ref_t ref, void *page); +/* + * Eventually end access through the given array of grant references. + * Access will be ended immediately iff the grant entry is not in use, + * otherwise it will happen some time later + */ +void gnttab_end_foreign_access_references(u_int count, grant_ref_t *refs); + int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn, grant_ref_t *result); unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref); diff --git a/sys/xen/interface/grant_table.h b/sys/xen/interface/grant_table.h index 26f2c35b181..e76ca67ec5f 100644 --- a/sys/xen/interface/grant_table.h +++ b/sys/xen/interface/grant_table.h @@ -159,6 +159,8 @@ typedef struct grant_entry grant_entry_t; */ typedef uint32_t grant_ref_t; +#define GRANT_REF_INVALID 0xffffffff + /* * Handle to track a mapping created via a grant reference. */ diff --git a/sys/xen/interface/hvm/params.h b/sys/xen/interface/hvm/params.h index 6befa78df8a..d846731e111 100644 --- a/sys/xen/interface/hvm/params.h +++ b/sys/xen/interface/hvm/params.h @@ -95,4 +95,30 @@ #define HVM_NR_PARAMS 15 +#ifdef XENHVM +/** + * Retrieve an HVM setting from the hypervisor. + * + * \param index The index of the HVM parameter to retrieve. + * + * \return On error, 0. Otherwise the value of the requested parameter. + */ +static inline unsigned long +hvm_get_parameter(int index) +{ + struct xen_hvm_param xhv; + int error; + + xhv.domid = DOMID_SELF; + xhv.index = index; + error = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); + if (error) { + printf("hvm_get_parameter: failed to get %d, error %d\n", + index, error); + return (0); + } + return (xhv.value); +} +#endif + #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ diff --git a/sys/xen/interface/io/blkif.h b/sys/xen/interface/io/blkif.h index 9e2d3d068b6..020936b1f53 100644 --- a/sys/xen/interface/io/blkif.h +++ b/sys/xen/interface/io/blkif.h @@ -78,11 +78,19 @@ #define BLKIF_OP_FLUSH_DISKCACHE 3 /* - * Maximum scatter/gather segments per request. - * This is carefully chosen so that sizeof(blkif_ring_t) <= PAGE_SIZE. - * NB. This could be 12 if the ring indexes weren't stored in the same page. + * Maximum scatter/gather segments associated with a request header block. */ -#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11 +#define BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK 11 + +/* + * Maximum scatter/gather segments associated with a segment block. + */ +#define BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK 14 + +/* + * Maximum scatter/gather segments per request (header + segment blocks). + */ +#define BLKIF_MAX_SEGMENTS_PER_REQUEST 255 struct blkif_request_segment { grant_ref_t gref; /* reference to I/O buffer frame */ @@ -90,6 +98,7 @@ struct blkif_request_segment { /* @last_sect: last sector in frame to transfer (inclusive). */ uint8_t first_sect, last_sect; }; +typedef struct blkif_request_segment blkif_request_segment_t; struct blkif_request { uint8_t operation; /* BLKIF_OP_??? */ @@ -97,7 +106,7 @@ struct blkif_request { blkif_vdev_t handle; /* only for read/write requests */ uint64_t id; /* private guest value, echoed in resp */ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ - struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK]; }; typedef struct blkif_request blkif_request_t; @@ -124,10 +133,22 @@ typedef struct blkif_response blkif_response_t; DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response); +#define BLKRING_GET_SG_REQUEST(_r, _idx) \ + ((struct blkif_request_segment *)RING_GET_REQUEST(_r, _idx)) + #define VDISK_CDROM 0x1 #define VDISK_REMOVABLE 0x2 #define VDISK_READONLY 0x4 +/* + * The number of ring request blocks required to handle an I/O + * request containing _segs segments. + */ +#define BLKIF_SEGS_TO_BLOCKS(_segs) \ + ((((_segs - BLKIF_MAX_SEGMENTS_PER_HEADER_BLOCK) \ + + (BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK - 1)) \ + / BLKIF_MAX_SEGMENTS_PER_SEGMENT_BLOCK) + /*header_block*/1) + #endif /* __XEN_PUBLIC_IO_BLKIF_H__ */ /* diff --git a/sys/xen/interface/io/protocols.h b/sys/xen/interface/io/protocols.h index 77bd1bdd288..fd52934e276 100644 --- a/sys/xen/interface/io/protocols.h +++ b/sys/xen/interface/io/protocols.h @@ -26,6 +26,7 @@ #define XEN_IO_PROTO_ABI_X86_32 "x86_32-abi" #define XEN_IO_PROTO_ABI_X86_64 "x86_64-abi" #define XEN_IO_PROTO_ABI_IA64 "ia64-abi" +#define XEN_IO_PROTO_ABI_POWERPC64 "powerpc64-abi" #if defined(__i386__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32 @@ -33,6 +34,8 @@ # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64 #elif defined(__ia64__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 +#elif defined(__powerpc64__) +# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 #else # error arch fixup needed here #endif diff --git a/sys/xen/interface/io/ring.h b/sys/xen/interface/io/ring.h index 6ce1d0d485f..6b7fd74e8bb 100644 --- a/sys/xen/interface/io/ring.h +++ b/sys/xen/interface/io/ring.h @@ -44,6 +44,12 @@ typedef unsigned int RING_IDX; #define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x)) #define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x)) +/* + * The amount of space reserved in the shared ring for accounting information. + */ +#define __RING_HEADER_SIZE(_s) \ + ((intptr_t)(_s)->ring - (intptr_t)(_s)) + /* * Calculate size of a shared ring, given the total available space for the * ring and indexes (_sz), and the name tag of the request/response structure. @@ -51,7 +57,17 @@ typedef unsigned int RING_IDX; * power of two (so we can mask with (size-1) to loop around). */ #define __RING_SIZE(_s, _sz) \ - (__RD32(((_sz) - (long)(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0]))) + (__RD32(((_sz) - __RING_HEADER_SIZE(_s)) / sizeof((_s)->ring[0]))) + +/* + * The number of pages needed to support a given number of request/reponse + * entries. The entry count is rounded down to the nearest power of two + * as required by the ring macros. + */ +#define __RING_PAGES(_s, _entries) \ + ((__RING_HEADER_SIZE(_s) \ + + (__RD32(_entries) * sizeof((_s)->ring[0])) \ + + PAGE_SIZE - 1) / PAGE_SIZE) /* * Macros to make the correct C datatypes for a new kind of ring. diff --git a/sys/xen/interface/io/xenbus.h b/sys/xen/interface/io/xenbus.h index 4a053df2a83..5e24f31ccf8 100644 --- a/sys/xen/interface/io/xenbus.h +++ b/sys/xen/interface/io/xenbus.h @@ -36,6 +36,9 @@ enum xenbus_state { XenbusStateUnknown = 0, + /* + * Initializing: Back-end is initializing. + */ XenbusStateInitialising = 1, /* @@ -49,6 +52,9 @@ enum xenbus_state { */ XenbusStateInitialised = 3, + /* + * Connected: The normal state for a front to backend connection. + */ XenbusStateConnected = 4, /* @@ -56,6 +62,9 @@ enum xenbus_state { */ XenbusStateClosing = 5, + /* + * Closed: No connection exists between front and back end. + */ XenbusStateClosed = 6, /* diff --git a/sys/xen/reboot.c b/sys/xen/reboot.c deleted file mode 100644 index 04ba1326c8b..00000000000 --- a/sys/xen/reboot.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * - * Copyright (c) 2004 Christian Limpach. - * Copyright (c) 2004-2006,2008 Kip Macy - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Christian Limpach. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#ifdef XENHVM - -#include - -#else - -static void xen_suspend(void); - -#endif - -static void -shutdown_handler(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - char *str; - struct xenbus_transaction xbt; - int error, howto; - - howto = 0; - - again: - error = xenbus_transaction_start(&xbt); - if (error) - return; - - error = xenbus_read(xbt, "control", "shutdown", NULL, (void **) &str); - - /* Ignore read errors and empty reads. */ - if (error || strlen(str) == 0) { - xenbus_transaction_end(xbt, 1); - return; - } - - xenbus_write(xbt, "control", "shutdown", ""); - - error = xenbus_transaction_end(xbt, 0); - if (error == EAGAIN) { - free(str, M_DEVBUF); - goto again; - } - - if (strcmp(str, "reboot") == 0) - howto = 0; - else if (strcmp(str, "poweroff") == 0) - howto |= (RB_POWEROFF | RB_HALT); - else if (strcmp(str, "halt") == 0) -#ifdef XENHVM - /* - * We rely on acpi powerdown to halt the VM. - */ - howto |= (RB_POWEROFF | RB_HALT); -#else - howto |= RB_HALT; -#endif - else if (strcmp(str, "suspend") == 0) - howto = -1; - else { - printf("Ignoring shutdown request: %s\n", str); - goto done; - } - - if (howto == -1) { - xen_suspend(); - goto done; - } - - shutdown_nice(howto); - done: - free(str, M_DEVBUF); -} - -#ifndef XENHVM - -/* - * In HV mode, we let acpi take care of halts and reboots. - */ - -static void -xen_shutdown_final(void *arg, int howto) -{ - - if (howto & (RB_HALT | RB_POWEROFF)) - HYPERVISOR_shutdown(SHUTDOWN_poweroff); - else - HYPERVISOR_shutdown(SHUTDOWN_reboot); -} - -#endif - -static struct xenbus_watch shutdown_watch = { - .node = "control/shutdown", - .callback = shutdown_handler -}; - -static void -setup_shutdown_watcher(void *unused) -{ - - if (register_xenbus_watch(&shutdown_watch)) - printf("Failed to set shutdown watcher\n"); -#ifndef XENHVM - EVENTHANDLER_REGISTER(shutdown_final, xen_shutdown_final, NULL, - SHUTDOWN_PRI_LAST); -#endif -} - -SYSINIT(shutdown, SI_SUB_PSEUDO, SI_ORDER_ANY, setup_shutdown_watcher, NULL); - -#ifndef XENHVM - -extern void xencons_suspend(void); -extern void xencons_resume(void); - -static void -xen_suspend() -{ - int i, j, k, fpp; - unsigned long max_pfn, start_info_mfn; - -#ifdef SMP - cpumask_t map; - /* - * Bind us to CPU 0 and stop any other VCPUs. - */ - thread_lock(curthread); - sched_bind(curthread, 0); - thread_unlock(curthread); - KASSERT(PCPU_GET(cpuid) == 0, ("xen_suspend: not running on cpu 0")); - - map = PCPU_GET(other_cpus) & ~stopped_cpus; - if (map) - stop_cpus(map); -#endif - - if (DEVICE_SUSPEND(root_bus) != 0) { - printf("xen_suspend: device_suspend failed\n"); -#ifdef SMP - if (map) - restart_cpus(map); -#endif - return; - } - - local_irq_disable(); - - xencons_suspend(); - gnttab_suspend(); - - max_pfn = HYPERVISOR_shared_info->arch.max_pfn; - - void *shared_info = HYPERVISOR_shared_info; - HYPERVISOR_shared_info = NULL; - pmap_kremove((vm_offset_t) shared_info); - PT_UPDATES_FLUSH(); - - xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn); - xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn); - - /* - * We'll stop somewhere inside this hypercall. When it returns, - * we'll start resuming after the restore. - */ - start_info_mfn = VTOMFN(xen_start_info); - pmap_suspend(); - HYPERVISOR_suspend(start_info_mfn); - pmap_resume(); - - pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info); - HYPERVISOR_shared_info = shared_info; - - HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = - VTOMFN(xen_pfn_to_mfn_frame_list_list); - - fpp = PAGE_SIZE/sizeof(unsigned long); - for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { - if ((j % fpp) == 0) { - k++; - xen_pfn_to_mfn_frame_list_list[k] = - VTOMFN(xen_pfn_to_mfn_frame_list[k]); - j = 0; - } - xen_pfn_to_mfn_frame_list[k][j] = - VTOMFN(&xen_phys_machine[i]); - } - HYPERVISOR_shared_info->arch.max_pfn = max_pfn; - - gnttab_resume(); - irq_resume(); - local_irq_enable(); - xencons_resume(); - -#ifdef CONFIG_SMP - for_each_cpu(i) - vcpu_prepare(i); - -#endif - /* - * Only resume xenbus /after/ we've prepared our VCPUs; otherwise - * the VCPU hotplug callback can race with our vcpu_prepare - */ - DEVICE_RESUME(root_bus); - -#ifdef SMP - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); - if (map) - restart_cpus(map); -#endif -} - -#endif diff --git a/sys/xen/xen_intr.h b/sys/xen/xen_intr.h index 68f594333fd..2e753e65ecb 100644 --- a/sys/xen/xen_intr.h +++ b/sys/xen/xen_intr.h @@ -76,7 +76,7 @@ extern int bind_ipi_to_irqhandler(unsigned int ipi, unsigned int cpu, */ extern int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain, unsigned int remote_port, const char *devname, - driver_filter_t filter, driver_intr_t handler, + driver_intr_t handler, void *arg, unsigned long irqflags, unsigned int *irqp); /* diff --git a/sys/xen/xenbus/init.txt b/sys/xen/xenbus/init.txt deleted file mode 100644 index 42495494bd0..00000000000 --- a/sys/xen/xenbus/init.txt +++ /dev/null @@ -1,14 +0,0 @@ - - -- frontend driver initializes static xenbus_driver with _ids, _probe, _remove, -_resume, _otherend_changed - - - initialization calls xenbus_register_frontend(xenbus_driver) - - - xenbus_register_frontend sets read_otherend details to read_backend_details - then calls xenbus_register_driver_common(xenbus_driver, xenbus_frontend) - - - xenbus_register_driver_common sets underlying driver name to xenbus_driver name - underlying driver bus to xenbus_frontend's bus, driver's probe to xenbus_dev_probe - driver's remove to xenbus_dev_remove then calls driver_register - diff --git a/sys/xen/xenbus/xenbus_client.c b/sys/xen/xenbus/xenbus.c similarity index 65% rename from sys/xen/xenbus/xenbus_client.c rename to sys/xen/xenbus/xenbus.c index 740d66409e1..c3e5fee32bc 100644 --- a/sys/xen/xenbus/xenbus_client.c +++ b/sys/xen/xenbus/xenbus.c @@ -1,8 +1,4 @@ /****************************************************************************** - * Client-facing interface for the Xenbus driver. In other words, the - * interface between the Xenbus and the device-specific code, be it the - * frontend or the backend of that driver. - * * Copyright (C) 2005 XenSource Ltd * * This file may be distributed separately from the Linux kernel, or @@ -27,6 +23,14 @@ * IN THE SOFTWARE. */ +/** + * \file xenbus.c + * + * \brief Client-facing interface for the Xenbus driver. + * + * In other words, the interface between the Xenbus and the device-specific + * code, be it the frontend or the backend of that driver. + */ #if 0 #define DPRINTK(fmt, args...) \ @@ -39,9 +43,12 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include #include +#include #include #include @@ -50,6 +57,34 @@ __FBSDID("$FreeBSD$"); #include #include +MALLOC_DEFINE(M_XENBUS, "xenbus", "XenBus Support"); + +/*------------------------- Private Functions --------------------------------*/ +/** + * \brief Construct the error path corresponding to the given XenBus + * device. + * + * \param dev The XenBus device for which we are constructing an error path. + * + * \return On success, the contructed error path. Otherwise NULL. + * + * It is the caller's responsibility to free any returned error path + * node using the M_XENBUS malloc type. + */ +static char * +error_path(device_t dev) +{ + char *path_buffer = malloc(strlen("error/") + + strlen(xenbus_get_node(dev)) + 1,M_XENBUS, M_WAITOK); + + strcpy(path_buffer, "error/"); + strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); + + return (path_buffer); +} + +/*--------------------------- Public Functions -------------------------------*/ +/*-------- API comments for these methods can be found in xenbusvar.h --------*/ const char * xenbus_strstate(XenbusState state) { @@ -67,15 +102,15 @@ xenbus_strstate(XenbusState state) } int -xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, const char **, unsigned int)) +xenbus_watch_path(device_t dev, char *path, struct xs_watch *watch, + xs_watch_cb_t *callback) { int error; watch->node = path; watch->callback = callback; - error = register_xenbus_watch(watch); + error = xs_register_watch(watch); if (error) { watch->node = NULL; @@ -88,12 +123,12 @@ xenbus_watch_path(device_t dev, char *path, struct xenbus_watch *watch, int xenbus_watch_path2(device_t dev, const char *path, - const char *path2, struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, const char **, unsigned int)) + const char *path2, struct xs_watch *watch, + xs_watch_cb_t *callback) { int error; char *state = malloc(strlen(path) + 1 + strlen(path2) + 1, - M_DEVBUF, M_WAITOK); + M_XENBUS, M_WAITOK); strcpy(state, path); strcat(state, "/"); @@ -101,46 +136,27 @@ xenbus_watch_path2(device_t dev, const char *path, error = xenbus_watch_path(dev, state, watch, callback); if (error) { - free(state, M_DEVBUF); + free(state,M_XENBUS); } return (error); } -/** - * Return the path to the error node for the given device, or NULL on failure. - * If the value returned is non-NULL, then it is the caller's to kfree. - */ -static char * -error_path(device_t dev) -{ - char *path_buffer = malloc(strlen("error/") - + strlen(xenbus_get_node(dev)) + 1, M_DEVBUF, M_WAITOK); - - strcpy(path_buffer, "error/"); - strcpy(path_buffer + strlen("error/"), xenbus_get_node(dev)); - - return (path_buffer); -} - - -static void -_dev_error(device_t dev, int err, const char *fmt, va_list ap) +void +xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap) { int ret; unsigned int len; char *printf_buffer = NULL, *path_buffer = NULL; #define PRINTF_BUFFER_SIZE 4096 - printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK); + printf_buffer = malloc(PRINTF_BUFFER_SIZE,M_XENBUS, M_WAITOK); len = sprintf(printf_buffer, "%i ", err); ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); KASSERT(len + ret <= PRINTF_BUFFER_SIZE-1, ("xenbus error message too big")); -#if 0 - dev_err(&dev->dev, "%s\n", printf_buffer); -#endif + device_printf(dev, "Error %s\n", printf_buffer); path_buffer = error_path(dev); if (path_buffer == NULL) { @@ -149,7 +165,7 @@ _dev_error(device_t dev, int err, const char *fmt, va_list ap) goto fail; } - if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { + if (xs_write(XST_NIL, path_buffer, "error", printf_buffer) != 0) { printf("xenbus: failed to write error node for %s (%s)\n", xenbus_get_node(dev), printf_buffer); goto fail; @@ -157,9 +173,9 @@ _dev_error(device_t dev, int err, const char *fmt, va_list ap) fail: if (printf_buffer) - free(printf_buffer, M_DEVBUF); + free(printf_buffer,M_XENBUS); if (path_buffer) - free(path_buffer, M_DEVBUF); + free(path_buffer,M_XENBUS); } void @@ -168,41 +184,45 @@ xenbus_dev_error(device_t dev, int err, const char *fmt, ...) va_list ap; va_start(ap, fmt); - _dev_error(dev, err, fmt, ap); + xenbus_dev_verror(dev, err, fmt, ap); va_end(ap); } +void +xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list ap) +{ + xenbus_dev_verror(dev, err, fmt, ap); + device_printf(dev, "Fatal error. Transitioning to Closing State\n"); + xenbus_set_state(dev, XenbusStateClosing); +} + void xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - _dev_error(dev, err, fmt, ap); + xenbus_dev_vfatal(dev, err, fmt, ap); va_end(ap); - - xenbus_set_state(dev, XenbusStateClosing); } int -xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp) +xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp) { int error; - grant_ref_t ref; error = gnttab_grant_foreign_access( - xenbus_get_otherend_id(dev), ring_mfn, 0, &ref); + xenbus_get_otherend_id(dev), ring_mfn, 0, refp); if (error) { xenbus_dev_fatal(dev, error, "granting access to ring page"); return (error); } - *refp = ref; return (0); } int -xenbus_alloc_evtchn(device_t dev, int *port) +xenbus_alloc_evtchn(device_t dev, evtchn_port_t *port) { struct evtchn_alloc_unbound alloc_unbound; int err; @@ -222,7 +242,7 @@ xenbus_alloc_evtchn(device_t dev, int *port) } int -xenbus_free_evtchn(device_t dev, int port) +xenbus_free_evtchn(device_t dev, evtchn_port_t port) { struct evtchn_close close; int err; @@ -240,12 +260,29 @@ xenbus_free_evtchn(device_t dev, int port) XenbusState xenbus_read_driver_state(const char *path) { - XenbusState result; - int error; + XenbusState result; + int error; - error = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); - if (error) - result = XenbusStateClosed; + error = xs_gather(XST_NIL, path, "state", "%d", &result, NULL); + if (error) + result = XenbusStateClosed; - return (result); + return (result); +} + +int +xenbus_dev_is_online(device_t dev) +{ + const char *path; + int error; + int value; + + path = xenbus_get_node(dev); + error = xs_gather(XST_NIL, path, "online", "%d", &value, NULL); + if (error != 0) { + /* Default to not online. */ + value = 0; + } + + return (value); } diff --git a/sys/xen/xenbus/xenbus_comms.c b/sys/xen/xenbus/xenbus_comms.c deleted file mode 100644 index 2f039551792..00000000000 --- a/sys/xen/xenbus/xenbus_comms.c +++ /dev/null @@ -1,226 +0,0 @@ -/****************************************************************************** - * xenbus_comms.c - * - * Low level code to talks to Xen Store: ringbuffer and event channel. - * - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -static unsigned int xenstore_irq; - -static inline struct xenstore_domain_interface * -xenstore_domain_interface(void) -{ - - return (struct xenstore_domain_interface *)xen_store; -} - -static void -xb_intr(void * arg __attribute__((unused))) -{ - - wakeup(xen_store); -} - -static int -xb_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) -{ - - return ((prod - cons) <= XENSTORE_RING_SIZE); -} - -static void * -xb_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, - char *buf, uint32_t *len) -{ - - *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); - if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) - *len = XENSTORE_RING_SIZE - (prod - cons); - return (buf + MASK_XENSTORE_IDX(prod)); -} - -static const void * -xb_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, - const char *buf, uint32_t *len) -{ - - *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); - if ((prod - cons) < *len) - *len = prod - cons; - return (buf + MASK_XENSTORE_IDX(cons)); -} - -int -xb_write(const void *tdata, unsigned len, struct lock_object *lock) -{ - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - XENSTORE_RING_IDX cons, prod; - const char *data = (const char *)tdata; - int error; - - while (len != 0) { - void *dst; - unsigned int avail; - - while ((intf->req_prod - intf->req_cons) - == XENSTORE_RING_SIZE) { - error = _sleep(intf, - lock, - PCATCH, "xbwrite", hz/10); - if (error && error != EWOULDBLOCK) - return (error); - } - - /* Read indexes, then verify. */ - cons = intf->req_cons; - prod = intf->req_prod; - mb(); - if (!xb_check_indexes(cons, prod)) { - intf->req_cons = intf->req_prod = 0; - return (EIO); - } - - dst = xb_get_output_chunk(cons, prod, intf->req, &avail); - if (avail == 0) - continue; - if (avail > len) - avail = len; - mb(); - - memcpy(dst, data, avail); - data += avail; - len -= avail; - - /* Other side must not see new header until data is there. */ - wmb(); - intf->req_prod += avail; - - /* This implies mb() before other side sees interrupt. */ - notify_remote_via_evtchn(xen_store_evtchn); - } - - return (0); -} - -int -xb_read(void *tdata, unsigned len, struct lock_object *lock) -{ - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - XENSTORE_RING_IDX cons, prod; - char *data = (char *)tdata; - int error; - - while (len != 0) { - unsigned int avail; - const char *src; - - while (intf->rsp_cons == intf->rsp_prod) { - error = _sleep(intf, lock, - PCATCH, "xbread", hz/10); - if (error && error != EWOULDBLOCK) - return (error); - } - - /* Read indexes, then verify. */ - cons = intf->rsp_cons; - prod = intf->rsp_prod; - if (!xb_check_indexes(cons, prod)) { - intf->rsp_cons = intf->rsp_prod = 0; - return (EIO); - } - - src = xb_get_input_chunk(cons, prod, intf->rsp, &avail); - if (avail == 0) - continue; - if (avail > len) - avail = len; - - /* We must read header before we read data. */ - rmb(); - - memcpy(data, src, avail); - data += avail; - len -= avail; - - /* Other side must not see free space until we've copied out */ - mb(); - intf->rsp_cons += avail; - - /* Implies mb(): they will see new header. */ - notify_remote_via_evtchn(xen_store_evtchn); - } - - return (0); -} - -/* Set up interrupt handler off store event channel. */ -int -xb_init_comms(void) -{ - struct xenstore_domain_interface *intf = xenstore_domain_interface(); - int error; - - if (intf->rsp_prod != intf->rsp_cons) { - log(LOG_WARNING, "XENBUS response ring is not quiescent " - "(%08x:%08x): fixing up\n", - intf->rsp_cons, intf->rsp_prod); - intf->rsp_cons = intf->rsp_prod; - } - - if (xenstore_irq) - unbind_from_irqhandler(xenstore_irq); - - error = bind_caller_port_to_irqhandler( - xen_store_evtchn, "xenbus", - xb_intr, NULL, INTR_TYPE_NET, &xenstore_irq); - if (error) { - log(LOG_WARNING, "XENBUS request irq failed %i\n", error); - return (error); - } - - return (0); -} diff --git a/sys/xen/xenbus/xenbus_comms.h b/sys/xen/xenbus/xenbus_comms.h deleted file mode 100644 index fa4733109d9..00000000000 --- a/sys/xen/xenbus/xenbus_comms.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Private include for xenbus communications. - * - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * $FreeBSD$ - */ - -#ifndef _XENBUS_COMMS_H -#define _XENBUS_COMMS_H - -struct sx; -extern int xen_store_evtchn; -extern char *xen_store; - -int xs_init(void); -int xb_init_comms(void); - -/* Low level routines. */ -int xb_write(const void *data, unsigned len, struct lock_object *); -int xb_read(void *data, unsigned len, struct lock_object *); -extern int xenbus_running; - -char *kasprintf(const char *fmt, ...); - - -#endif /* _XENBUS_COMMS_H */ diff --git a/sys/xen/xenbus/xenbus_if.m b/sys/xen/xenbus/xenbus_if.m index 018a2bbf43b..d6714183178 100644 --- a/sys/xen/xenbus/xenbus_if.m +++ b/sys/xen/xenbus/xenbus_if.m @@ -31,7 +31,15 @@ INTERFACE xenbus; -METHOD int backend_changed { - device_t dev; - enum xenbus_state newstate; +/** + * \brief Callback triggered when the state of the otherend + * of a split device changes. + * + * \param _dev NewBus device_t for this XenBus device whose otherend's + * state has changed.. + * \param _newstate The new state of the otherend device. + */ +METHOD int otherend_changed { + device_t _dev; + enum xenbus_state _newstate; }; diff --git a/sys/xen/xenbus/xenbus_probe.c b/sys/xen/xenbus/xenbus_probe.c deleted file mode 100644 index b1e9a2108aa..00000000000 --- a/sys/xen/xenbus/xenbus_probe.c +++ /dev/null @@ -1,602 +0,0 @@ -/****************************************************************************** - * Talks to Xen Store to figure out what devices we have. - * - * Copyright (C) 2008 Doug Rabson - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * Copyright (C) 2005 Mike Wray, Hewlett-Packard - * Copyright (C) 2005 XenSource Ltd - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#if 0 -#define DPRINTK(fmt, args...) \ - printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTK(fmt, args...) ((void)0) -#endif - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -struct xenbus_softc { - struct xenbus_watch xs_devicewatch; - struct task xs_probechildren; - struct intr_config_hook xs_attachcb; - device_t xs_dev; -}; - -struct xenbus_device_ivars { - struct xenbus_watch xd_otherend_watch; /* must be first */ - struct sx xd_lock; - device_t xd_dev; - char *xd_node; /* node name in xenstore */ - char *xd_type; /* xen device type */ - enum xenbus_state xd_state; - int xd_otherend_id; - char *xd_otherend_path; -}; - -/* Simplified asprintf. */ -char * -kasprintf(const char *fmt, ...) -{ - va_list ap; - unsigned int len; - char *p, dummy[1]; - - va_start(ap, fmt); - /* FIXME: vsnprintf has a bug, NULL should work */ - len = vsnprintf(dummy, 0, fmt, ap); - va_end(ap); - - p = malloc(len + 1, M_DEVBUF, M_WAITOK); - va_start(ap, fmt); - vsprintf(p, fmt, ap); - va_end(ap); - return p; -} - -static void -xenbus_identify(driver_t *driver, device_t parent) -{ - - BUS_ADD_CHILD(parent, 0, "xenbus", 0); -} - -static int -xenbus_probe(device_t dev) -{ - int err = 0; - - DPRINTK(""); - - /* Initialize the interface to xenstore. */ - err = xs_init(); - if (err) { - log(LOG_WARNING, - "XENBUS: Error initializing xenstore comms: %i\n", err); - return (ENXIO); - } - err = gnttab_init(); - if (err) { - log(LOG_WARNING, - "XENBUS: Error initializing grant table: %i\n", err); - return (ENXIO); - } - device_set_desc(dev, "Xen Devices"); - - return (0); -} - -static enum xenbus_state -xenbus_otherend_state(struct xenbus_device_ivars *ivars) -{ - - return (xenbus_read_driver_state(ivars->xd_otherend_path)); -} - -static void -xenbus_backend_changed(struct xenbus_watch *watch, const char **vec, - unsigned int len) -{ - struct xenbus_device_ivars *ivars; - device_t dev; - enum xenbus_state newstate; - - ivars = (struct xenbus_device_ivars *) watch; - dev = ivars->xd_dev; - - if (!ivars->xd_otherend_path - || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH], - strlen(ivars->xd_otherend_path))) - return; - - newstate = xenbus_otherend_state(ivars); - XENBUS_BACKEND_CHANGED(dev, newstate); -} - -static int -xenbus_device_exists(device_t dev, const char *node) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count, result; - - if (device_get_children(dev, &kids, &count)) - return (FALSE); - - result = FALSE; - for (i = 0; i < count; i++) { - ivars = device_get_ivars(kids[i]); - if (!strcmp(ivars->xd_node, node)) { - result = TRUE; - break; - } - } - free(kids, M_TEMP); - - return (result); -} - -static int -xenbus_add_device(device_t dev, const char *bus, - const char *type, const char *id) -{ - device_t child; - struct xenbus_device_ivars *ivars; - enum xenbus_state state; - char *statepath; - int error; - - ivars = malloc(sizeof(struct xenbus_device_ivars), - M_DEVBUF, M_ZERO|M_WAITOK); - ivars->xd_node = kasprintf("%s/%s/%s", bus, type, id); - - if (xenbus_device_exists(dev, ivars->xd_node)) { - /* - * We are already tracking this node - */ - free(ivars->xd_node, M_DEVBUF); - free(ivars, M_DEVBUF); - return (0); - } - - state = xenbus_read_driver_state(ivars->xd_node); - - if (state != XenbusStateInitialising) { - /* - * Device is not new, so ignore it. This can - * happen if a device is going away after - * switching to Closed. - */ - free(ivars->xd_node, M_DEVBUF); - free(ivars, M_DEVBUF); - return (0); - } - - /* - * Find the backend details - */ - error = xenbus_gather(XBT_NIL, ivars->xd_node, - "backend-id", "%i", &ivars->xd_otherend_id, - "backend", NULL, &ivars->xd_otherend_path, - NULL); - if (error) - return (error); - - sx_init(&ivars->xd_lock, "xdlock"); - ivars->xd_type = strdup(type, M_DEVBUF); - ivars->xd_state = XenbusStateInitialising; - - statepath = malloc(strlen(ivars->xd_otherend_path) - + strlen("/state") + 1, M_DEVBUF, M_WAITOK); - sprintf(statepath, "%s/state", ivars->xd_otherend_path); - - ivars->xd_otherend_watch.node = statepath; - ivars->xd_otherend_watch.callback = xenbus_backend_changed; - - child = device_add_child(dev, NULL, -1); - ivars->xd_dev = child; - device_set_ivars(child, ivars); - - return (0); -} - -static int -xenbus_enumerate_type(device_t dev, const char *bus, const char *type) -{ - char **dir; - unsigned int i, count; - int error; - - error = xenbus_directory(XBT_NIL, bus, type, &count, &dir); - if (error) - return (error); - for (i = 0; i < count; i++) - xenbus_add_device(dev, bus, type, dir[i]); - - free(dir, M_DEVBUF); - - return (0); -} - -static int -xenbus_enumerate_bus(device_t dev, const char *bus) -{ - char **dir; - unsigned int i, count; - int error; - - error = xenbus_directory(XBT_NIL, bus, "", &count, &dir); - if (error) - return (error); - for (i = 0; i < count; i++) { - xenbus_enumerate_type(dev, bus, dir[i]); - } - free(dir, M_DEVBUF); - - return (0); -} - -static int -xenbus_probe_children(device_t dev) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count; - - /* - * Probe any new devices and register watches for any that - * attach successfully. Since part of the protocol which - * establishes a connection with the other end is interrupt - * driven, we sleep until the device reaches a stable state - * (closed or connected). - */ - if (device_get_children(dev, &kids, &count) == 0) { - for (i = 0; i < count; i++) { - if (device_get_state(kids[i]) != DS_NOTPRESENT) - continue; - - if (device_probe_and_attach(kids[i])) - continue; - ivars = device_get_ivars(kids[i]); - register_xenbus_watch( - &ivars->xd_otherend_watch); - sx_xlock(&ivars->xd_lock); - while (ivars->xd_state != XenbusStateClosed - && ivars->xd_state != XenbusStateConnected) - sx_sleep(&ivars->xd_state, &ivars->xd_lock, - 0, "xdattach", 0); - sx_xunlock(&ivars->xd_lock); - } - free(kids, M_TEMP); - } - - return (0); -} - -static void -xenbus_probe_children_cb(void *arg, int pending) -{ - device_t dev = (device_t) arg; - - xenbus_probe_children(dev); -} - -static void -xenbus_devices_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - struct xenbus_softc *sc = (struct xenbus_softc *) watch; - device_t dev = sc->xs_dev; - char *node, *bus, *type, *id, *p; - - node = strdup(vec[XS_WATCH_PATH], M_DEVBUF); - p = strchr(node, '/'); - if (!p) - goto out; - bus = node; - *p = 0; - type = p + 1; - - p = strchr(type, '/'); - if (!p) - goto out; - *p = 0; - id = p + 1; - - p = strchr(id, '/'); - if (p) - *p = 0; - - xenbus_add_device(dev, bus, type, id); - taskqueue_enqueue(taskqueue_thread, &sc->xs_probechildren); -out: - free(node, M_DEVBUF); -} - -static void -xenbus_attach_deferred(void *arg) -{ - device_t dev = (device_t) arg; - struct xenbus_softc *sc = device_get_softc(dev); - int error; - - error = xenbus_enumerate_bus(dev, "device"); - if (error) - return; - xenbus_probe_children(dev); - - sc->xs_dev = dev; - sc->xs_devicewatch.node = "device"; - sc->xs_devicewatch.callback = xenbus_devices_changed; - - TASK_INIT(&sc->xs_probechildren, 0, xenbus_probe_children_cb, dev); - - register_xenbus_watch(&sc->xs_devicewatch); - - config_intrhook_disestablish(&sc->xs_attachcb); -} - -static int -xenbus_attach(device_t dev) -{ - struct xenbus_softc *sc = device_get_softc(dev); - - sc->xs_attachcb.ich_func = xenbus_attach_deferred; - sc->xs_attachcb.ich_arg = dev; - config_intrhook_establish(&sc->xs_attachcb); - - return (0); -} - -static int -xenbus_suspend(device_t dev) -{ - int error; - - DPRINTK(""); - - error = bus_generic_suspend(dev); - if (error) - return (error); - - xs_suspend(); - - return (0); -} - -static int -xenbus_resume(device_t dev) -{ - device_t *kids; - struct xenbus_device_ivars *ivars; - int i, count, error; - char *statepath; - - xb_init_comms(); - xs_resume(); - - /* - * We must re-examine each device and find the new path for - * its backend. - */ - if (device_get_children(dev, &kids, &count) == 0) { - for (i = 0; i < count; i++) { - if (device_get_state(kids[i]) == DS_NOTPRESENT) - continue; - - ivars = device_get_ivars(kids[i]); - - unregister_xenbus_watch( - &ivars->xd_otherend_watch); - ivars->xd_state = XenbusStateInitialising; - - /* - * Find the new backend details and - * re-register our watch. - */ - free(ivars->xd_otherend_path, M_DEVBUF); - error = xenbus_gather(XBT_NIL, ivars->xd_node, - "backend-id", "%i", &ivars->xd_otherend_id, - "backend", NULL, &ivars->xd_otherend_path, - NULL); - if (error) - return (error); - - DEVICE_RESUME(kids[i]); - - statepath = malloc(strlen(ivars->xd_otherend_path) - + strlen("/state") + 1, M_DEVBUF, M_WAITOK); - sprintf(statepath, "%s/state", ivars->xd_otherend_path); - - free(ivars->xd_otherend_watch.node, M_DEVBUF); - ivars->xd_otherend_watch.node = statepath; - register_xenbus_watch( - &ivars->xd_otherend_watch); - -#if 0 - /* - * Can't do this yet since we are running in - * the xenwatch thread and if we sleep here, - * we will stop delivering watch notifications - * and the device will never come back online. - */ - sx_xlock(&ivars->xd_lock); - while (ivars->xd_state != XenbusStateClosed - && ivars->xd_state != XenbusStateConnected) - sx_sleep(&ivars->xd_state, &ivars->xd_lock, - 0, "xdresume", 0); - sx_xunlock(&ivars->xd_lock); -#endif - } - free(kids, M_TEMP); - } - - return (0); -} - -static int -xenbus_print_child(device_t dev, device_t child) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - int retval = 0; - - retval += bus_print_child_header(dev, child); - retval += printf(" at %s", ivars->xd_node); - retval += bus_print_child_footer(dev, child); - - return (retval); -} - -static int -xenbus_read_ivar(device_t dev, device_t child, int index, - uintptr_t * result) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - - switch (index) { - case XENBUS_IVAR_NODE: - *result = (uintptr_t) ivars->xd_node; - return (0); - - case XENBUS_IVAR_TYPE: - *result = (uintptr_t) ivars->xd_type; - return (0); - - case XENBUS_IVAR_STATE: - *result = (uintptr_t) ivars->xd_state; - return (0); - - case XENBUS_IVAR_OTHEREND_ID: - *result = (uintptr_t) ivars->xd_otherend_id; - return (0); - - case XENBUS_IVAR_OTHEREND_PATH: - *result = (uintptr_t) ivars->xd_otherend_path; - return (0); - } - - return (ENOENT); -} - -static int -xenbus_write_ivar(device_t dev, device_t child, int index, uintptr_t value) -{ - struct xenbus_device_ivars *ivars = device_get_ivars(child); - enum xenbus_state newstate; - int currstate; - int error; - - switch (index) { - case XENBUS_IVAR_STATE: - newstate = (enum xenbus_state) value; - sx_xlock(&ivars->xd_lock); - if (ivars->xd_state == newstate) - goto out; - - error = xenbus_scanf(XBT_NIL, ivars->xd_node, "state", - NULL, "%d", &currstate); - if (error) - goto out; - - error = xenbus_printf(XBT_NIL, ivars->xd_node, "state", - "%d", newstate); - if (error) { - if (newstate != XenbusStateClosing) /* Avoid looping */ - xenbus_dev_fatal(dev, error, "writing new state"); - goto out; - } - ivars->xd_state = newstate; - wakeup(&ivars->xd_state); - out: - sx_xunlock(&ivars->xd_lock); - return (0); - - case XENBUS_IVAR_NODE: - case XENBUS_IVAR_TYPE: - case XENBUS_IVAR_OTHEREND_ID: - case XENBUS_IVAR_OTHEREND_PATH: - /* - * These variables are read-only. - */ - return (EINVAL); - } - - return (ENOENT); -} - -SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); -SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xen_store_evtchn, 0, ""); -SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); - -static device_method_t xenbus_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, xenbus_identify), - DEVMETHOD(device_probe, xenbus_probe), - DEVMETHOD(device_attach, xenbus_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, xenbus_suspend), - DEVMETHOD(device_resume, xenbus_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, xenbus_print_child), - DEVMETHOD(bus_read_ivar, xenbus_read_ivar), - DEVMETHOD(bus_write_ivar, xenbus_write_ivar), - - { 0, 0 } -}; - -static char driver_name[] = "xenbus"; -static driver_t xenbus_driver = { - driver_name, - xenbus_methods, - sizeof(struct xenbus_softc), -}; -devclass_t xenbus_devclass; - -#ifdef XENHVM -DRIVER_MODULE(xenbus, xenpci, xenbus_driver, xenbus_devclass, 0, 0); -#else -DRIVER_MODULE(xenbus, nexus, xenbus_driver, xenbus_devclass, 0, 0); -#endif diff --git a/sys/xen/xenbus/xenbus_probe_backend.c b/sys/xen/xenbus/xenbus_probe_backend.c deleted file mode 100644 index 20cc49f8229..00000000000 --- a/sys/xen/xenbus/xenbus_probe_backend.c +++ /dev/null @@ -1,308 +0,0 @@ -/****************************************************************************** - * Talks to Xen Store to figure out what devices we have (backend half). - * - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * Copyright (C) 2005 Mike Wray, Hewlett-Packard - * Copyright (C) 2005, 2006 XenSource Ltd - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation; or, when distributed - * separately from the Linux kernel or incorporated into other - * software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#if 0 -#define DPRINTK(fmt, args...) \ - printf("xenbus_probe (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) -#else -#define DPRINTK(fmt, args...) ((void)0) -#endif - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#define BUG_ON PANIC_IF -#define semaphore sema -#define rw_semaphore sema -#define DEFINE_SPINLOCK(lock) struct mtx lock -#define DECLARE_MUTEX(lock) struct sema lock -#define u32 uint32_t -#define list_del(head, ent) TAILQ_REMOVE(head, ent, list) -#define simple_strtoul strtoul -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -#define list_empty TAILQ_EMPTY - -extern struct xendev_list_head xenbus_device_backend_list; -#if 0 -static int xenbus_uevent_backend(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size); -#endif -static int xenbus_probe_backend(const char *type, const char *domid); - -static int read_frontend_details(struct xenbus_device *xendev) -{ - return read_otherend_details(xendev, "frontend-id", "frontend"); -} - -/* backend/// => -- */ -static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) -{ - int domid, err; - const char *devid, *type, *frontend; - unsigned int typelen; - - type = strchr(nodename, '/'); - if (!type) - return -EINVAL; - type++; - typelen = strcspn(type, "/"); - if (!typelen || type[typelen] != '/') - return -EINVAL; - - devid = strrchr(nodename, '/') + 1; - - err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid, - "frontend", NULL, &frontend, - NULL); - if (err) - return err; - if (strlen(frontend) == 0) - err = -ERANGE; - if (!err && !xenbus_exists(XBT_NIL, frontend, "")) - err = -ENOENT; - kfree(frontend); - - if (err) - return err; - - if (snprintf(bus_id, BUS_ID_SIZE, - "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE) - return -ENOSPC; - return 0; -} - -static struct xen_bus_type xenbus_backend = { - .root = "backend", - .levels = 3, /* backend/type// */ - .get_bus_id = backend_bus_id, - .probe = xenbus_probe_backend, - .bus = &xenbus_device_backend_list, - -#if 0 - .error = -ENODEV, - .bus = { - .name = "xen-backend", - .match = xenbus_match, - .probe = xenbus_dev_probe, - .remove = xenbus_dev_remove, -// .shutdown = xenbus_dev_shutdown, - .uevent = xenbus_uevent_backend, - }, - .dev = { - .bus_id = "xen-backend", - }, -#endif -}; - -#if 0 -static int xenbus_uevent_backend(struct device *dev, char **envp, - int num_envp, char *buffer, int buffer_size) -{ - struct xenbus_device *xdev; - struct xenbus_driver *drv; - int i = 0; - int length = 0; - - DPRINTK(""); - - if (dev == NULL) - return -ENODEV; - - xdev = to_xenbus_device(dev); - if (xdev == NULL) - return -ENODEV; -2 - /* stuff we want to pass to /sbin/hotplug */ - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "XENBUS_TYPE=%s", xdev->devicetype); - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "XENBUS_PATH=%s", xdev->nodename); - - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "XENBUS_BASE_PATH=%s", xenbus_backend.root); - - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - - if (dev->driver) { - drv = to_xenbus_driver(dev->driver); - if (drv && drv->uevent) - return drv->uevent(xdev, envp, num_envp, buffer, - buffer_size); - } - - return 0; -} -#endif - -int xenbus_register_backend(struct xenbus_driver *drv) -{ - drv->read_otherend_details = read_frontend_details; - - return xenbus_register_driver_common(drv, &xenbus_backend); -} - -/* backend/// */ -static int xenbus_probe_backend_unit(const char *dir, - const char *type, - const char *name) -{ - char *nodename; - int err; - - nodename = kasprintf("%s/%s", dir, name); - if (!nodename) - return -ENOMEM; - - DPRINTK("%s\n", nodename); - - err = xenbus_probe_node(&xenbus_backend, type, nodename); - kfree(nodename); - return err; -} - -/* backend// */ -static int xenbus_probe_backend(const char *type, const char *domid) -{ - char *nodename; - int err = 0; - char **dir; - unsigned int i, dir_n = 0; - - DPRINTK(""); - - nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid); - if (!nodename) - return -ENOMEM; - - dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n); - if (IS_ERR(dir)) { - kfree(nodename); - return PTR_ERR(dir); - } - - for (i = 0; i < dir_n; i++) { - err = xenbus_probe_backend_unit(nodename, type, dir[i]); - if (err) - break; - } - kfree(dir); - kfree(nodename); - return err; -} - -static void backend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) -{ - DPRINTK(""); - - dev_changed(vec[XS_WATCH_PATH], &xenbus_backend); -} - -static struct xenbus_watch be_watch = { - .node = "backend", - .callback = backend_changed, -}; -#if 0 -void xenbus_backend_suspend(int (*fn)(struct device *, void *)) -{ - DPRINTK(""); - if (!xenbus_backend.error) - bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); -} - -void xenbus_backend_resume(int (*fn)(struct device *, void *)) -{ - DPRINTK(""); - if (!xenbus_backend.error) - bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn); -} -#endif -void xenbus_backend_probe_and_watch(void) -{ - xenbus_probe_devices(&xenbus_backend); - register_xenbus_watch(&be_watch); -} - -#if 0 -void xenbus_backend_bus_register(void) -{ - xenbus_backend.error = bus_register(&xenbus_backend.bus); - if (xenbus_backend.error) - log(LOG_WARNING, - "XENBUS: Error registering backend bus: %i\n", - xenbus_backend.error); -} - -void xenbus_backend_device_register(void) -{ - if (xenbus_backend.error) - return; - - xenbus_backend.error = device_register(&xenbus_backend.dev); - if (xenbus_backend.error) { - bus_unregister(&xenbus_backend.bus); - log(LOG_WARNING, - "XENBUS: Error registering backend device: %i\n", - xenbus_backend.error); - } -} -#endif diff --git a/sys/xen/xenbus/xenbus_xs.c b/sys/xen/xenbus/xenbus_xs.c deleted file mode 100644 index 93122553e0c..00000000000 --- a/sys/xen/xenbus/xenbus_xs.c +++ /dev/null @@ -1,935 +0,0 @@ -/****************************************************************************** - * xenbus_xs.c - * - * This is the kernel equivalent of the "xs" library. We don't need everything - * and we use xenbus_comms for communication. - * - * Copyright (C) 2005 Rusty Russell, IBM Corporation - * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this source file (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, modify, - * merge, publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -static int xs_process_msg(enum xsd_sockmsg_type *type); - -int xenwatch_running = 0; -int xenbus_running = 0; -int xen_store_evtchn; - -struct xs_stored_msg { - TAILQ_ENTRY(xs_stored_msg) list; - - struct xsd_sockmsg hdr; - - union { - /* Queued replies. */ - struct { - char *body; - } reply; - - /* Queued watch events. */ - struct { - struct xenbus_watch *handle; - char **vec; - unsigned int vec_size; - } watch; - } u; -}; - -struct xs_handle { - /* A list of replies. Currently only one will ever be outstanding. */ - TAILQ_HEAD(xs_handle_list, xs_stored_msg) reply_list; - struct mtx reply_lock; - int reply_waitq; - - /* One request at a time. */ - struct sx request_mutex; - - /* Protect transactions against save/restore. */ - struct sx suspend_mutex; -}; - -static struct xs_handle xs_state; - -/* List of registered watches, and a lock to protect it. */ -static LIST_HEAD(watch_list_head, xenbus_watch) watches; -static struct mtx watches_lock; -/* List of pending watch callback events, and a lock to protect it. */ -static TAILQ_HEAD(event_list_head, xs_stored_msg) watch_events; -static struct mtx watch_events_lock; - -/* - * Details of the xenwatch callback kernel thread. The thread waits on the - * watch_events_waitq for work to do (queued on watch_events list). When it - * wakes up it acquires the xenwatch_mutex before reading the list and - * carrying out work. - */ -static pid_t xenwatch_pid; -struct sx xenwatch_mutex; -static int watch_events_waitq; - -#define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0])) - -static int -xs_get_error(const char *errorstring) -{ - unsigned int i; - - for (i = 0; i < xsd_error_count; i++) { - if (!strcmp(errorstring, xsd_errors[i].errstring)) - return (xsd_errors[i].errnum); - } - log(LOG_WARNING, "XENBUS xen store gave: unknown error %s", - errorstring); - return (EINVAL); -} - -extern void kdb_backtrace(void); - -static int -xs_read_reply(enum xsd_sockmsg_type *type, unsigned int *len, void **result) -{ - struct xs_stored_msg *msg; - char *body; - int error; - - mtx_lock(&xs_state.reply_lock); - - while (TAILQ_EMPTY(&xs_state.reply_list)) { - while (TAILQ_EMPTY(&xs_state.reply_list)) { - error = mtx_sleep(&xs_state.reply_waitq, - &xs_state.reply_lock, - PCATCH, "xswait", hz/10); - if (error && error != EWOULDBLOCK) { - mtx_unlock(&xs_state.reply_lock); - return (error); - } - } - } - - msg = TAILQ_FIRST(&xs_state.reply_list); - TAILQ_REMOVE(&xs_state.reply_list, msg, list); - - mtx_unlock(&xs_state.reply_lock); - - *type = msg->hdr.type; - if (len) - *len = msg->hdr.len; - body = msg->u.reply.body; - - free(msg, M_DEVBUF); - *result = body; - return (0); -} - -#if 0 -/* Emergency write. UNUSED*/ -void xenbus_debug_write(const char *str, unsigned int count) -{ - struct xsd_sockmsg msg = { 0 }; - - msg.type = XS_DEBUG; - msg.len = sizeof("print") + count + 1; - - sx_xlock(&xs_state.request_mutex); - xb_write(&msg, sizeof(msg)); - xb_write("print", sizeof("print")); - xb_write(str, count); - xb_write("", 1); - sx_xunlock(&xs_state.request_mutex); -} - -#endif - -int -xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result) -{ - struct xsd_sockmsg req_msg = *msg; - int error; - - if (req_msg.type == XS_TRANSACTION_START) - sx_slock(&xs_state.suspend_mutex); - - sx_xlock(&xs_state.request_mutex); - - error = xb_write(msg, sizeof(*msg) + msg->len, - &xs_state.request_mutex.lock_object); - if (error) { - msg->type = XS_ERROR; - } else { - error = xs_read_reply(&msg->type, &msg->len, result); - } - - sx_xunlock(&xs_state.request_mutex); - - if ((msg->type == XS_TRANSACTION_END) || - ((req_msg.type == XS_TRANSACTION_START) && - (msg->type == XS_ERROR))) - sx_sunlock(&xs_state.suspend_mutex); - - return (error); -} - -/* - * Send message to xs. The reply is returned in *result and should be - * fred with free(*result, M_DEVBUF). Return zero on success or an - * error code on failure. - */ -static int -xs_talkv(struct xenbus_transaction t, enum xsd_sockmsg_type type, - const struct iovec *iovec, unsigned int num_vecs, - unsigned int *len, void **result) -{ - struct xsd_sockmsg msg; - void *ret = NULL; - unsigned int i; - int error; - - msg.tx_id = t.id; - msg.req_id = 0; - msg.type = type; - msg.len = 0; - for (i = 0; i < num_vecs; i++) - msg.len += iovec[i].iov_len; - - sx_xlock(&xs_state.request_mutex); - - error = xb_write(&msg, sizeof(msg), - &xs_state.request_mutex.lock_object); - if (error) { - sx_xunlock(&xs_state.request_mutex); - printf("xs_talkv failed %d\n", error); - return (error); - } - - for (i = 0; i < num_vecs; i++) { - error = xb_write(iovec[i].iov_base, iovec[i].iov_len, - &xs_state.request_mutex.lock_object); - if (error) { - sx_xunlock(&xs_state.request_mutex); - printf("xs_talkv failed %d\n", error); - return (error); - } - } - - error = xs_read_reply(&msg.type, len, &ret); - - sx_xunlock(&xs_state.request_mutex); - - if (error) - return (error); - - if (msg.type == XS_ERROR) { - error = xs_get_error(ret); - free(ret, M_DEVBUF); - return (error); - } - -#if 0 - if ((xenwatch_running == 0) && (xenwatch_inline == 0)) { - xenwatch_inline = 1; - while (!TAILQ_EMPTY(&watch_events) - && xenwatch_running == 0) { - - struct xs_stored_msg *wmsg = TAILQ_FIRST(&watch_events); - TAILQ_REMOVE(&watch_events, wmsg, list); - - wmsg->u.watch.handle->callback( - wmsg->u.watch.handle, - (const char **)wmsg->u.watch.vec, - wmsg->u.watch.vec_size); - free(wmsg->u.watch.vec, M_DEVBUF); - free(wmsg, M_DEVBUF); - } - xenwatch_inline = 0; - } -#endif - KASSERT(msg.type == type, ("bad xenstore message type")); - - if (result) - *result = ret; - else - free(ret, M_DEVBUF); - - return (0); -} - -/* Simplified version of xs_talkv: single message. */ -static int -xs_single(struct xenbus_transaction t, enum xsd_sockmsg_type type, - const char *string, unsigned int *len, void **result) -{ - struct iovec iovec; - - iovec.iov_base = (void *)(uintptr_t) string; - iovec.iov_len = strlen(string) + 1; - - return (xs_talkv(t, type, &iovec, 1, len, result)); -} - -static unsigned int -count_strings(const char *strings, unsigned int len) -{ - unsigned int num; - const char *p; - - for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) - num++; - - return num; -} - -/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ -static char * -join(const char *dir, const char *name) -{ - char *buffer; - - buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1, - M_DEVBUF, M_WAITOK); - - strcpy(buffer, dir); - if (strcmp(name, "")) { - strcat(buffer, "/"); - strcat(buffer, name); - } - - return (buffer); -} - -static char ** -split(char *strings, unsigned int len, unsigned int *num) -{ - char *p, **ret; - - /* Count the strings. */ - *num = count_strings(strings, len) + 1; - - /* Transfer to one big alloc for easy freeing. */ - ret = malloc(*num * sizeof(char *) + len, M_DEVBUF, M_WAITOK); - memcpy(&ret[*num], strings, len); - free(strings, M_DEVBUF); - - strings = (char *)&ret[*num]; - for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) - ret[(*num)++] = p; - - ret[*num] = strings + len; - - return ret; -} - -/* - * Return the contents of a directory in *result which should be freed - * with free(*result, M_DEVBUF). - */ -int -xenbus_directory(struct xenbus_transaction t, const char *dir, - const char *node, unsigned int *num, char ***result) -{ - char *strings, *path; - unsigned int len = 0; - int error; - - path = join(dir, node); - error = xs_single(t, XS_DIRECTORY, path, &len, (void **) &strings); - free(path, M_DEVBUF); - if (error) - return (error); - - *result = split(strings, len, num); - return (0); -} - -/* - * Check if a path exists. Return 1 if it does. - */ -int -xenbus_exists(struct xenbus_transaction t, const char *dir, const char *node) -{ - char **d; - int error, dir_n; - - error = xenbus_directory(t, dir, node, &dir_n, &d); - if (error) - return (0); - free(d, M_DEVBUF); - return (1); -} - -/* - * Get the value of a single file. Returns the contents in *result - * which should be freed with free(*result, M_DEVBUF) after use. - * The length of the value in bytes is returned in *len. - */ -int -xenbus_read(struct xenbus_transaction t, const char *dir, const char *node, - unsigned int *len, void **result) -{ - char *path; - void *ret; - int error; - - path = join(dir, node); - error = xs_single(t, XS_READ, path, len, &ret); - free(path, M_DEVBUF); - if (error) - return (error); - *result = ret; - return (0); -} - -/* - * Write the value of a single file. Returns error on failure. - */ -int -xenbus_write(struct xenbus_transaction t, const char *dir, const char *node, - const char *string) -{ - char *path; - struct iovec iovec[2]; - int error; - - path = join(dir, node); - - iovec[0].iov_base = (void *)(uintptr_t) path; - iovec[0].iov_len = strlen(path) + 1; - iovec[1].iov_base = (void *)(uintptr_t) string; - iovec[1].iov_len = strlen(string); - - error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); - free(path, M_DEVBUF); - - return (error); -} - -/* - * Create a new directory. - */ -int -xenbus_mkdir(struct xenbus_transaction t, const char *dir, const char *node) -{ - char *path; - int ret; - - path = join(dir, node); - ret = xs_single(t, XS_MKDIR, path, NULL, NULL); - free(path, M_DEVBUF); - - return (ret); -} - -/* - * Destroy a file or directory (directories must be empty). - */ -int -xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) -{ - char *path; - int ret; - - path = join(dir, node); - ret = xs_single(t, XS_RM, path, NULL, NULL); - free(path, M_DEVBUF); - - return (ret); -} - -/* - * Start a transaction: changes by others will not be seen during this - * transaction, and changes will not be visible to others until end. - */ -int -xenbus_transaction_start(struct xenbus_transaction *t) -{ - char *id_str; - int error; - - sx_slock(&xs_state.suspend_mutex); - error = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL, - (void **) &id_str); - if (error) { - sx_sunlock(&xs_state.suspend_mutex); - return (error); - } - - t->id = strtoul(id_str, NULL, 0); - free(id_str, M_DEVBUF); - - return (0); -} - -/* - * End a transaction. If abandon is true, transaction is discarded - * instead of committed. - */ -int xenbus_transaction_end(struct xenbus_transaction t, int abort) -{ - char abortstr[2]; - int error; - - if (abort) - strcpy(abortstr, "F"); - else - strcpy(abortstr, "T"); - - error = xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL); - - sx_sunlock(&xs_state.suspend_mutex); - - return (error); -} - -/* Single read and scanf: returns zero or errno. */ -int -xenbus_scanf(struct xenbus_transaction t, - const char *dir, const char *node, int *scancountp, const char *fmt, ...) -{ - va_list ap; - int error, ns; - char *val; - - error = xenbus_read(t, dir, node, NULL, (void **) &val); - if (error) - return (error); - - va_start(ap, fmt); - ns = vsscanf(val, fmt, ap); - va_end(ap); - free(val, M_DEVBUF); - /* Distinctive errno. */ - if (ns == 0) - return (ERANGE); - if (scancountp) - *scancountp = ns; - return (0); -} - -/* Single printf and write: returns zero or errno. */ -int -xenbus_printf(struct xenbus_transaction t, - const char *dir, const char *node, const char *fmt, ...) -{ - va_list ap; - int error, ret; -#define PRINTF_BUFFER_SIZE 4096 - char *printf_buffer; - - printf_buffer = malloc(PRINTF_BUFFER_SIZE, M_DEVBUF, M_WAITOK); - - va_start(ap, fmt); - ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); - va_end(ap); - - KASSERT(ret <= PRINTF_BUFFER_SIZE-1, ("xenbus_printf: message too large")); - error = xenbus_write(t, dir, node, printf_buffer); - - free(printf_buffer, M_DEVBUF); - - return (error); -} - -/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ -int -xenbus_gather(struct xenbus_transaction t, const char *dir, ...) -{ - va_list ap; - const char *name; - int error, i; - - for (i = 0; i < 10000; i++) - HYPERVISOR_yield(); - - va_start(ap, dir); - error = 0; - while (error == 0 && (name = va_arg(ap, char *)) != NULL) { - const char *fmt = va_arg(ap, char *); - void *result = va_arg(ap, void *); - char *p; - - error = xenbus_read(t, dir, name, NULL, (void **) &p); - if (error) - break; - - if (fmt) { - if (sscanf(p, fmt, result) == 0) - error = EINVAL; - free(p, M_DEVBUF); - } else - *(char **)result = p; - } - va_end(ap); - - return (error); -} - -static int -xs_watch(const char *path, const char *token) -{ - struct iovec iov[2]; - - iov[0].iov_base = (void *)(uintptr_t) path; - iov[0].iov_len = strlen(path) + 1; - iov[1].iov_base = (void *)(uintptr_t) token; - iov[1].iov_len = strlen(token) + 1; - - return (xs_talkv(XBT_NIL, XS_WATCH, iov, 2, NULL, NULL)); -} - -static int -xs_unwatch(const char *path, const char *token) -{ - struct iovec iov[2]; - - iov[0].iov_base = (void *)(uintptr_t) path; - iov[0].iov_len = strlen(path) + 1; - iov[1].iov_base = (void *)(uintptr_t) token; - iov[1].iov_len = strlen(token) + 1; - - return (xs_talkv(XBT_NIL, XS_UNWATCH, iov, 2, NULL, NULL)); -} - -static struct xenbus_watch * -find_watch(const char *token) -{ - struct xenbus_watch *i, *cmp; - - cmp = (void *)strtoul(token, NULL, 16); - - LIST_FOREACH(i, &watches, list) - if (i == cmp) - return (i); - - return (NULL); -} - -/* Register callback to watch this node. */ -int -register_xenbus_watch(struct xenbus_watch *watch) -{ - /* Pointer in ascii is the token. */ - char token[sizeof(watch) * 2 + 1]; - int error; - - sprintf(token, "%lX", (long)watch); - - sx_slock(&xs_state.suspend_mutex); - - mtx_lock(&watches_lock); - KASSERT(find_watch(token) == NULL, ("watch already registered")); - LIST_INSERT_HEAD(&watches, watch, list); - mtx_unlock(&watches_lock); - - error = xs_watch(watch->node, token); - - /* Ignore errors due to multiple registration. */ - if (error == EEXIST) { - mtx_lock(&watches_lock); - LIST_REMOVE(watch, list); - mtx_unlock(&watches_lock); - } - - sx_sunlock(&xs_state.suspend_mutex); - - return (error); -} - -void -unregister_xenbus_watch(struct xenbus_watch *watch) -{ - struct xs_stored_msg *msg, *tmp; - char token[sizeof(watch) * 2 + 1]; - int error; - - sprintf(token, "%lX", (long)watch); - - sx_slock(&xs_state.suspend_mutex); - - mtx_lock(&watches_lock); - KASSERT(find_watch(token), ("watch not registered")); - LIST_REMOVE(watch, list); - mtx_unlock(&watches_lock); - - error = xs_unwatch(watch->node, token); - if (error) - log(LOG_WARNING, "XENBUS Failed to release watch %s: %i\n", - watch->node, error); - - sx_sunlock(&xs_state.suspend_mutex); - - /* Cancel pending watch events. */ - mtx_lock(&watch_events_lock); - TAILQ_FOREACH_SAFE(msg, &watch_events, list, tmp) { - if (msg->u.watch.handle != watch) - continue; - TAILQ_REMOVE(&watch_events, msg, list); - free(msg->u.watch.vec, M_DEVBUF); - free(msg, M_DEVBUF); - } - mtx_unlock(&watch_events_lock); - - /* Flush any currently-executing callback, unless we are it. :-) */ - if (curproc->p_pid != xenwatch_pid) { - sx_xlock(&xenwatch_mutex); - sx_xunlock(&xenwatch_mutex); - } -} - -void -xs_suspend(void) -{ - - sx_xlock(&xs_state.suspend_mutex); - sx_xlock(&xs_state.request_mutex); -} - -void -xs_resume(void) -{ - struct xenbus_watch *watch; - char token[sizeof(watch) * 2 + 1]; - - sx_xunlock(&xs_state.request_mutex); - - /* No need for watches_lock: the suspend_mutex is sufficient. */ - LIST_FOREACH(watch, &watches, list) { - sprintf(token, "%lX", (long)watch); - xs_watch(watch->node, token); - } - - sx_xunlock(&xs_state.suspend_mutex); -} - -static void -xenwatch_thread(void *unused) -{ - struct xs_stored_msg *msg; - - for (;;) { - - mtx_lock(&watch_events_lock); - while (TAILQ_EMPTY(&watch_events)) - mtx_sleep(&watch_events_waitq, - &watch_events_lock, - PWAIT | PCATCH, "waitev", hz/10); - - mtx_unlock(&watch_events_lock); - sx_xlock(&xenwatch_mutex); - - mtx_lock(&watch_events_lock); - msg = TAILQ_FIRST(&watch_events); - if (msg) - TAILQ_REMOVE(&watch_events, msg, list); - mtx_unlock(&watch_events_lock); - - if (msg != NULL) { - /* - * XXX There are messages coming in with a NULL callback. - * XXX This deserves further investigation; the workaround - * XXX here simply prevents the kernel from panic'ing - * XXX on startup. - */ - if (msg->u.watch.handle->callback != NULL) - msg->u.watch.handle->callback( - msg->u.watch.handle, - (const char **)msg->u.watch.vec, - msg->u.watch.vec_size); - free(msg->u.watch.vec, M_DEVBUF); - free(msg, M_DEVBUF); - } - - sx_xunlock(&xenwatch_mutex); - } -} - -static int -xs_process_msg(enum xsd_sockmsg_type *type) -{ - struct xs_stored_msg *msg; - char *body; - int error; - - msg = malloc(sizeof(*msg), M_DEVBUF, M_WAITOK); - mtx_lock(&xs_state.reply_lock); - error = xb_read(&msg->hdr, sizeof(msg->hdr), - &xs_state.reply_lock.lock_object); - mtx_unlock(&xs_state.reply_lock); - if (error) { - free(msg, M_DEVBUF); - return (error); - } - - body = malloc(msg->hdr.len + 1, M_DEVBUF, M_WAITOK); - mtx_lock(&xs_state.reply_lock); - error = xb_read(body, msg->hdr.len, - &xs_state.reply_lock.lock_object); - mtx_unlock(&xs_state.reply_lock); - if (error) { - free(body, M_DEVBUF); - free(msg, M_DEVBUF); - return (error); - } - body[msg->hdr.len] = '\0'; - - *type = msg->hdr.type; - if (msg->hdr.type == XS_WATCH_EVENT) { - msg->u.watch.vec = split(body, msg->hdr.len, - &msg->u.watch.vec_size); - - mtx_lock(&watches_lock); - msg->u.watch.handle = find_watch( - msg->u.watch.vec[XS_WATCH_TOKEN]); - if (msg->u.watch.handle != NULL) { - mtx_lock(&watch_events_lock); - TAILQ_INSERT_TAIL(&watch_events, msg, list); - wakeup(&watch_events_waitq); - mtx_unlock(&watch_events_lock); - } else { - free(msg->u.watch.vec, M_DEVBUF); - free(msg, M_DEVBUF); - } - mtx_unlock(&watches_lock); - } else { - msg->u.reply.body = body; - mtx_lock(&xs_state.reply_lock); - TAILQ_INSERT_TAIL(&xs_state.reply_list, msg, list); - wakeup(&xs_state.reply_waitq); - mtx_unlock(&xs_state.reply_lock); - } - - return 0; -} - -static void -xenbus_thread(void *unused) -{ - int error; - enum xsd_sockmsg_type type; - xenbus_running = 1; - - for (;;) { - error = xs_process_msg(&type); - if (error) - printf("XENBUS error %d while reading message\n", - error); - } -} - -#ifdef XENHVM -static unsigned long xen_store_mfn; -char *xen_store; - -static inline unsigned long -hvm_get_parameter(int index) -{ - struct xen_hvm_param xhv; - int error; - - xhv.domid = DOMID_SELF; - xhv.index = index; - error = HYPERVISOR_hvm_op(HVMOP_get_param, &xhv); - if (error) { - printf("hvm_get_parameter: failed to get %d, error %d\n", - index, error); - return (0); - } - return (xhv.value); -} - -#endif - -int -xs_init(void) -{ - int error; - struct proc *p; - -#ifdef XENHVM - xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); - xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); - xen_store = pmap_mapdev(xen_store_mfn * PAGE_SIZE, PAGE_SIZE); -#else - xen_store_evtchn = xen_start_info->store_evtchn; -#endif - - TAILQ_INIT(&xs_state.reply_list); - TAILQ_INIT(&watch_events); - sx_init(&xenwatch_mutex, "xenwatch"); - - - mtx_init(&xs_state.reply_lock, "state reply", NULL, MTX_DEF); - sx_init(&xs_state.request_mutex, "xenstore request"); - sx_init(&xs_state.suspend_mutex, "xenstore suspend"); - - -#if 0 - mtx_init(&xs_state.suspend_mutex, "xenstore suspend", NULL, MTX_DEF); - sema_init(&xs_state.request_mutex, 1, "xenstore request"); - sema_init(&xenwatch_mutex, 1, "xenwatch"); -#endif - mtx_init(&watches_lock, "watches", NULL, MTX_DEF); - mtx_init(&watch_events_lock, "watch events", NULL, MTX_DEF); - - /* Initialize the shared memory rings to talk to xenstored */ - error = xb_init_comms(); - if (error) - return (error); - - xenwatch_running = 1; - error = kproc_create(xenwatch_thread, NULL, &p, - RFHIGHPID, 0, "xenwatch"); - if (error) - return (error); - xenwatch_pid = p->p_pid; - - error = kproc_create(xenbus_thread, NULL, NULL, - RFHIGHPID, 0, "xenbus"); - - return (error); -} diff --git a/sys/xen/xenbus/xenbusb.c b/sys/xen/xenbus/xenbusb.c new file mode 100644 index 00000000000..49facb6ddcc --- /dev/null +++ b/sys/xen/xenbus/xenbusb.c @@ -0,0 +1,878 @@ +/****************************************************************************** + * Copyright (C) 2010 Spectra Logic Corporation + * Copyright (C) 2008 Doug Rabson + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005 XenSource Ltd + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * \file xenbusb.c + * + * \brief Shared support functions for managing the NewBus busses that contain + * Xen front and back end device instances. + * + * The NewBus implementation of XenBus attaches a xenbusb_front and xenbusb_back + * child bus to the xenstore device. This strategy allows the small differences + * in the handling of XenBus operations for front and back devices to be handled + * as overrides in xenbusb_front/back.c. Front and back specific device + * classes are also provided so device drivers can register for the devices they + * can handle without the need to filter within their probe routines. The + * net result is a device hierarchy that might look like this: + * + * xenstore0/ + * xenbusb_front0/ + * xn0 + * xbd0 + * xbd1 + * xenbusb_back0/ + * xbbd0 + * xnb0 + * xnb1 + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +/*------------------------- Private Functions --------------------------------*/ +/** + * \brief Deallocate XenBus device instance variables. + * + * \param ivars The instance variable block to free. + */ +static void +xenbusb_free_child_ivars(struct xenbus_device_ivars *ivars) +{ + if (ivars->xd_otherend_watch.node != NULL) { + xs_unregister_watch(&ivars->xd_otherend_watch); + free(ivars->xd_otherend_watch.node, M_XENBUS); + ivars->xd_otherend_watch.node = NULL; + } + + if (ivars->xd_node != NULL) { + free(ivars->xd_node, M_XENBUS); + ivars->xd_node = NULL; + } + + if (ivars->xd_type != NULL) { + free(ivars->xd_type, M_XENBUS); + ivars->xd_type = NULL; + } + + if (ivars->xd_otherend_path != NULL) { + free(ivars->xd_otherend_path, M_XENBUS); + ivars->xd_otherend_path = NULL; + } + + free(ivars, M_XENBUS); +} + +/** + * XenBus watch callback registered against the "state" XenStore + * node of the other-end of a split device connection. + * + * This callback is invoked whenever the state of a device instance's + * peer changes. + * + * \param watch The xs_watch object used to register this callback + * function. + * \param vec An array of pointers to NUL terminated strings containing + * watch event data. The vector should be indexed via the + * xs_watch_type enum in xs_wire.h. + * \param vec_size The number of elements in vec. + * + * \return The device_t of the found device if any, or NULL. + * + * \note device_t is a pointer type, so it can be compared against + * NULL for validity. + */ +static void +xenbusb_otherend_changed(struct xs_watch *watch, const char **vec, + unsigned int vec_size __unused) +{ + struct xenbus_device_ivars *ivars; + device_t dev; + enum xenbus_state newstate; + + ivars = (struct xenbus_device_ivars *) watch; + dev = ivars->xd_dev; + + if (!ivars->xd_otherend_path + || strncmp(ivars->xd_otherend_path, vec[XS_WATCH_PATH], + strlen(ivars->xd_otherend_path))) + return; + + newstate = xenbus_read_driver_state(ivars->xd_otherend_path); + XENBUS_OTHEREND_CHANGED(dev, newstate); +} + +/** + * Search our internal record of configured devices (not the XenStore) + * to determine if the XenBus device indicated by \a node is known to + * the system. + * + * \param dev The XenBus bus instance to search for device children. + * \param node The XenStore node path for the device to find. + * + * \return The device_t of the found device if any, or NULL. + * + * \note device_t is a pointer type, so it can be compared against + * NULL for validity. + */ +static device_t +xenbusb_device_exists(device_t dev, const char *node) +{ + device_t *kids; + device_t result; + struct xenbus_device_ivars *ivars; + int i, count; + + if (device_get_children(dev, &kids, &count)) + return (FALSE); + + result = NULL; + for (i = 0; i < count; i++) { + ivars = device_get_ivars(kids[i]); + if (!strcmp(ivars->xd_node, node)) { + result = kids[i]; + break; + } + } + free(kids, M_TEMP); + + return (result); +} + +static void +xenbusb_delete_child(device_t dev, device_t child) +{ + struct xenbus_device_ivars *ivars; + + ivars = device_get_ivars(child); + + /* + * We no longer care about the otherend of the + * connection. Cancel the watch now so that we + * don't try to handle an event for a partially + * detached child. + */ + if (ivars->xd_otherend_watch.node != NULL) + xs_unregister_watch(&ivars->xd_otherend_watch); + + device_delete_child(dev, child); + xenbusb_free_child_ivars(ivars); +} + +/** + * \param dev The NewBus device representing this XenBus bus. + * \param child The NewBus device representing a child of dev%'s XenBus bus. + */ +static void +xenbusb_verify_device(device_t dev, device_t child) +{ + if (xs_exists(XST_NIL, xenbus_get_node(child), "") == 0) { + + /* + * Device tree has been removed from Xenbus. + * Tear down the device. + */ + xenbusb_delete_child(dev, child); + } +} + +/** + * \brief Enumerate the devices on a XenBus bus and register them with + * the NewBus device tree. + * + * xenbusb_enumerate_bus() will create entries (in state DS_NOTPRESENT) + * for nodes that appear in the XenStore, but will not invoke probe/attach + * operations on drivers. Probe/Attach processing must be separately + * performed via an invocation of xenbusb_probe_children(). This is usually + * done via the xbs_probe_children task. + * + * \param xbs XenBus Bus device softc of the owner of the bus to enumerate. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xenbusb_enumerate_bus(struct xenbusb_softc *xbs) +{ + const char **types; + u_int type_idx; + u_int type_count; + int error; + + error = xs_directory(XST_NIL, xbs->xbs_node, "", &type_count, &types); + if (error) + return (error); + + for (type_idx = 0; type_idx < type_count; type_idx++) + XENBUSB_ENUMERATE_TYPE(xbs->xbs_dev, types[type_idx]); + + free(types, M_XENSTORE); + + return (0); +} + +/** + * Handler for all generic XenBus device systcl nodes. + */ +static int +xenbusb_device_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + device_t dev; + const char *value; + + dev = (device_t)arg1; + switch (arg2) { + case XENBUS_IVAR_NODE: + value = xenbus_get_node(dev); + break; + case XENBUS_IVAR_TYPE: + value = xenbus_get_type(dev); + break; + case XENBUS_IVAR_STATE: + value = xenbus_strstate(xenbus_get_state(dev)); + break; + case XENBUS_IVAR_OTHEREND_ID: + return (sysctl_handle_int(oidp, NULL, + xenbus_get_otherend_id(dev), + req)); + /* NOTREACHED */ + case XENBUS_IVAR_OTHEREND_PATH: + value = xenbus_get_otherend_path(dev); + break; + default: + return (EINVAL); + } + return (SYSCTL_OUT(req, value, strlen(value))); +} + +/** + * Create read-only systcl nodes for xenbusb device ivar data. + * + * \param dev The XenBus device instance to register with sysctl. + */ +static void +xenbusb_device_sysctl_init(device_t dev) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid *tree; + + ctx = device_get_sysctl_ctx(dev); + tree = device_get_sysctl_tree(dev); + + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(tree), + OID_AUTO, + "xenstore_path", + CTLFLAG_RD, + dev, + XENBUS_IVAR_NODE, + xenbusb_device_sysctl_handler, + "A", + "XenStore path to device"); + + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(tree), + OID_AUTO, + "xenbus_dev_type", + CTLFLAG_RD, + dev, + XENBUS_IVAR_TYPE, + xenbusb_device_sysctl_handler, + "A", + "XenBus device type"); + + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(tree), + OID_AUTO, + "xenbus_connection_state", + CTLFLAG_RD, + dev, + XENBUS_IVAR_STATE, + xenbusb_device_sysctl_handler, + "A", + "XenBus state of peer connection"); + + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(tree), + OID_AUTO, + "xenbus_peer_domid", + CTLFLAG_RD, + dev, + XENBUS_IVAR_OTHEREND_ID, + xenbusb_device_sysctl_handler, + "I", + "Xen domain ID of peer"); + + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(tree), + OID_AUTO, + "xenstore_peer_path", + CTLFLAG_RD, + dev, + XENBUS_IVAR_OTHEREND_PATH, + xenbusb_device_sysctl_handler, + "A", + "XenStore path to peer device"); +} + +/** + * \brief Verify the existance of attached device instances and perform + * probe/attach processing for newly arrived devices. + * + * \param dev The NewBus device representing this XenBus bus. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xenbusb_probe_children(device_t dev) +{ + device_t *kids; + struct xenbus_device_ivars *ivars; + int i, count; + + if (device_get_children(dev, &kids, &count) == 0) { + for (i = 0; i < count; i++) { + if (device_get_state(kids[i]) != DS_NOTPRESENT) { + /* + * We already know about this one. + * Make sure it's still here. + */ + xenbusb_verify_device(dev, kids[i]); + continue; + } + + if (device_probe_and_attach(kids[i])) { + /* + * Transition device to the closed state + * so the world knows that attachment will + * not occur. + */ + xenbus_set_state(kids[i], XenbusStateClosed); + + /* + * Remove our record of this device. + * So long as it remains in the closed + * state in the XenStore, we will not find + * it again. The state will only change + * if the control domain actively reconfigures + * this device. + */ + xenbusb_delete_child(dev, kids[i]); + + continue; + } + /* + * Augment default newbus provided dynamic sysctl + * variables with the standard ivar contents of + * XenBus devices. + */ + xenbusb_device_sysctl_init(kids[i]); + + /* + * Now that we have a driver managing this device + * that can receive otherend state change events, + * hook up a watch for them. + */ + ivars = device_get_ivars(kids[i]); + xs_register_watch(&ivars->xd_otherend_watch); + } + free(kids, M_TEMP); + } + + return (0); +} + +/** + * \brief Task callback function to perform XenBus probe operations + * from a known safe context. + * + * \param arg The NewBus device_t representing the bus instance to + * on which to perform probe processing. + * \param pending The number of times this task was queued before it could + * be run. + */ +static void +xenbusb_probe_children_cb(void *arg, int pending __unused) +{ + device_t dev = (device_t)arg; + + /* + * Hold Giant until the Giant free newbus changes are committed. + */ + mtx_lock(&Giant); + xenbusb_probe_children(dev); + mtx_unlock(&Giant); +} + +/** + * \brief XenStore watch callback for the root node of the XenStore + * subtree representing a XenBus. + * + * This callback performs, or delegates to the xbs_probe_children task, + * all processing necessary to handle dynmaic device arrival and departure + * events from a XenBus. + * + * \param watch The XenStore watch object associated with this callback. + * \param vec The XenStore watch event data. + * \param len The number of fields in the event data stream. + */ +static void +xenbusb_devices_changed(struct xs_watch *watch, const char **vec, + unsigned int len) +{ + struct xenbusb_softc *xbs; + device_t dev; + char *node; + char *bus; + char *type; + char *id; + char *p; + u_int component; + + xbs = (struct xenbusb_softc *)watch; + dev = xbs->xbs_dev; + + if (len <= XS_WATCH_PATH) { + device_printf(dev, "xenbusb_devices_changed: " + "Short Event Data.\n"); + return; + } + + node = strdup(vec[XS_WATCH_PATH], M_XENBUS); + p = strchr(node, '/'); + if (p == NULL) + goto out; + bus = node; + *p = 0; + type = p + 1; + + p = strchr(type, '/'); + if (p == NULL) + goto out; + *p++ = 0; + + /* + * Extract the device ID. A device ID has one or more path + * components separated by the '/' character. + * + * e.g. "/" for backend devices. + */ + id = p; + for (component = 0; component < xbs->xbs_id_components; component++) { + p = strchr(p, '/'); + if (p == NULL) + break; + p++; + } + if (p != NULL) + *p = 0; + + if (*id != 0 && component >= xbs->xbs_id_components - 1) { + xenbusb_add_device(xbs->xbs_dev, type, id); + taskqueue_enqueue(taskqueue_thread, &xbs->xbs_probe_children); + } +out: + free(node, M_XENBUS); +} + +/** + * \brief Interrupt configuration hook callback associated with xbs_attch_ch. + * + * Since interrupts are always functional at the time of XenBus configuration, + * there is nothing to be done when the callback occurs. This hook is only + * registered to hold up boot processing while XenBus devices come online. + * + * \param arg Unused configuration hook callback argument. + */ +static void +xenbusb_nop_confighook_cb(void *arg __unused) +{ +} + +/** + * \brief Decrement the number of XenBus child devices in the + * connecting state by one and release the xbs_attch_ch + * interrupt configuration hook if the connecting count + * drops to zero. + * + * \param xbs XenBus Bus device softc of the owner of the bus to enumerate. + */ +static void +xenbusb_release_confighook(struct xenbusb_softc *xbs) +{ + mtx_lock(&xbs->xbs_lock); + KASSERT(xbs->xbs_connecting_children > 0, + ("Connecting device count error\n")); + xbs->xbs_connecting_children--; + if (xbs->xbs_connecting_children == 0 + && (xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) { + xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE; + mtx_unlock(&xbs->xbs_lock); + config_intrhook_disestablish(&xbs->xbs_attach_ch); + } else { + mtx_unlock(&xbs->xbs_lock); + } +} + +/*--------------------------- Public Functions -------------------------------*/ +/*--------- API comments for these methods can be found in xenbusb.h ---------*/ +void +xenbusb_identify(driver_t *driver __unused, device_t parent) +{ + /* + * A single instance of each bus type for which we have a driver + * is always present in a system operating under Xen. + */ + BUS_ADD_CHILD(parent, 0, driver->name, 0); +} + +int +xenbusb_add_device(device_t dev, const char *type, const char *id) +{ + struct xenbusb_softc *xbs; + struct sbuf *devpath_sbuf; + char *devpath; + struct xenbus_device_ivars *ivars; + int error; + + xbs = device_get_softc(dev); + devpath_sbuf = sbuf_new_auto(); + sbuf_printf(devpath_sbuf, "%s/%s/%s", xbs->xbs_node, type, id); + sbuf_finish(devpath_sbuf); + devpath = sbuf_data(devpath_sbuf); + + ivars = malloc(sizeof(*ivars), M_XENBUS, M_ZERO|M_WAITOK); + error = ENXIO; + + if (xs_exists(XST_NIL, devpath, "") != 0) { + device_t child; + enum xenbus_state state; + char *statepath; + + child = xenbusb_device_exists(dev, devpath); + if (child != NULL) { + /* + * We are already tracking this node + */ + error = 0; + goto out; + } + + state = xenbus_read_driver_state(devpath); + if (state != XenbusStateInitialising) { + /* + * Device is not new, so ignore it. This can + * happen if a device is going away after + * switching to Closed. + */ + printf("xenbusb_add_device: Device %s ignored. " + "State %d\n", devpath, state); + error = 0; + goto out; + } + + sx_init(&ivars->xd_lock, "xdlock"); + ivars->xd_flags = XDF_CONNECTING; + ivars->xd_node = strdup(devpath, M_XENBUS); + ivars->xd_type = strdup(type, M_XENBUS); + ivars->xd_state = XenbusStateInitialising; + + error = XENBUSB_GET_OTHEREND_NODE(dev, ivars); + if (error) { + printf("xenbus_update_device: %s no otherend id\n", + devpath); + goto out; + } + + statepath = malloc(strlen(ivars->xd_otherend_path) + + strlen("/state") + 1, M_XENBUS, M_WAITOK); + sprintf(statepath, "%s/state", ivars->xd_otherend_path); + + ivars->xd_otherend_watch.node = statepath; + ivars->xd_otherend_watch.callback = xenbusb_otherend_changed; + + mtx_lock(&xbs->xbs_lock); + xbs->xbs_connecting_children++; + mtx_unlock(&xbs->xbs_lock); + + child = device_add_child(dev, NULL, -1); + ivars->xd_dev = child; + device_set_ivars(child, ivars); + } + +out: + sbuf_delete(devpath_sbuf); + if (error != 0) + xenbusb_free_child_ivars(ivars); + + return (error); +} + +int +xenbusb_attach(device_t dev, char *bus_node, u_int id_components) +{ + struct xenbusb_softc *xbs; + + xbs = device_get_softc(dev); + mtx_init(&xbs->xbs_lock, "xenbusb softc lock", NULL, MTX_DEF); + xbs->xbs_node = bus_node; + xbs->xbs_id_components = id_components; + xbs->xbs_dev = dev; + + /* + * Since XenBus busses are attached to the XenStore, and + * the XenStore does not probe children until after interrupt + * services are available, this config hook is used solely + * to ensure that the remainder of the boot process (e.g. + * mount root) is deferred until child devices are adequately + * probed. We unblock the boot process as soon as the + * connecting child count in our softc goes to 0. + */ + xbs->xbs_attach_ch.ich_func = xenbusb_nop_confighook_cb; + xbs->xbs_attach_ch.ich_arg = dev; + config_intrhook_establish(&xbs->xbs_attach_ch); + xbs->xbs_flags |= XBS_ATTACH_CH_ACTIVE; + xbs->xbs_connecting_children = 1; + + /* + * The subtree for this bus type may not yet exist + * causing initial enumeration to fail. We still + * want to return success from our attach though + * so that we are ready to handle devices for this + * bus when they are dynamically attached to us + * by a Xen management action. + */ + (void)xenbusb_enumerate_bus(xbs); + xenbusb_probe_children(dev); + + xbs->xbs_device_watch.node = bus_node; + xbs->xbs_device_watch.callback = xenbusb_devices_changed; + + TASK_INIT(&xbs->xbs_probe_children, 0, xenbusb_probe_children_cb, dev); + + xs_register_watch(&xbs->xbs_device_watch); + + xenbusb_release_confighook(xbs); + + return (0); +} + +int +xenbusb_resume(device_t dev) +{ + device_t *kids; + struct xenbus_device_ivars *ivars; + int i, count, error; + char *statepath; + + /* + * We must re-examine each device and find the new path for + * its backend. + */ + if (device_get_children(dev, &kids, &count) == 0) { + for (i = 0; i < count; i++) { + if (device_get_state(kids[i]) == DS_NOTPRESENT) + continue; + + ivars = device_get_ivars(kids[i]); + + xs_unregister_watch(&ivars->xd_otherend_watch); + ivars->xd_state = XenbusStateInitialising; + + /* + * Find the new backend details and + * re-register our watch. + */ + error = XENBUSB_GET_OTHEREND_NODE(dev, ivars); + if (error) + return (error); + + DEVICE_RESUME(kids[i]); + + statepath = malloc(strlen(ivars->xd_otherend_path) + + strlen("/state") + 1, M_XENBUS, M_WAITOK); + sprintf(statepath, "%s/state", ivars->xd_otherend_path); + + free(ivars->xd_otherend_watch.node, M_XENBUS); + ivars->xd_otherend_watch.node = statepath; + xs_register_watch(&ivars->xd_otherend_watch); + +#if 0 + /* + * Can't do this yet since we are running in + * the xenwatch thread and if we sleep here, + * we will stop delivering watch notifications + * and the device will never come back online. + */ + sx_xlock(&ivars->xd_lock); + while (ivars->xd_state != XenbusStateClosed + && ivars->xd_state != XenbusStateConnected) + sx_sleep(&ivars->xd_state, &ivars->xd_lock, + 0, "xdresume", 0); + sx_xunlock(&ivars->xd_lock); +#endif + } + free(kids, M_TEMP); + } + + return (0); +} + +int +xenbusb_print_child(device_t dev, device_t child) +{ + struct xenbus_device_ivars *ivars = device_get_ivars(child); + int retval = 0; + + retval += bus_print_child_header(dev, child); + retval += printf(" at %s", ivars->xd_node); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +int +xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct xenbus_device_ivars *ivars = device_get_ivars(child); + + switch (index) { + case XENBUS_IVAR_NODE: + *result = (uintptr_t) ivars->xd_node; + return (0); + + case XENBUS_IVAR_TYPE: + *result = (uintptr_t) ivars->xd_type; + return (0); + + case XENBUS_IVAR_STATE: + *result = (uintptr_t) ivars->xd_state; + return (0); + + case XENBUS_IVAR_OTHEREND_ID: + *result = (uintptr_t) ivars->xd_otherend_id; + return (0); + + case XENBUS_IVAR_OTHEREND_PATH: + *result = (uintptr_t) ivars->xd_otherend_path; + return (0); + } + + return (ENOENT); +} + +int +xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + struct xenbus_device_ivars *ivars = device_get_ivars(child); + enum xenbus_state newstate; + int currstate; + + switch (index) { + case XENBUS_IVAR_STATE: + { + int error; + + newstate = (enum xenbus_state) value; + sx_xlock(&ivars->xd_lock); + if (ivars->xd_state == newstate) { + error = 0; + goto out; + } + + error = xs_scanf(XST_NIL, ivars->xd_node, "state", + NULL, "%d", &currstate); + if (error) + goto out; + + do { + error = xs_printf(XST_NIL, ivars->xd_node, "state", + "%d", newstate); + } while (error == EAGAIN); + if (error) { + /* + * Avoid looping through xenbus_dev_fatal() + * which calls xenbus_write_ivar to set the + * state to closing. + */ + if (newstate != XenbusStateClosing) + xenbus_dev_fatal(dev, error, + "writing new state"); + goto out; + } + ivars->xd_state = newstate; + + if ((ivars->xd_flags & XDF_CONNECTING) != 0 + && (newstate == XenbusStateClosed + || newstate == XenbusStateConnected)) { + struct xenbusb_softc *xbs; + + ivars->xd_flags &= ~XDF_CONNECTING; + xbs = device_get_softc(dev); + xenbusb_release_confighook(xbs); + } + + wakeup(&ivars->xd_state); + out: + sx_xunlock(&ivars->xd_lock); + return (error); + } + + case XENBUS_IVAR_NODE: + case XENBUS_IVAR_TYPE: + case XENBUS_IVAR_OTHEREND_ID: + case XENBUS_IVAR_OTHEREND_PATH: + /* + * These variables are read-only. + */ + return (EINVAL); + } + + return (ENOENT); +} diff --git a/sys/xen/xenbus/xenbusb.h b/sys/xen/xenbus/xenbusb.h new file mode 100644 index 00000000000..75abb983c3a --- /dev/null +++ b/sys/xen/xenbus/xenbusb.h @@ -0,0 +1,272 @@ +/*- + * Core definitions and data structures shareable across OS platforms. + * + * Copyright (c) 2010 Spectra Logic Corporation + * Copyright (C) 2008 Doug Rabson + * 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 + * substantially 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 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 _XEN_XENBUS_XENBUSB_H +#define _XEN_XENBUS_XENBUSB_H + +/** + * \file xenbusb.h + * + * Datastructures and function declarations for use in implementing + * bus attachements (e.g. frontend and backend device busses) for XenBus. + */ +#include "xenbusb_if.h" + +/** + * Enumeration of state flag values for the xbs_flags field of + * the xenbusb_softc structure. + */ +typedef enum { + /** */ + XBS_ATTACH_CH_ACTIVE = 0x01 +} xenbusb_softc_flag; + +/** + * \brief Container for all state needed to manage a Xenbus Bus + * attachment. + */ +struct xenbusb_softc { + /** + * XenStore watch used to monitor the subtree of the + * XenStore where devices for this bus attachment arrive + * and depart. + * + * \note This field must be the first in the softc structure + * so that a simple cast can be used to retrieve the + * softc from within a XenStore watch event callback. + */ + struct xs_watch xbs_device_watch; + + /** Mutex used to protect fields of the xenbusb_softc. */ + struct mtx xbs_lock; + + /** State flags. */ + xenbusb_softc_flag xbs_flags; + + /** + * A dedicated task for processing child arrival and + * departure events. + */ + struct task xbs_probe_children; + + /** + * Config Hook used to block boot processing until + * XenBus devices complete their connection processing + * with other VMs. + */ + struct intr_config_hook xbs_attach_ch; + + /** + * The number of children for this bus that are still + * in the connecting (to other VMs) state. This variable + * is used to determine when to release xbs_attach_ch. + */ + u_int xbs_connecting_children; + + /** The NewBus device_t for this bus attachment. */ + device_t xbs_dev; + + /** + * The VM relative path to the XenStore subtree this + * bus attachment manages. + */ + const char *xbs_node; + + /** + * The number of path components (strings separated by the '/' + * character) that make up the device ID on this bus. + */ + u_int xbs_id_components; +}; + +/** + * Enumeration of state flag values for the xbs_flags field of + * the xenbusb_softc structure. + */ +typedef enum { + + /** + * This device is contributing to the xbs_connecting_children + * count of its parent bus. + */ + XDF_CONNECTING = 0x01 +} xenbus_dev_flag; + +/** Instance variables for devices on a XenBus bus. */ +struct xenbus_device_ivars { + /** + * XenStore watch used to monitor the subtree of the + * XenStore where information about the otherend of + * the split Xen device this device instance represents. + * + * \note This field must be the first in the instance + * variable structure so that a simple cast can be + * used to retrieve ivar data from within a XenStore + * watch event callback. + */ + struct xs_watch xd_otherend_watch; + + /** Sleepable lock used to protect instance data. */ + struct sx xd_lock; + + /** State flags. */ + xenbus_dev_flag xd_flags; + + /** The NewBus device_t for this XenBus device instance. */ + device_t xd_dev; + + /** + * The VM relative path to the XenStore subtree representing + * this VMs half of this device. + */ + char *xd_node; + + /** XenBus device type ("vbd", "vif", etc.). */ + char *xd_type; + + /** + * Cached version of /state node in the XenStore. + */ + enum xenbus_state xd_state; + + /** The VM identifier of the other end of this split device. */ + int xd_otherend_id; + + /** + * The path to the subtree of the XenStore where information + * about the otherend of this split device instance. + */ + char *xd_otherend_path; +}; + +/** + * \brief Identify instances of this device type in the system. + * + * \param driver The driver performing this identify action. + * \param parent The NewBus parent device for any devices this method adds. + */ +void xenbusb_identify(driver_t *driver __unused, device_t parent); + +/** + * \brief Perform common XenBus bus attach processing. + * + * \param dev The NewBus device representing this XenBus bus. + * \param bus_node The XenStore path to the XenStore subtree for + * this XenBus bus. + * \param id_components The number of '/' separated path components that + * make up a unique device ID on this XenBus bus. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * Intiailizes the softc for this bus, installs an interrupt driven + * configuration hook to block boot processing until XenBus devices fully + * configure, performs an initial probe/attach of the bus, and registers + * a XenStore watch so we are notified when the bus topology changes. + */ +int xenbusb_attach(device_t dev, char *bus_node, u_int id_components); + +/** + * \brief Perform common XenBus bus resume handling. + * + * \param dev The NewBus device representing this XenBus bus. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xenbusb_resume(device_t dev); + +/** + * \brief Pretty-prints information about a child of a XenBus bus. + * + * \param dev The NewBus device representing this XenBus bus. + * \param child The NewBus device representing a child of dev%'s XenBus bus. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xenbusb_print_child(device_t dev, device_t child); + +/** + * \brief Common XenBus child instance variable read access method. + * + * \param dev The NewBus device representing this XenBus bus. + * \param child The NewBus device representing a child of dev%'s XenBus bus. + * \param index The index of the instance variable to access. + * \param result The value of the instance variable accessed. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xenbusb_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result); + +/** + * \brief Common XenBus child instance variable write access method. + * + * \param dev The NewBus device representing this XenBus bus. + * \param child The NewBus device representing a child of dev%'s XenBus bus. + * \param index The index of the instance variable to access. + * \param value The new value to set in the instance variable accessed. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xenbusb_write_ivar(device_t dev, device_t child, int index, + uintptr_t value); + +/** + * \brief Attempt to add a XenBus device instance to this XenBus bus. + * + * \param dev The NewBus device representing this XenBus bus. + * \param type The device type being added (e.g. "vbd", "vif"). + * \param id The device ID for this device. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. Failure indicates that either the + * path to this device no longer exists or insufficient + * information exists in the XenStore to create a new + * device. + * + * If successful, this routine will add a device_t with instance + * variable storage to the NewBus device topology. Probe/Attach + * processing is not performed by this routine, but must be scheduled + * via the xbs_probe_children task. This separation of responsibilities + * is required to avoid hanging up the XenStore event delivery thread + * with our probe/attach work in the event a device is added via + * a callback from the XenStore. + */ +int xenbusb_add_device(device_t dev, const char *type, const char *id); + +#endif /* _XEN_XENBUS_XENBUSB_H */ diff --git a/sys/xen/xenbus/xenbusb_back.c b/sys/xen/xenbus/xenbusb_back.c new file mode 100644 index 00000000000..32bbc04dbdc --- /dev/null +++ b/sys/xen/xenbus/xenbusb_back.c @@ -0,0 +1,295 @@ +/****************************************************************************** + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2009, 2010 Spectra Logic Corporation + * Copyright (C) 2008 Doug Rabson + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005 XenSource Ltd + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * \file xenbusb_back.c + * + * XenBus management of the NewBus bus containing the backend instances of + * Xen split devices. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +/*------------------ Private Device Attachment Functions --------------------*/ +/** + * \brief Probe for the existance of the XenBus back bus. + * + * \param dev NewBus device_t for this XenBus back bus instance. + * + * \return Always returns 0 indicating success. + */ +static int +xenbusb_back_probe(device_t dev) +{ + device_set_desc(dev, "Xen Backend Devices"); + + return (0); +} + +/** + * \brief Attach the XenBus back bus. + * + * \param dev NewBus device_t for this XenBus back bus instance. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xenbusb_back_attach(device_t dev) +{ + struct xenbusb_softc *xbs; + int error; + + xbs = device_get_softc(dev); + error = xenbusb_attach(dev, "backend", /*id_components*/2); + + /* + * Backend devices operate to serve other domains, + * so there is no need to hold up boot processing + * while connections to foreign domains are made. + */ + mtx_lock(&xbs->xbs_lock); + if ((xbs->xbs_flags & XBS_ATTACH_CH_ACTIVE) != 0) { + xbs->xbs_flags &= ~XBS_ATTACH_CH_ACTIVE; + mtx_unlock(&xbs->xbs_lock); + config_intrhook_disestablish(&xbs->xbs_attach_ch); + } else { + mtx_unlock(&xbs->xbs_lock); + } + + return (error); +} + +/** + * \brief Enumerate all devices of the given type on this bus. + * + * \param dev NewBus device_t for this XenBus backend bus instance. + * \param type String indicating the device sub-tree (e.g. "vfb", "vif") + * to enumerate. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * Devices that are found are entered into the NewBus hierarchy via + * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects + * and ignores duplicate devices, so it can be called unconditionally + * for any device found in the XenStore. + * + * The backend XenStore hierarchy has the following format: + * + * backend/// + * + */ +static int +xenbusb_back_enumerate_type(device_t dev, const char *type) +{ + struct xenbusb_softc *xbs; + const char **vms; + u_int vm_idx; + u_int vm_count; + int error; + + xbs = device_get_softc(dev); + error = xs_directory(XST_NIL, xbs->xbs_node, type, &vm_count, &vms); + if (error) + return (error); + for (vm_idx = 0; vm_idx < vm_count; vm_idx++) { + struct sbuf *vm_path; + const char *vm; + const char **devs; + u_int dev_idx; + u_int dev_count; + + vm = vms[vm_idx]; + + vm_path = xs_join(type, vm); + error = xs_directory(XST_NIL, xbs->xbs_node, sbuf_data(vm_path), + &dev_count, &devs); + sbuf_delete(vm_path); + if (error) + break; + + for (dev_idx = 0; dev_idx < dev_count; dev_idx++) { + const char *dev_num; + struct sbuf *id; + + dev_num = devs[dev_idx]; + id = xs_join(vm, dev_num); + xenbusb_add_device(dev, type, sbuf_data(id)); + sbuf_delete(id); + } + free(devs, M_XENSTORE); + } + + free(vms, M_XENSTORE); + + return (0); +} + +/** + * \brief Determine and store the XenStore path for the other end of + * a split device whose local end is represented by ivars. + * + * \param dev NewBus device_t for this XenBus backend bus instance. + * \param ivars Instance variables from the XenBus child device for + * which to perform this function. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * If successful, the xd_otherend_path field of the child's instance + * variables will be updated. + * + */ +static int +xenbusb_back_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars) +{ + char *otherend_path; + int error; + + if (ivars->xd_otherend_path != NULL) { + free(ivars->xd_otherend_path, M_XENBUS); + ivars->xd_otherend_path = NULL; + } + + error = xs_gather(XST_NIL, ivars->xd_node, + "frontend-id", "%i", &ivars->xd_otherend_id, + "frontend", NULL, &otherend_path, + NULL); + + if (error == 0) { + ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS); + free(otherend_path, M_XENSTORE); + } + return (error); +} + +/** + * \brief Backend XenBus child instance variable write access method. + * + * \param dev The NewBus device representing this XenBus bus. + * \param child The NewBus device representing a child of dev%'s XenBus bus. + * \param index The index of the instance variable to access. + * \param value The new value to set in the instance variable accessed. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * Xenbus_back overrides this method so that it can trap state transitions + * of local backend devices and clean up their XenStore entries as necessary + * during device instance teardown. + */ +static int +xenbusb_back_write_ivar(device_t dev, device_t child, int index, + uintptr_t value) +{ + int error; + + error = xenbusb_write_ivar(dev, child, index, value); + + if (index == XENBUS_IVAR_STATE + && (enum xenbus_state)value == XenbusStateClosed + && xenbus_dev_is_online(child) == 0) { + + /* + * Cleanup the hotplug entry in the XenStore if + * present. The control domain expects any userland + * component associated with this device to destroy + * this node in order to signify it is safe to + * teardown the device. However, not all backends + * rely on userland components, and those that + * do should either use a communication channel + * other than the XenStore, or ensure the hotplug + * data is already cleaned up. + * + * This removal ensures that no matter what path + * is taken to mark a back-end closed, the control + * domain will understand that it is closed. + */ + xs_rm(XST_NIL, xenbus_get_node(child), "hotplug-status"); + } + + return (error); +} + +/*-------------------- Private Device Attachment Data -----------------------*/ +static device_method_t xenbusb_back_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, xenbusb_identify), + DEVMETHOD(device_probe, xenbusb_back_probe), + DEVMETHOD(device_attach, xenbusb_back_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus Interface */ + DEVMETHOD(bus_print_child, xenbusb_print_child), + DEVMETHOD(bus_read_ivar, xenbusb_read_ivar), + DEVMETHOD(bus_write_ivar, xenbusb_back_write_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + /* XenBus Bus Interface */ + DEVMETHOD(xenbusb_enumerate_type, xenbusb_back_enumerate_type), + DEVMETHOD(xenbusb_get_otherend_node, xenbusb_back_get_otherend_node), + { 0, 0 } +}; + +DEFINE_CLASS_0(xenbusb_back, xenbusb_back_driver, xenbusb_back_methods, + sizeof(struct xenbusb_softc)); +devclass_t xenbusb_back_devclass; + +DRIVER_MODULE(xenbusb_back, xenstore, xenbusb_back_driver, + xenbusb_back_devclass, 0, 0); diff --git a/sys/xen/xenbus/xenbusb_front.c b/sys/xen/xenbus/xenbusb_front.c new file mode 100644 index 00000000000..0bc06a4538c --- /dev/null +++ b/sys/xen/xenbus/xenbusb_front.c @@ -0,0 +1,195 @@ +/****************************************************************************** + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2009, 2010 Spectra Logic Corporation + * Copyright (C) 2008 Doug Rabson + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * Copyright (C) 2005 XenSource Ltd + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * \file xenbusb_front.c + * + * XenBus management of the NewBus bus containing the frontend instances of + * Xen split devices. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +/*------------------ Private Device Attachment Functions --------------------*/ +/** + * \brief Probe for the existance of the XenBus front bus. + * + * \param dev NewBus device_t for this XenBus front bus instance. + * + * \return Always returns 0 indicating success. + */ +static int +xenbusb_front_probe(device_t dev) +{ + device_set_desc(dev, "Xen Frontend Devices"); + + return (0); +} + +/** + * \brief Attach the XenBus front bus. + * + * \param dev NewBus device_t for this XenBus front bus instance. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xenbusb_front_attach(device_t dev) +{ + return (xenbusb_attach(dev, "device", /*id_components*/1)); +} + +/** + * \brief Enumerate all devices of the given type on this bus. + * + * \param dev NewBus device_t for this XenBus front bus instance. + * \param type String indicating the device sub-tree (e.g. "vfb", "vif") + * to enumerate. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * Devices that are found are entered into the NewBus hierarchy via + * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects + * and ignores duplicate devices, so it can be called unconditionally + * for any device found in the XenStore. + */ +static int +xenbusb_front_enumerate_type(device_t dev, const char *type) +{ + struct xenbusb_softc *xbs; + const char **dir; + unsigned int i, count; + int error; + + xbs = device_get_softc(dev); + error = xs_directory(XST_NIL, xbs->xbs_node, type, &count, &dir); + if (error) + return (error); + for (i = 0; i < count; i++) + xenbusb_add_device(dev, type, dir[i]); + + free(dir, M_XENSTORE); + + return (0); +} + +/** + * \brief Determine and store the XenStore path for the other end of + * a split device whose local end is represented by ivars. + * + * If successful, the xd_otherend_path field of the child's instance + * variables will be updated. + * + * \param dev NewBus device_t for this XenBus front bus instance. + * \param ivars Instance variables from the XenBus child device for + * which to perform this function. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xenbusb_front_get_otherend_node(device_t dev, struct xenbus_device_ivars *ivars) +{ + char *otherend_path; + int error; + + if (ivars->xd_otherend_path != NULL) { + free(ivars->xd_otherend_path, M_XENBUS); + ivars->xd_otherend_path = NULL; + } + + error = xs_gather(XST_NIL, ivars->xd_node, + "backend-id", "%i", &ivars->xd_otherend_id, + "backend", NULL, &otherend_path, + NULL); + + if (error == 0) { + ivars->xd_otherend_path = strdup(otherend_path, M_XENBUS); + free(otherend_path, M_XENSTORE); + } + return (error); +} + +/*-------------------- Private Device Attachment Data -----------------------*/ +static device_method_t xenbusb_front_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, xenbusb_identify), + DEVMETHOD(device_probe, xenbusb_front_probe), + DEVMETHOD(device_attach, xenbusb_front_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + + /* Bus Interface */ + DEVMETHOD(bus_print_child, xenbusb_print_child), + DEVMETHOD(bus_read_ivar, xenbusb_read_ivar), + DEVMETHOD(bus_write_ivar, xenbusb_write_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + /* XenBus Bus Interface */ + DEVMETHOD(xenbusb_enumerate_type, xenbusb_front_enumerate_type), + DEVMETHOD(xenbusb_get_otherend_node, xenbusb_front_get_otherend_node), + { 0, 0 } +}; + +DEFINE_CLASS_0(xenbusb_front, xenbusb_front_driver, xenbusb_front_methods, + sizeof(struct xenbusb_softc)); +devclass_t xenbusb_front_devclass; + +DRIVER_MODULE(xenbusb_front, xenstore, xenbusb_front_driver, + xenbusb_front_devclass, 0, 0); diff --git a/sys/xen/xenbus/xenbusb_if.m b/sys/xen/xenbus/xenbusb_if.m new file mode 100644 index 00000000000..a32e3f6fe51 --- /dev/null +++ b/sys/xen/xenbus/xenbusb_if.m @@ -0,0 +1,78 @@ +#- +# Copyright (c) 2010 Spectra Logic Corporation +# 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 +# substantially 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 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$ +# + +#include + +HEADER { +struct xenbus_device_ivars; +} + +INTERFACE xenbusb; + +/** + * \brief Enumerate all devices of the given type on this bus. + * + * \param _dev NewBus device_t for this XenBus (front/back) bus instance. + * \param _type String indicating the device sub-tree (e.g. "vfb", "vif") + * to enumerate. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * Devices that are found should be entered into the NewBus hierarchy via + * xenbusb_add_device(). xenbusb_add_device() ignores duplicate detects + * and ignores duplicate devices, so it can be called unconditionally + * for any device found in the XenStore. + */ +METHOD int enumerate_type { + device_t _dev; + const char *_type; +}; + +/** + * \brief Determine and store the XenStore path for the other end of + * a split device whose local end is represented by ivars. + * + * If successful, the xd_otherend_path field of the child's instance + * variables must be updated. + * + * \param _dev NewBus device_t for this XenBus (front/back) bus instance. + * \param _ivars Instance variables from the XenBus child device for + * which to perform this function. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +METHOD int get_otherend_node { + device_t _dev; + struct xenbus_device_ivars *_ivars; +} diff --git a/sys/xen/xenbus/xenbusvar.h b/sys/xen/xenbus/xenbusvar.h index 651166421ea..55d7f29d4d6 100644 --- a/sys/xen/xenbus/xenbusvar.h +++ b/sys/xen/xenbus/xenbusvar.h @@ -1,8 +1,4 @@ /****************************************************************************** - * xenbus.h - * - * Talks to Xen Store to figure out what devices we have. - * * Copyright (C) 2005 Rusty Russell, IBM Corporation * Copyright (C) 2005 XenSource Ltd. * @@ -30,46 +26,64 @@ * $FreeBSD$ */ +/** + * \file xenbusvar.h + * + * \brief Datastructures and function declarations for usedby device + * drivers operating on the XenBus. + */ + #ifndef _XEN_XENBUS_XENBUSVAR_H #define _XEN_XENBUS_XENBUSVAR_H #include #include #include +#include +#include + +#include #include + +#include #include #include +#include + #include "xenbus_if.h" +/* XenBus allocations including XenStore data returned to clients. */ +MALLOC_DECLARE(M_XENBUS); + enum { - /* + /** * Path of this device node. */ XENBUS_IVAR_NODE, - /* + /** * The device type (e.g. vif, vbd). */ XENBUS_IVAR_TYPE, - /* + /** * The state of this device (not the otherend's state). */ XENBUS_IVAR_STATE, - /* + /** * Domain ID of the other end device. */ XENBUS_IVAR_OTHEREND_ID, - /* + /** * Path of the other end device. */ XENBUS_IVAR_OTHEREND_PATH }; -/* +/** * Simplified accessors for xenbus devices */ #define XENBUS_ACCESSOR(var, ivar, type) \ @@ -81,179 +95,184 @@ XENBUS_ACCESSOR(state, STATE, enum xenbus_state) XENBUS_ACCESSOR(otherend_id, OTHEREND_ID, int) XENBUS_ACCESSOR(otherend_path, OTHEREND_PATH, const char *) -/* Register callback to watch this node. */ -struct xenbus_watch -{ - LIST_ENTRY(xenbus_watch) list; - - /* Path being watched. */ - char *node; - - /* Callback (executed in a process context with no locks held). */ - void (*callback)(struct xenbus_watch *, - const char **vec, unsigned int len); -}; - -typedef int (*xenstore_event_handler_t)(void *); - -struct xenbus_transaction -{ - uint32_t id; -}; - -#define XBT_NIL ((struct xenbus_transaction) { 0 }) - -int xenbus_directory(struct xenbus_transaction t, const char *dir, - const char *node, unsigned int *num, char ***result); -int xenbus_read(struct xenbus_transaction t, const char *dir, - const char *node, unsigned int *len, void **result); -int xenbus_write(struct xenbus_transaction t, const char *dir, - const char *node, const char *string); -int xenbus_mkdir(struct xenbus_transaction t, const char *dir, - const char *node); -int xenbus_exists(struct xenbus_transaction t, const char *dir, - const char *node); -int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node); -int xenbus_transaction_start(struct xenbus_transaction *t); -int xenbus_transaction_end(struct xenbus_transaction t, int abort); - -/* - * Single read and scanf: returns errno or zero. If scancountp is - * non-null, then number of items scanned is returned in *scanncountp. - */ -int xenbus_scanf(struct xenbus_transaction t, - const char *dir, const char *node, int *scancountp, const char *fmt, ...) - __attribute__((format(scanf, 5, 6))); - -/* Single printf and write: returns errno or 0. */ -int xenbus_printf(struct xenbus_transaction t, - const char *dir, const char *node, const char *fmt, ...) - __attribute__((format(printf, 4, 5))); - -/* - * Generic read function: NULL-terminated triples of name, - * sprintf-style type string, and pointer. Returns 0 or errno. - */ -int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); - -/* notifer routines for when the xenstore comes up */ -int register_xenstore_notifier(xenstore_event_handler_t func, void *arg, int priority); -#if 0 -void unregister_xenstore_notifier(); -#endif -int register_xenbus_watch(struct xenbus_watch *watch); -void unregister_xenbus_watch(struct xenbus_watch *watch); -void xs_suspend(void); -void xs_resume(void); - -/* Used by xenbus_dev to borrow kernel's store connection. */ -int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void **result); - -#if 0 - -#define XENBUS_IS_ERR_READ(str) ({ \ - if (!IS_ERR(str) && strlen(str) == 0) { \ - free(str, M_DEVBUF); \ - str = ERR_PTR(-ERANGE); \ - } \ - IS_ERR(str); \ -}) - -#endif - -#define XENBUS_EXIST_ERR(err) ((err) == ENOENT || (err) == ERANGE) - - /** - * Register a watch on the given path, using the given xenbus_watch structure - * for storage, and the given callback function as the callback. Return 0 on - * success, or errno on error. On success, the given path will be saved as - * watch->node, and remains the caller's to free. On error, watch->node will - * be NULL, the device will switch to XenbusStateClosing, and the error will - * be saved in the store. - */ -int xenbus_watch_path(device_t dev, char *path, - struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)); - - -/** - * Register a watch on the given path/path2, using the given xenbus_watch - * structure for storage, and the given callback function as the callback. - * Return 0 on success, or errno on error. On success, the watched path - * (path/path2) will be saved as watch->node, and becomes the caller's to - * kfree(). On error, watch->node will be NULL, so the caller has nothing to - * free, the device will switch to XenbusStateClosing, and the error will be - * saved in the store. - */ -int xenbus_watch_path2(device_t dev, const char *path, - const char *path2, struct xenbus_watch *watch, - void (*callback)(struct xenbus_watch *, - const char **, unsigned int)); - - -/** - * Advertise in the store a change of the given driver to the given new_state. - * which case this is performed inside its own transaction. Return 0 on - * success, or errno on error. On error, the device will switch to - * XenbusStateClosing, and the error will be saved in the store. - */ -int xenbus_switch_state(device_t dev, - XenbusState new_state); - - -/** - * Grant access to the given ring_mfn to the peer of the given device. - * Return 0 on success, or errno on error. On error, the device will - * switch to XenbusStateClosing, and the error will be saved in the - * store. The grant ring reference is returned in *refp. - */ -int xenbus_grant_ring(device_t dev, unsigned long ring_mfn, int *refp); - - -/** - * Allocate an event channel for the given xenbus_device, assigning the newly - * created local port to *port. Return 0 on success, or errno on error. On - * error, the device will switch to XenbusStateClosing, and the error will be - * saved in the store. - */ -int xenbus_alloc_evtchn(device_t dev, int *port); - - -/** - * Free an existing event channel. Returns 0 on success or errno on error. - */ -int xenbus_free_evtchn(device_t dev, int port); - - -/** - * Return the state of the driver rooted at the given store path, or - * XenbusStateClosed if no state can be read. + * Return the state of a XenBus device. + * + * \param path The root XenStore path for the device. + * + * \return The current state of the device or XenbusStateClosed if no + * state can be read. */ XenbusState xenbus_read_driver_state(const char *path); - -/*** - * Report the given negative errno into the store, along with the given - * formatted message. +/** + * Initialize and register a watch on the given path (client suplied storage). + * + * \param dev The XenBus device requesting the watch service. + * \param path The XenStore path of the object to be watched. The + * storage for this string must be stable for the lifetime + * of the watch. + * \param watch The watch object to use for this request. This object + * must be stable for the lifetime of the watch. + * \param callback The function to call when XenStore objects at or below + * path are modified. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * \note On error, the device 'dev' will be switched to the XenbusStateClosing + * state and the returned error is saved in the per-device error node + * for dev in the XenStore. */ -void xenbus_dev_error(device_t dev, int err, const char *fmt, - ...); +int xenbus_watch_path(device_t dev, char *path, + struct xs_watch *watch, + xs_watch_cb_t *callback); - -/*** - * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by - * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly - * closedown of this driver and its peer. +/** + * Initialize and register a watch at path/path2 in the XenStore. + * + * \param dev The XenBus device requesting the watch service. + * \param path The base XenStore path of the object to be watched. + * \param path2 The tail XenStore path of the object to be watched. + * \param watch The watch object to use for this request. This object + * must be stable for the lifetime of the watch. + * \param callback The function to call when XenStore objects at or below + * path are modified. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * \note On error, \a dev will be switched to the XenbusStateClosing + * state and the returned error is saved in the per-device error node + * for \a dev in the XenStore. + * + * Similar to xenbus_watch_path, however the storage for the path to the + * watched object is allocated from the heap and filled with "path '/' path2". + * Should a call to this function succeed, it is the callers responsibility + * to free watch->node using the M_XENBUS malloc type. */ -void xenbus_dev_fatal(device_t dev, int err, const char *fmt, - ...); +int xenbus_watch_path2(device_t dev, const char *path, + const char *path2, struct xs_watch *watch, + xs_watch_cb_t *callback); -int xenbus_dev_init(void); +/** + * Grant access to the given ring_mfn to the peer of the given device. + * + * \param dev The device granting access to the ring page. + * \param ring_mfn The guest machine page number of the page to grant + * peer access rights. + * \param refp[out] The grant reference for the page. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * A successful call to xenbus_grant_ring should be paired with a call + * to gnttab_end_foreign_access() when foregn access to this page is no + * longer requried. + * + * \note On error, \a dev will be switched to the XenbusStateClosing + * state and the returned error is saved in the per-device error node + * for \a dev in the XenStore. + */ +int xenbus_grant_ring(device_t dev, unsigned long ring_mfn, grant_ref_t *refp); +/** + * Allocate an event channel for the given XenBus device. + * + * \param dev The device for which to allocate the event channel. + * \param port[out] The port identifier for the allocated event channel. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * A successfully allocated event channel should be free'd using + * xenbus_free_evtchn(). + * + * \note On error, \a dev will be switched to the XenbusStateClosing + * state and the returned error is saved in the per-device error node + * for \a dev in the XenStore. + */ +int xenbus_alloc_evtchn(device_t dev, evtchn_port_t *port); + +/** + * Free an existing event channel. + * + * \param dev The device which allocated this event channel. + * \param port The port identifier for the event channel to free. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * \note On error, \a dev will be switched to the XenbusStateClosing + * state and the returned error is saved in the per-device error node + * for \a dev in the XenStore. + */ +int xenbus_free_evtchn(device_t dev, evtchn_port_t port); + +/** + * Record the given errno, along with the given, printf-style, formatted + * message in dev's device specific error node in the XenStore. + * + * \param dev The device which encountered the error. + * \param err The errno value corresponding to the error. + * \param fmt Printf format string followed by a variable number of + * printf arguments. + */ +void xenbus_dev_error(device_t dev, int err, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); + +/** + * va_list version of xenbus_dev_error(). + * + * \param dev The device which encountered the error. + * \param err The errno value corresponding to the error. + * \param fmt Printf format string. + * \param ap Va_list of printf arguments. + */ +void xenbus_dev_verror(device_t dev, int err, const char *fmt, va_list ap) + __attribute__((format(printf, 3, 0))); + +/** + * Equivalent to xenbus_dev_error(), followed by + * xenbus_set_state(dev, XenbusStateClosing). + * + * \param dev The device which encountered the error. + * \param err The errno value corresponding to the error. + * \param fmt Printf format string followed by a variable number of + * printf arguments. + */ +void xenbus_dev_fatal(device_t dev, int err, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); + +/** + * va_list version of xenbus_dev_fatal(). + * + * \param dev The device which encountered the error. + * \param err The errno value corresponding to the error. + * \param fmt Printf format string. + * \param ap Va_list of printf arguments. + */ +void xenbus_dev_vfatal(device_t dev, int err, const char *fmt, va_list) + __attribute__((format(printf, 3, 0))); + +/** + * Convert a member of the xenbus_state enum into an ASCII string. + * + * /param state The XenBus state to lookup. + * + * /return A string representing state or, for unrecognized states, + * the string "Unknown". + */ const char *xenbus_strstate(enum xenbus_state state); + +/** + * Return the value of a XenBus device's "online" node within the XenStore. + * + * \param dev The XenBus device to query. + * + * \return The value of the "online" node for the device. If the node + * does not exist, 0 (offline) is returned. + */ int xenbus_dev_is_online(device_t dev); -int xenbus_frontend_closed(device_t dev); #endif /* _XEN_XENBUS_XENBUSVAR_H */ diff --git a/sys/xen/xenstore/xenstore.c b/sys/xen/xenstore/xenstore.c new file mode 100644 index 00000000000..76dfb5a576b --- /dev/null +++ b/sys/xen/xenstore/xenstore.c @@ -0,0 +1,1654 @@ +/****************************************************************************** + * xenstore.c + * + * Low-level kernel interface to the XenStore. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2009,2010 Spectra Logic Corporation + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +/** + * \file xenstore.c + * \brief XenStore interface + * + * The XenStore interface is a simple storage system that is a means of + * communicating state and configuration data between the Xen Domain 0 + * and the various guest domains. All configuration data other than + * a small amount of essential information required during the early + * boot process of launching a Xen aware guest, is managed using the + * XenStore. + * + * The XenStore is ASCII string based, and has a structure and semantics + * similar to a filesystem. There are files and directories, the directories + * able to contain files or other directories. The depth of the hierachy + * is only limited by the XenStore's maximum path length. + * + * The communication channel between the XenStore service and other + * domains is via two, guest specific, ring buffers in a shared memory + * area. One ring buffer is used for communicating in each direction. + * The grant table references for this shared memory are given to the + * guest either via the xen_start_info structure for a fully para- + * virtualized guest, or via HVM hypercalls for a hardware virtualized + * guest. + * + * The XenStore communication relies on an event channel and thus + * interrupts. For this reason, the attachment of the XenStore + * relies on an interrupt driven configuration hook to hold off + * boot processing until communication with the XenStore service + * can be established. + * + * Several Xen services depend on the XenStore, most notably the + * XenBus used to discover and manage Xen devices. These services + * are implemented as NewBus child attachments to a bus exported + * by this XenStore driver. + */ + +static struct xs_watch *find_watch(const char *token); + +MALLOC_DEFINE(M_XENSTORE, "xenstore", "XenStore data and results"); + +/** + * Pointer to shared memory communication structures allowing us + * to communicate with the XenStore service. + * + * When operating in full PV mode, this pointer is set early in kernel + * startup from within xen_machdep.c. In HVM mode, we use hypercalls + * to get the guest frame number for the shared page and then map it + * into kva. See xs_init() for details. + */ +struct xenstore_domain_interface *xen_store; + +/*-------------------------- Private Data Structures ------------------------*/ + +/** + * Structure capturing messages received from the XenStore service. + */ +struct xs_stored_msg { + TAILQ_ENTRY(xs_stored_msg) list; + + struct xsd_sockmsg hdr; + + union { + /* Queued replies. */ + struct { + char *body; + } reply; + + /* Queued watch events. */ + struct { + struct xs_watch *handle; + const char **vec; + u_int vec_size; + } watch; + } u; +}; +TAILQ_HEAD(xs_stored_msg_list, xs_stored_msg); + +/** + * Container for all XenStore related state. + */ +struct xs_softc { + /** Newbus device for the XenStore. */ + device_t xs_dev; + + /** + * Lock serializing access to ring producer/consumer + * indexes. Use of this lock guarantees that wakeups + * of blocking readers/writers are not missed due to + * races with the XenStore service. + */ + struct mtx ring_lock; + + /* + * Mutex used to insure exclusive access to the outgoing + * communication ring. We use a lock type that can be + * held while sleeping so that xs_write() can block waiting + * for space in the ring to free up, without allowing another + * writer to come in and corrupt a partial message write. + */ + struct sx request_mutex; + + /** + * A list of replies to our requests. + * + * The reply list is filled by xs_rcv_thread(). It + * is consumed by the context that issued the request + * to which a reply is made. The requester blocks in + * xs_read_reply(). + * + * /note Only one requesting context can be active at a time. + * This is guaranteed by the request_mutex and insures + * that the requester sees replies matching the order + * of its requests. + */ + struct xs_stored_msg_list reply_list; + + /** Lock protecting the reply list. */ + struct mtx reply_lock; + + /** + * List of registered watches. + */ + struct xs_watch_list registered_watches; + + /** Lock protecting the registered watches list. */ + struct mtx registered_watches_lock; + + /** + * List of pending watch callback events. + */ + struct xs_stored_msg_list watch_events; + + /** Lock protecting the watch calback list. */ + struct mtx watch_events_lock; + + /** + * Sleepable lock used to prevent VM suspension while a + * xenstore transaction is outstanding. + * + * Each active transaction holds a shared lock on the + * suspend mutex. Our suspend method blocks waiting + * to acquire an exclusive lock. This guarantees that + * suspend processing will only proceed once all active + * transactions have been retired. + */ + struct sx suspend_mutex; + + /** + * The processid of the xenwatch thread. + */ + pid_t xenwatch_pid; + + /** + * Sleepable mutex used to gate the execution of XenStore + * watch event callbacks. + * + * xenwatch_thread holds an exclusive lock on this mutex + * while delivering event callbacks, and xenstore_unregister_watch() + * uses an exclusive lock of this mutex to guarantee that no + * callbacks of the just unregistered watch are pending + * before returning to its caller. + */ + struct sx xenwatch_mutex; + +#ifdef XENHVM + /** + * The HVM guest pseudo-physical frame number. This is Xen's mapping + * of the true machine frame number into our "physical address space". + */ + unsigned long gpfn; +#endif + + /** + * The event channel for communicating with the + * XenStore service. + */ + int evtchn; + + /** Interrupt number for our event channel. */ + u_int irq; + + /** + * Interrupt driven config hook allowing us to defer + * attaching children until interrupts (and thus communication + * with the XenStore service) are available. + */ + struct intr_config_hook xs_attachcb; +}; + +/*-------------------------------- Global Data ------------------------------*/ +static struct xs_softc xs; + +/*------------------------- Private Utility Functions -----------------------*/ + +/** + * Count and optionally record pointers to a number of NUL terminated + * strings in a buffer. + * + * \param strings A pointer to a contiguous buffer of NUL terminated strings. + * \param dest An array to store pointers to each string found in strings. + * \param len The length of the buffer pointed to by strings. + * + * \return A count of the number of strings found. + */ +static u_int +extract_strings(const char *strings, const char **dest, u_int len) +{ + u_int num; + const char *p; + + for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) { + if (dest != NULL) + *dest++ = p; + num++; + } + + return (num); +} + +/** + * Convert a contiguous buffer containing a series of NUL terminated + * strings into an array of pointers to strings. + * + * The returned pointer references the array of string pointers which + * is followed by the storage for the string data. It is the client's + * responsibility to free this storage. + * + * The storage addressed by strings is free'd prior to split returning. + * + * \param strings A pointer to a contiguous buffer of NUL terminated strings. + * \param len The length of the buffer pointed to by strings. + * \param num The number of strings found and returned in the strings + * array. + * + * \return An array of pointers to the strings found in the input buffer. + */ +static const char ** +split(char *strings, u_int len, u_int *num) +{ + const char **ret; + + /* Protect against unterminated buffers. */ + strings[len - 1] = '\0'; + + /* Count the strings. */ + *num = extract_strings(strings, /*dest*/NULL, len); + + /* Transfer to one big alloc for easy freeing by the caller. */ + ret = malloc(*num * sizeof(char *) + len, M_XENSTORE, M_WAITOK); + memcpy(&ret[*num], strings, len); + free(strings, M_XENSTORE); + + /* Extract pointers to newly allocated array. */ + strings = (char *)&ret[*num]; + (void)extract_strings(strings, /*dest*/ret, len); + + return (ret); +} + +/*------------------------- Public Utility Functions -------------------------*/ +/*------- API comments for these methods can be found in xenstorevar.h -------*/ +struct sbuf * +xs_join(const char *dir, const char *name) +{ + struct sbuf *sb; + + sb = sbuf_new_auto(); + sbuf_cat(sb, dir); + if (name[0] != '\0') { + sbuf_putc(sb, '/'); + sbuf_cat(sb, name); + } + sbuf_finish(sb); + + return (sb); +} + +/*-------------------- Low Level Communication Management --------------------*/ +/** + * Interrupt handler for the XenStore event channel. + * + * XenStore reads and writes block on "xen_store" for buffer + * space. Wakeup any blocking operations when the XenStore + * service has modified the queues. + */ +static void +xs_intr(void * arg __unused /*__attribute__((unused))*/) +{ + + /* + * Hold ring lock across wakeup so that clients + * cannot miss a wakeup. + */ + mtx_lock(&xs.ring_lock); + wakeup(xen_store); + mtx_unlock(&xs.ring_lock); +} + +/** + * Verify that the indexes for a ring are valid. + * + * The difference between the producer and consumer cannot + * exceed the size of the ring. + * + * \param cons The consumer index for the ring to test. + * \param prod The producer index for the ring to test. + * + * \retval 1 If indexes are in range. + * \retval 0 If the indexes are out of range. + */ +static int +xs_check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) +{ + + return ((prod - cons) <= XENSTORE_RING_SIZE); +} + +/** + * Return a pointer to, and the length of, the contiguous + * free region available for output in a ring buffer. + * + * \param cons The consumer index for the ring. + * \param prod The producer index for the ring. + * \param buf The base address of the ring's storage. + * \param len The amount of contiguous storage available. + * + * \return A pointer to the start location of the free region. + */ +static void * +xs_get_output_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, + char *buf, uint32_t *len) +{ + + *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); + if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) + *len = XENSTORE_RING_SIZE - (prod - cons); + return (buf + MASK_XENSTORE_IDX(prod)); +} + +/** + * Return a pointer to, and the length of, the contiguous + * data available to read from a ring buffer. + * + * \param cons The consumer index for the ring. + * \param prod The producer index for the ring. + * \param buf The base address of the ring's storage. + * \param len The amount of contiguous data available to read. + * + * \return A pointer to the start location of the available data. + */ +static const void * +xs_get_input_chunk(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod, + const char *buf, uint32_t *len) +{ + + *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); + if ((prod - cons) < *len) + *len = prod - cons; + return (buf + MASK_XENSTORE_IDX(cons)); +} + +/** + * Transmit data to the XenStore service. + * + * \param tdata A pointer to the contiguous data to send. + * \param len The amount of data to send. + * + * \return On success 0, otherwise an errno value indicating the + * cause of failure. + * + * \invariant Called from thread context. + * \invariant The buffer pointed to by tdata is at least len bytes + * in length. + * \invariant xs.request_mutex exclusively locked. + */ +static int +xs_write_store(const void *tdata, unsigned len) +{ + XENSTORE_RING_IDX cons, prod; + const char *data = (const char *)tdata; + int error; + + sx_assert(&xs.request_mutex, SX_XLOCKED); + while (len != 0) { + void *dst; + u_int avail; + + /* Hold lock so we can't miss wakeups should we block. */ + mtx_lock(&xs.ring_lock); + cons = xen_store->req_cons; + prod = xen_store->req_prod; + if ((prod - cons) == XENSTORE_RING_SIZE) { + /* + * Output ring is full. Wait for a ring event. + * + * Note that the events from both queues + * are combined, so being woken does not + * guarantee that data exist in the read + * ring. + * + * To simplify error recovery and the retry, + * we specify PDROP so our lock is *not* held + * when msleep returns. + */ + error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP, + "xbwrite", /*timeout*/0); + if (error && error != EWOULDBLOCK) + return (error); + + /* Try again. */ + continue; + } + mtx_unlock(&xs.ring_lock); + + /* Verify queue sanity. */ + if (!xs_check_indexes(cons, prod)) { + xen_store->req_cons = xen_store->req_prod = 0; + return (EIO); + } + + dst = xs_get_output_chunk(cons, prod, xen_store->req, &avail); + if (avail > len) + avail = len; + + memcpy(dst, data, avail); + data += avail; + len -= avail; + + /* + * The store to the producer index, which indicates + * to the other side that new data has arrived, must + * be visible only after our copy of the data into the + * ring has completed. + */ + wmb(); + xen_store->req_prod += avail; + + /* + * notify_remote_via_evtchn implies mb(). The other side + * will see the change to req_prod at the time of the + * interrupt. + */ + notify_remote_via_evtchn(xs.evtchn); + } + + return (0); +} + +/** + * Receive data from the XenStore service. + * + * \param tdata A pointer to the contiguous buffer to receive the data. + * \param len The amount of data to receive. + * + * \return On success 0, otherwise an errno value indicating the + * cause of failure. + * + * \invariant Called from thread context. + * \invariant The buffer pointed to by tdata is at least len bytes + * in length. + * + * \note xs_read does not perform any internal locking to guarantee + * serial access to the incoming ring buffer. However, there + * is only one context processing reads: xs_rcv_thread(). + */ +static int +xs_read_store(void *tdata, unsigned len) +{ + XENSTORE_RING_IDX cons, prod; + char *data = (char *)tdata; + int error; + + while (len != 0) { + u_int avail; + const char *src; + + /* Hold lock so we can't miss wakeups should we block. */ + mtx_lock(&xs.ring_lock); + cons = xen_store->rsp_cons; + prod = xen_store->rsp_prod; + if (cons == prod) { + /* + * Nothing to read. Wait for a ring event. + * + * Note that the events from both queues + * are combined, so being woken does not + * guarantee that data exist in the read + * ring. + * + * To simplify error recovery and the retry, + * we specify PDROP so our lock is *not* held + * when msleep returns. + */ + error = msleep(xen_store, &xs.ring_lock, PCATCH|PDROP, + "xbread", /*timout*/0); + if (error && error != EWOULDBLOCK) + return (error); + continue; + } + mtx_unlock(&xs.ring_lock); + + /* Verify queue sanity. */ + if (!xs_check_indexes(cons, prod)) { + xen_store->rsp_cons = xen_store->rsp_prod = 0; + return (EIO); + } + + src = xs_get_input_chunk(cons, prod, xen_store->rsp, &avail); + if (avail > len) + avail = len; + + /* + * Insure the data we read is related to the indexes + * we read above. + */ + rmb(); + + memcpy(data, src, avail); + data += avail; + len -= avail; + + /* + * Insure that the producer of this ring does not see + * the ring space as free until after we have copied it + * out. + */ + mb(); + xen_store->rsp_cons += avail; + + /* + * notify_remote_via_evtchn implies mb(). The producer + * will see the updated consumer index when the event + * is delivered. + */ + notify_remote_via_evtchn(xs.evtchn); + } + + return (0); +} + +/*----------------------- Received Message Processing ------------------------*/ +/** + * Block reading the next message from the XenStore service and + * process the result. + * + * \param type The returned type of the XenStore message received. + * + * \return 0 on success. Otherwise an errno value indicating the + * type of failure encountered. + */ +static int +xs_process_msg(enum xsd_sockmsg_type *type) +{ + struct xs_stored_msg *msg; + char *body; + int error; + + msg = malloc(sizeof(*msg), M_XENSTORE, M_WAITOK); + error = xs_read_store(&msg->hdr, sizeof(msg->hdr)); + if (error) { + free(msg, M_XENSTORE); + return (error); + } + + body = malloc(msg->hdr.len + 1, M_XENSTORE, M_WAITOK); + error = xs_read_store(body, msg->hdr.len); + if (error) { + free(body, M_XENSTORE); + free(msg, M_XENSTORE); + return (error); + } + body[msg->hdr.len] = '\0'; + + *type = msg->hdr.type; + if (msg->hdr.type == XS_WATCH_EVENT) { + msg->u.watch.vec = split(body, msg->hdr.len, + &msg->u.watch.vec_size); + + mtx_lock(&xs.registered_watches_lock); + msg->u.watch.handle = find_watch( + msg->u.watch.vec[XS_WATCH_TOKEN]); + if (msg->u.watch.handle != NULL) { + mtx_lock(&xs.watch_events_lock); + TAILQ_INSERT_TAIL(&xs.watch_events, msg, list); + wakeup(&xs.watch_events); + mtx_unlock(&xs.watch_events_lock); + } else { + free(msg->u.watch.vec, M_XENSTORE); + free(msg, M_XENSTORE); + } + mtx_unlock(&xs.registered_watches_lock); + } else { + msg->u.reply.body = body; + mtx_lock(&xs.reply_lock); + TAILQ_INSERT_TAIL(&xs.reply_list, msg, list); + wakeup(&xs.reply_list); + mtx_unlock(&xs.reply_lock); + } + + return (0); +} + +/** + * Thread body of the XenStore receive thread. + * + * This thread blocks waiting for data from the XenStore service + * and processes and received messages. + */ +static void +xs_rcv_thread(void *arg __unused) +{ + int error; + enum xsd_sockmsg_type type; + + for (;;) { + error = xs_process_msg(&type); + if (error) + printf("XENSTORE error %d while reading message\n", + error); + } +} + +/*---------------- XenStore Message Request/Reply Processing -----------------*/ +/** + * Filter invoked before transmitting any message to the XenStore service. + * + * The role of the filter may expand, but currently serves to manage + * the interactions of messages with transaction state. + * + * \param request_msg_type The message type for the request. + */ +static inline void +xs_request_filter(uint32_t request_msg_type) +{ + if (request_msg_type == XS_TRANSACTION_START) + sx_slock(&xs.suspend_mutex); +} + +/** + * Filter invoked after transmitting any message to the XenStore service. + * + * The role of the filter may expand, but currently serves to manage + * the interactions of messages with transaction state. + * + * \param request_msg_type The message type for the original request. + * \param reply_msg_type The message type for any received reply. + * \param request_reply_error The error status from the attempt to send + * the request or retrieve the reply. + */ +static inline void +xs_reply_filter(uint32_t request_msg_type, + uint32_t reply_msg_type, int request_reply_error) +{ + /* + * The count of transactions drops if we attempted + * to end a transaction (even if that attempt fails + * in error), we receive a transaction end acknowledgement + * or if our attempt to begin a transactionfails. + */ + if (request_msg_type == XS_TRANSACTION_END + || (request_reply_error == 0 && reply_msg_type == XS_TRANSACTION_END) + || (request_msg_type == XS_TRANSACTION_START + && (request_reply_error != 0 || reply_msg_type == XS_ERROR))) + sx_sunlock(&xs.suspend_mutex); + +} + +#define xsd_error_count (sizeof(xsd_errors) / sizeof(xsd_errors[0])) + +/** + * Convert a XenStore error string into an errno number. + * + * \param errorstring The error string to convert. + * + * \return The errno best matching the input string. + * + * \note Unknown error strings are converted to EINVAL. + */ +static int +xs_get_error(const char *errorstring) +{ + u_int i; + + for (i = 0; i < xsd_error_count; i++) { + if (!strcmp(errorstring, xsd_errors[i].errstring)) + return (xsd_errors[i].errnum); + } + log(LOG_WARNING, "XENSTORE xen store gave: unknown error %s", + errorstring); + return (EINVAL); +} + +/** + * Block waiting for a reply to a message request. + * + * \param type The returned type of the reply. + * \param len The returned body length of the reply. + * \param result The returned body of the reply. + * + * \return 0 on success. Otherwise an errno indicating the + * cause of failure. + */ +static int +xs_read_reply(enum xsd_sockmsg_type *type, u_int *len, void **result) +{ + struct xs_stored_msg *msg; + char *body; + int error; + + mtx_lock(&xs.reply_lock); + while (TAILQ_EMPTY(&xs.reply_list)) { + error = mtx_sleep(&xs.reply_list, &xs.reply_lock, + PCATCH, "xswait", hz/10); + if (error && error != EWOULDBLOCK) { + mtx_unlock(&xs.reply_lock); + return (error); + } + } + msg = TAILQ_FIRST(&xs.reply_list); + TAILQ_REMOVE(&xs.reply_list, msg, list); + mtx_unlock(&xs.reply_lock); + + *type = msg->hdr.type; + if (len) + *len = msg->hdr.len; + body = msg->u.reply.body; + + free(msg, M_XENSTORE); + *result = body; + return (0); +} + +/** + * Pass-thru interface for XenStore access by userland processes + * via the XenStore device. + * + * Reply type and length data are returned by overwriting these + * fields in the passed in request message. + * + * \param msg A properly formatted message to transmit to + * the XenStore service. + * \param result The returned body of the reply. + * + * \return 0 on success. Otherwise an errno indicating the cause + * of failure. + * + * \note The returned result is provided in malloced storage and thus + * must be free'd by the caller with 'free(result, M_XENSTORE); + */ +int +xs_dev_request_and_reply(struct xsd_sockmsg *msg, void **result) +{ + uint32_t request_type; + int error; + + request_type = msg->type; + xs_request_filter(request_type); + + sx_xlock(&xs.request_mutex); + if ((error = xs_write_store(msg, sizeof(*msg) + msg->len)) == 0) + error = xs_read_reply(&msg->type, &msg->len, result); + sx_xunlock(&xs.request_mutex); + + xs_reply_filter(request_type, msg->type, error); + + return (error); +} + +/** + * Send a message with an optionally muti-part body to the XenStore service. + * + * \param t The transaction to use for this request. + * \param request_type The type of message to send. + * \param iovec Pointers to the body sections of the request. + * \param num_vecs The number of body sections in the request. + * \param len The returned length of the reply. + * \param result The returned body of the reply. + * + * \return 0 on success. Otherwise an errno indicating + * the cause of failure. + * + * \note The returned result is provided in malloced storage and thus + * must be free'd by the caller with 'free(*result, M_XENSTORE); + */ +static int +xs_talkv(struct xs_transaction t, enum xsd_sockmsg_type request_type, + const struct iovec *iovec, u_int num_vecs, u_int *len, void **result) +{ + struct xsd_sockmsg msg; + void *ret = NULL; + u_int i; + int error; + + msg.tx_id = t.id; + msg.req_id = 0; + msg.type = request_type; + msg.len = 0; + for (i = 0; i < num_vecs; i++) + msg.len += iovec[i].iov_len; + + xs_request_filter(request_type); + + sx_xlock(&xs.request_mutex); + error = xs_write_store(&msg, sizeof(msg)); + if (error) { + printf("xs_talkv failed %d\n", error); + goto error_lock_held; + } + + for (i = 0; i < num_vecs; i++) { + error = xs_write_store(iovec[i].iov_base, iovec[i].iov_len); + if (error) { + printf("xs_talkv failed %d\n", error); + goto error_lock_held; + } + } + + error = xs_read_reply(&msg.type, len, &ret); + +error_lock_held: + sx_xunlock(&xs.request_mutex); + xs_reply_filter(request_type, msg.type, error); + if (error) + return (error); + + if (msg.type == XS_ERROR) { + error = xs_get_error(ret); + free(ret, M_XENSTORE); + return (error); + } + + /* Reply is either error or an echo of our request message type. */ + KASSERT(msg.type == request_type, ("bad xenstore message type")); + + if (result) + *result = ret; + else + free(ret, M_XENSTORE); + + return (0); +} + +/** + * Wrapper for xs_talkv allowing easy transmission of a message with + * a single, contiguous, message body. + * + * \param t The transaction to use for this request. + * \param request_type The type of message to send. + * \param body The body of the request. + * \param len The returned length of the reply. + * \param result The returned body of the reply. + * + * \return 0 on success. Otherwise an errno indicating + * the cause of failure. + * + * \note The returned result is provided in malloced storage and thus + * must be free'd by the caller with 'free(*result, M_XENSTORE); + */ +static int +xs_single(struct xs_transaction t, enum xsd_sockmsg_type request_type, + const char *body, u_int *len, void **result) +{ + struct iovec iovec; + + iovec.iov_base = (void *)(uintptr_t)body; + iovec.iov_len = strlen(body) + 1; + + return (xs_talkv(t, request_type, &iovec, 1, len, result)); +} + +/*------------------------- XenStore Watch Support ---------------------------*/ +/** + * Transmit a watch request to the XenStore service. + * + * \param path The path in the XenStore to watch. + * \param tocken A unique identifier for this watch. + * + * \return 0 on success. Otherwise an errno indicating the + * cause of failure. + */ +static int +xs_watch(const char *path, const char *token) +{ + struct iovec iov[2]; + + iov[0].iov_base = (void *)(uintptr_t) path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)(uintptr_t) token; + iov[1].iov_len = strlen(token) + 1; + + return (xs_talkv(XST_NIL, XS_WATCH, iov, 2, NULL, NULL)); +} + +/** + * Transmit an uwatch request to the XenStore service. + * + * \param path The path in the XenStore to watch. + * \param tocken A unique identifier for this watch. + * + * \return 0 on success. Otherwise an errno indicating the + * cause of failure. + */ +static int +xs_unwatch(const char *path, const char *token) +{ + struct iovec iov[2]; + + iov[0].iov_base = (void *)(uintptr_t) path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)(uintptr_t) token; + iov[1].iov_len = strlen(token) + 1; + + return (xs_talkv(XST_NIL, XS_UNWATCH, iov, 2, NULL, NULL)); +} + +/** + * Convert from watch token (unique identifier) to the associated + * internal tracking structure for this watch. + * + * \param tocken The unique identifier for the watch to find. + * + * \return A pointer to the found watch structure or NULL. + */ +static struct xs_watch * +find_watch(const char *token) +{ + struct xs_watch *i, *cmp; + + cmp = (void *)strtoul(token, NULL, 16); + + LIST_FOREACH(i, &xs.registered_watches, list) + if (i == cmp) + return (i); + + return (NULL); +} + +/** + * Thread body of the XenStore watch event dispatch thread. + */ +static void +xenwatch_thread(void *unused) +{ + struct xs_stored_msg *msg; + + for (;;) { + + mtx_lock(&xs.watch_events_lock); + while (TAILQ_EMPTY(&xs.watch_events)) + mtx_sleep(&xs.watch_events, + &xs.watch_events_lock, + PWAIT | PCATCH, "waitev", hz/10); + + mtx_unlock(&xs.watch_events_lock); + sx_xlock(&xs.xenwatch_mutex); + + mtx_lock(&xs.watch_events_lock); + msg = TAILQ_FIRST(&xs.watch_events); + if (msg) + TAILQ_REMOVE(&xs.watch_events, msg, list); + mtx_unlock(&xs.watch_events_lock); + + if (msg != NULL) { + /* + * XXX There are messages coming in with a NULL + * XXX callback. This deserves further investigation; + * XXX the workaround here simply prevents the kernel + * XXX from panic'ing on startup. + */ + if (msg->u.watch.handle->callback != NULL) + msg->u.watch.handle->callback( + msg->u.watch.handle, + (const char **)msg->u.watch.vec, + msg->u.watch.vec_size); + free(msg->u.watch.vec, M_XENSTORE); + free(msg, M_XENSTORE); + } + + sx_xunlock(&xs.xenwatch_mutex); + } +} + +/*----------- XenStore Configuration, Initialization, and Control ------------*/ +/** + * Setup communication channels with the XenStore service. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +static int +xs_init_comms(void) +{ + int error; + + if (xen_store->rsp_prod != xen_store->rsp_cons) { + log(LOG_WARNING, "XENSTORE response ring is not quiescent " + "(%08x:%08x): fixing up\n", + xen_store->rsp_cons, xen_store->rsp_prod); + xen_store->rsp_cons = xen_store->rsp_prod; + } + + if (xs.irq) + unbind_from_irqhandler(xs.irq); + + error = bind_caller_port_to_irqhandler(xs.evtchn, "xenstore", + xs_intr, NULL, INTR_TYPE_NET, &xs.irq); + if (error) { + log(LOG_WARNING, "XENSTORE request irq failed %i\n", error); + return (error); + } + + return (0); +} + +/*------------------ Private Device Attachment Functions --------------------*/ +static void +xs_identify(driver_t *driver, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "xenstore", 0); +} + +/** + * Probe for the existance of the XenStore. + * + * \param dev + */ +static int +xs_probe(device_t dev) +{ + /* + * We are either operating within a PV kernel or being probed + * as the child of the successfully attached xenpci device. + * Thus we are in a Xen environment and there will be a XenStore. + * Uncontitionally return success. + */ + device_set_desc(dev, "XenStore"); +printf("xs_probe: Probe retuns 0\n"); + return (0); +} + +static void +xs_attach_deferred(void *arg) +{ + xs_dev_init(); + + bus_generic_probe(xs.xs_dev); + bus_generic_attach(xs.xs_dev); + + config_intrhook_disestablish(&xs.xs_attachcb); +} + +/** + * Attach to the XenStore. + * + * This routine also prepares for the probe/attach of drivers that rely + * on the XenStore. + */ +static int +xs_attach(device_t dev) +{ + int error; + + /* Allow us to get device_t from softc and vice-versa. */ + xs.xs_dev = dev; + device_set_softc(dev, &xs); + + /* + * This seems to be a layering violation. The XenStore is just + * one of many clients of the Grant Table facility. It happens + * to be the first and a gating consumer to all other devices, + * so this does work. A better place would be in the PV support + * code for fully PV kernels and the xenpci driver for HVM kernels. + */ + error = gnttab_init(); + if (error != 0) { + log(LOG_WARNING, + "XENSTORE: Error initializing grant tables: %d\n", error); + return (ENXIO); + } + + /* Initialize the interface to xenstore. */ + struct proc *p; + +#ifdef XENHVM + xs.evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN); + xs.gpfn = hvm_get_parameter(HVM_PARAM_STORE_PFN); + xen_store = pmap_mapdev(xs.gpfn * PAGE_SIZE, PAGE_SIZE); +#else + xs.evtchn = xen_start_info->store_evtchn; +#endif + + TAILQ_INIT(&xs.reply_list); + TAILQ_INIT(&xs.watch_events); + + mtx_init(&xs.ring_lock, "ring lock", NULL, MTX_DEF); + mtx_init(&xs.reply_lock, "reply lock", NULL, MTX_DEF); + sx_init(&xs.xenwatch_mutex, "xenwatch"); + sx_init(&xs.request_mutex, "xenstore request"); + sx_init(&xs.suspend_mutex, "xenstore suspend"); + mtx_init(&xs.registered_watches_lock, "watches", NULL, MTX_DEF); + mtx_init(&xs.watch_events_lock, "watch events", NULL, MTX_DEF); + xs.irq = 0; + + /* Initialize the shared memory rings to talk to xenstored */ + error = xs_init_comms(); + if (error) + return (error); + + error = kproc_create(xenwatch_thread, NULL, &p, RFHIGHPID, + 0, "xenwatch"); + if (error) + return (error); + xs.xenwatch_pid = p->p_pid; + + error = kproc_create(xs_rcv_thread, NULL, NULL, + RFHIGHPID, 0, "xenstore_rcv"); + + xs.xs_attachcb.ich_func = xs_attach_deferred; + xs.xs_attachcb.ich_arg = NULL; + config_intrhook_establish(&xs.xs_attachcb); + + return (error); +} + +/** + * Prepare for suspension of this VM by halting XenStore access after + * all transactions and individual requests have completed. + */ +static int +xs_suspend(device_t dev __unused) +{ + + sx_xlock(&xs.suspend_mutex); + sx_xlock(&xs.request_mutex); + + return (0); +} + +/** + * Resume XenStore operations after this VM is resumed. + */ +static int +xs_resume(device_t dev __unused) +{ + struct xs_watch *watch; + char token[sizeof(watch) * 2 + 1]; + + xs_init_comms(); + + sx_xunlock(&xs.request_mutex); + + /* + * No need for registered_watches_lock: the suspend_mutex + * is sufficient. + */ + LIST_FOREACH(watch, &xs.registered_watches, list) { + sprintf(token, "%lX", (long)watch); + xs_watch(watch->node, token); + } + + sx_xunlock(&xs.suspend_mutex); + + return (0); +} + +/*-------------------- Private Device Attachment Data -----------------------*/ +static device_method_t xenstore_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, xs_identify), + DEVMETHOD(device_probe, xs_probe), + DEVMETHOD(device_attach, xs_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, xs_suspend), + DEVMETHOD(device_resume, xs_resume), + + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + { 0, 0 } +}; + +DEFINE_CLASS_0(xenstore, xenstore_driver, xenstore_methods, 0); +static devclass_t xenstore_devclass; + +#ifdef XENHVM +DRIVER_MODULE(xenstore, xenpci, xenstore_driver, xenstore_devclass, 0, 0); +#else +DRIVER_MODULE(xenstore, nexus, xenstore_driver, xenstore_devclass, 0, 0); +#endif + +/*------------------------------- Sysctl Data --------------------------------*/ +/* XXX Shouldn't the node be somewhere else? */ +SYSCTL_NODE(_dev, OID_AUTO, xen, CTLFLAG_RD, NULL, "Xen"); +SYSCTL_INT(_dev_xen, OID_AUTO, xsd_port, CTLFLAG_RD, &xs.evtchn, 0, ""); +SYSCTL_ULONG(_dev_xen, OID_AUTO, xsd_kva, CTLFLAG_RD, (u_long *) &xen_store, 0, ""); + +/*-------------------------------- Public API --------------------------------*/ +/*------- API comments for these methods can be found in xenstorevar.h -------*/ +int +xs_directory(struct xs_transaction t, const char *dir, const char *node, + u_int *num, const char ***result) +{ + struct sbuf *path; + char *strings; + u_int len = 0; + int error; + + path = xs_join(dir, node); + error = xs_single(t, XS_DIRECTORY, sbuf_data(path), &len, + (void **)&strings); + sbuf_delete(path); + if (error) + return (error); + + *result = split(strings, len, num); + + return (0); +} + +int +xs_exists(struct xs_transaction t, const char *dir, const char *node) +{ + const char **d; + int error, dir_n; + + error = xs_directory(t, dir, node, &dir_n, &d); + if (error) + return (0); + free(d, M_XENSTORE); + return (1); +} + +int +xs_read(struct xs_transaction t, const char *dir, const char *node, + u_int *len, void **result) +{ + struct sbuf *path; + void *ret; + int error; + + path = xs_join(dir, node); + error = xs_single(t, XS_READ, sbuf_data(path), len, &ret); + sbuf_delete(path); + if (error) + return (error); + *result = ret; + return (0); +} + +int +xs_write(struct xs_transaction t, const char *dir, const char *node, + const char *string) +{ + struct sbuf *path; + struct iovec iovec[2]; + int error; + + path = xs_join(dir, node); + + iovec[0].iov_base = (void *)(uintptr_t) sbuf_data(path); + iovec[0].iov_len = sbuf_len(path) + 1; + iovec[1].iov_base = (void *)(uintptr_t) string; + iovec[1].iov_len = strlen(string); + + error = xs_talkv(t, XS_WRITE, iovec, 2, NULL, NULL); + sbuf_delete(path); + + return (error); +} + +int +xs_mkdir(struct xs_transaction t, const char *dir, const char *node) +{ + struct sbuf *path; + int ret; + + path = xs_join(dir, node); + ret = xs_single(t, XS_MKDIR, sbuf_data(path), NULL, NULL); + sbuf_delete(path); + + return (ret); +} + +int +xs_rm(struct xs_transaction t, const char *dir, const char *node) +{ + struct sbuf *path; + int ret; + + path = xs_join(dir, node); + ret = xs_single(t, XS_RM, sbuf_data(path), NULL, NULL); + sbuf_delete(path); + + return (ret); +} + +int +xs_rm_tree(struct xs_transaction xbt, const char *base, const char *node) +{ + struct xs_transaction local_xbt; + struct sbuf *root_path_sbuf; + struct sbuf *cur_path_sbuf; + char *root_path; + char *cur_path; + const char **dir; + int error; + int empty; + +retry: + root_path_sbuf = xs_join(base, node); + cur_path_sbuf = xs_join(base, node); + root_path = sbuf_data(root_path_sbuf); + cur_path = sbuf_data(cur_path_sbuf); + dir = NULL; + local_xbt.id = 0; + + if (xbt.id == 0) { + error = xs_transaction_start(&local_xbt); + if (error != 0) + goto out; + xbt = local_xbt; + } + + empty = 0; + while (1) { + u_int count; + u_int i; + + error = xs_directory(xbt, cur_path, "", &count, &dir); + if (error) + goto out; + + for (i = 0; i < count; i++) { + error = xs_rm(xbt, cur_path, dir[i]); + if (error == ENOTEMPTY) { + struct sbuf *push_dir; + + /* + * Descend to clear out this sub directory. + * We'll return to cur_dir once push_dir + * is empty. + */ + push_dir = xs_join(cur_path, dir[i]); + sbuf_delete(cur_path_sbuf); + cur_path_sbuf = push_dir; + cur_path = sbuf_data(cur_path_sbuf); + break; + } else if (error != 0) { + goto out; + } + } + + free(dir, M_XENSTORE); + dir = NULL; + + if (i == count) { + char *last_slash; + + /* Directory is empty. It is now safe to remove. */ + error = xs_rm(xbt, cur_path, ""); + if (error != 0) + goto out; + + if (!strcmp(cur_path, root_path)) + break; + + /* Return to processing the parent directory. */ + last_slash = strrchr(cur_path, '/'); + KASSERT(last_slash != NULL, + ("xs_rm_tree: mangled path %s", cur_path)); + *last_slash = '\0'; + } + } + +out: + sbuf_delete(cur_path_sbuf); + sbuf_delete(root_path_sbuf); + if (dir != NULL) + free(dir, M_XENSTORE); + + if (local_xbt.id != 0) { + int terror; + + terror = xs_transaction_end(local_xbt, /*abort*/error != 0); + xbt.id = 0; + if (terror == EAGAIN && error == 0) + goto retry; + } + return (error); +} + +int +xs_transaction_start(struct xs_transaction *t) +{ + char *id_str; + int error; + + error = xs_single(XST_NIL, XS_TRANSACTION_START, "", NULL, + (void **)&id_str); + if (error == 0) { + t->id = strtoul(id_str, NULL, 0); + free(id_str, M_XENSTORE); + } + return (error); +} + +int +xs_transaction_end(struct xs_transaction t, int abort) +{ + char abortstr[2]; + + if (abort) + strcpy(abortstr, "F"); + else + strcpy(abortstr, "T"); + + return (xs_single(t, XS_TRANSACTION_END, abortstr, NULL, NULL)); +} + +int +xs_scanf(struct xs_transaction t, const char *dir, const char *node, + int *scancountp, const char *fmt, ...) +{ + va_list ap; + int error, ns; + char *val; + + error = xs_read(t, dir, node, NULL, (void **) &val); + if (error) + return (error); + + va_start(ap, fmt); + ns = vsscanf(val, fmt, ap); + va_end(ap); + free(val, M_XENSTORE); + /* Distinctive errno. */ + if (ns == 0) + return (ERANGE); + if (scancountp) + *scancountp = ns; + return (0); +} + +int +xs_vprintf(struct xs_transaction t, + const char *dir, const char *node, const char *fmt, va_list ap) +{ + struct sbuf *sb; + int error; + + sb = sbuf_new_auto(); + sbuf_vprintf(sb, fmt, ap); + sbuf_finish(sb); + error = xs_write(t, dir, node, sbuf_data(sb)); + sbuf_delete(sb); + + return (error); +} + +int +xs_printf(struct xs_transaction t, const char *dir, const char *node, + const char *fmt, ...) +{ + va_list ap; + int error; + + va_start(ap, fmt); + error = xs_vprintf(t, dir, node, fmt, ap); + va_end(ap); + + return (error); +} + +int +xs_gather(struct xs_transaction t, const char *dir, ...) +{ + va_list ap; + const char *name; + int error; + + va_start(ap, dir); + error = 0; + while (error == 0 && (name = va_arg(ap, char *)) != NULL) { + const char *fmt = va_arg(ap, char *); + void *result = va_arg(ap, void *); + char *p; + + error = xs_read(t, dir, name, NULL, (void **) &p); + if (error) + break; + + if (fmt) { + if (sscanf(p, fmt, result) == 0) + error = EINVAL; + free(p, M_XENSTORE); + } else + *(char **)result = p; + } + va_end(ap); + + return (error); +} + +int +xs_register_watch(struct xs_watch *watch) +{ + /* Pointer in ascii is the token. */ + char token[sizeof(watch) * 2 + 1]; + int error; + + sprintf(token, "%lX", (long)watch); + + sx_slock(&xs.suspend_mutex); + + mtx_lock(&xs.registered_watches_lock); + KASSERT(find_watch(token) == NULL, ("watch already registered")); + LIST_INSERT_HEAD(&xs.registered_watches, watch, list); + mtx_unlock(&xs.registered_watches_lock); + + error = xs_watch(watch->node, token); + + /* Ignore errors due to multiple registration. */ + if (error == EEXIST) + error = 0; + + if (error != 0) { + mtx_lock(&xs.registered_watches_lock); + LIST_REMOVE(watch, list); + mtx_unlock(&xs.registered_watches_lock); + } + + sx_sunlock(&xs.suspend_mutex); + + return (error); +} + +void +xs_unregister_watch(struct xs_watch *watch) +{ + struct xs_stored_msg *msg, *tmp; + char token[sizeof(watch) * 2 + 1]; + int error; + + sprintf(token, "%lX", (long)watch); + + sx_slock(&xs.suspend_mutex); + + mtx_lock(&xs.registered_watches_lock); + if (find_watch(token) == NULL) { + mtx_unlock(&xs.registered_watches_lock); + sx_sunlock(&xs.suspend_mutex); + return; + } + LIST_REMOVE(watch, list); + mtx_unlock(&xs.registered_watches_lock); + + error = xs_unwatch(watch->node, token); + if (error) + log(LOG_WARNING, "XENSTORE Failed to release watch %s: %i\n", + watch->node, error); + + sx_sunlock(&xs.suspend_mutex); + + /* Cancel pending watch events. */ + mtx_lock(&xs.watch_events_lock); + TAILQ_FOREACH_SAFE(msg, &xs.watch_events, list, tmp) { + if (msg->u.watch.handle != watch) + continue; + TAILQ_REMOVE(&xs.watch_events, msg, list); + free(msg->u.watch.vec, M_XENSTORE); + free(msg, M_XENSTORE); + } + mtx_unlock(&xs.watch_events_lock); + + /* Flush any currently-executing callback, unless we are it. :-) */ + if (curproc->p_pid != xs.xenwatch_pid) { + sx_xlock(&xs.xenwatch_mutex); + sx_xunlock(&xs.xenwatch_mutex); + } +} diff --git a/sys/xen/xenbus/xenbus_dev.c b/sys/xen/xenstore/xenstore_dev.c similarity index 68% rename from sys/xen/xenbus/xenbus_dev.c rename to sys/xen/xenstore/xenstore_dev.c index ac3f103e1fa..1fa419795ed 100644 --- a/sys/xen/xenbus/xenbus_dev.c +++ b/sys/xen/xenstore/xenstore_dev.c @@ -1,8 +1,8 @@ /* - * xenbus_dev.c + * xenstore_dev.c * - * Driver giving user-space access to the kernel's xenbus connection - * to xenstore. + * Driver giving user-space access to the kernel's connection to the + * XenStore service. * * Copyright (c) 2005, Christian Limpach * Copyright (c) 2005, Rusty Russell, IBM Corporation @@ -45,18 +45,19 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include -struct xenbus_dev_transaction { - LIST_ENTRY(xenbus_dev_transaction) list; - struct xenbus_transaction handle; +#include +#include +#include + +struct xs_dev_transaction { + LIST_ENTRY(xs_dev_transaction) list; + struct xs_transaction handle; }; -struct xenbus_dev_data { +struct xs_dev_data { /* In-progress transaction. */ - LIST_HEAD(xdd_list_head, xenbus_dev_transaction) transactions; + LIST_HEAD(xdd_list_head, xs_dev_transaction) transactions; /* Partial request. */ unsigned int len; @@ -72,13 +73,13 @@ struct xenbus_dev_data { }; static int -xenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag) +xs_dev_read(struct cdev *dev, struct uio *uio, int ioflag) { int error; - struct xenbus_dev_data *u = dev->si_drv1; + struct xs_dev_data *u = dev->si_drv1; while (u->read_prod == u->read_cons) { - error = tsleep(u, PCATCH, "xbdread", hz/10); + error = tsleep(u, PCATCH, "xsdread", hz/10); if (error && error != EWOULDBLOCK) return (error); } @@ -96,7 +97,7 @@ xenbus_dev_read(struct cdev *dev, struct uio *uio, int ioflag) } static void -queue_reply(struct xenbus_dev_data *u, char *data, unsigned int len) +xs_queue_reply(struct xs_dev_data *u, char *data, unsigned int len) { int i; @@ -110,11 +111,11 @@ queue_reply(struct xenbus_dev_data *u, char *data, unsigned int len) } static int -xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) +xs_dev_write(struct cdev *dev, struct uio *uio, int ioflag) { int error; - struct xenbus_dev_data *u = dev->si_drv1; - struct xenbus_dev_transaction *trans; + struct xs_dev_data *u = dev->si_drv1; + struct xs_dev_transaction *trans; void *reply; int len = uio->uio_resid; @@ -141,10 +142,10 @@ xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) case XS_MKDIR: case XS_RM: case XS_SET_PERMS: - error = xenbus_dev_request_and_reply(&u->u.msg, &reply); + error = xs_dev_request_and_reply(&u->u.msg, &reply); if (!error) { if (u->u.msg.type == XS_TRANSACTION_START) { - trans = malloc(sizeof(*trans), M_DEVBUF, + trans = malloc(sizeof(*trans), M_XENSTORE, M_WAITOK); trans->handle.id = strtoul(reply, NULL, 0); LIST_INSERT_HEAD(&u->transactions, trans, list); @@ -156,11 +157,11 @@ xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) BUG_ON(&trans->list == &u->transactions); #endif LIST_REMOVE(trans, list); - free(trans, M_DEVBUF); + free(trans, M_XENSTORE); } - queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); - queue_reply(u, (char *)reply, u->u.msg.len); - free(reply, M_DEVBUF); + xs_queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg)); + xs_queue_reply(u, (char *)reply, u->u.msg.len); + free(reply, M_XENSTORE); } break; @@ -176,16 +177,14 @@ xenbus_dev_write(struct cdev *dev, struct uio *uio, int ioflag) } static int -xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +xs_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { - struct xenbus_dev_data *u; + struct xs_dev_data *u; - if (xen_store_evtchn == 0) - return (ENOENT); #if 0 /* XXX figure out if equiv needed */ nonseekable_open(inode, filp); #endif - u = malloc(sizeof(*u), M_DEVBUF, M_WAITOK|M_ZERO); + u = malloc(sizeof(*u), M_XENSTORE, M_WAITOK|M_ZERO); LIST_INIT(&u->transactions); dev->si_drv1 = u; @@ -193,37 +192,33 @@ xenbus_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) } static int -xenbus_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +xs_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { - struct xenbus_dev_data *u = dev->si_drv1; - struct xenbus_dev_transaction *trans, *tmp; + struct xs_dev_data *u = dev->si_drv1; + struct xs_dev_transaction *trans, *tmp; LIST_FOREACH_SAFE(trans, &u->transactions, list, tmp) { - xenbus_transaction_end(trans->handle, 1); + xs_transaction_end(trans->handle, 1); LIST_REMOVE(trans, list); - free(trans, M_DEVBUF); + free(trans, M_XENSTORE); } - free(u, M_DEVBUF); + free(u, M_XENSTORE); return (0); } -static struct cdevsw xenbus_dev_cdevsw = { +static struct cdevsw xs_dev_cdevsw = { .d_version = D_VERSION, - .d_read = xenbus_dev_read, - .d_write = xenbus_dev_write, - .d_open = xenbus_dev_open, - .d_close = xenbus_dev_close, - .d_name = "xenbus_dev", + .d_read = xs_dev_read, + .d_write = xs_dev_write, + .d_open = xs_dev_open, + .d_close = xs_dev_close, + .d_name = "xs_dev", }; -static int -xenbus_dev_sysinit(void) +void +xs_dev_init() { - make_dev(&xenbus_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, - "xen/xenbus"); - - return (0); + make_dev(&xs_dev_cdevsw, 0, UID_ROOT, GID_WHEEL, 0400, + "xen/xenstore"); } -SYSINIT(xenbus_dev_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, - xenbus_dev_sysinit, NULL); diff --git a/sys/xen/xenstore/xenstore_internal.h b/sys/xen/xenstore/xenstore_internal.h new file mode 100644 index 00000000000..0398aef708a --- /dev/null +++ b/sys/xen/xenstore/xenstore_internal.h @@ -0,0 +1,39 @@ +/*- + * Core definitions and data structures shareable across OS platforms. + * + * Copyright (c) 2010 Spectra Logic Corporation + * 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 + * substantially 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 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$ + */ + +/* Initialize support for userspace access to the XenStore. */ +void xs_dev_init(void); + +/* Used by the XenStore character device to borrow kernel's store connection. */ +int xs_dev_request_and_reply(struct xsd_sockmsg *msg, void **result); diff --git a/sys/xen/xenstore/xenstorevar.h b/sys/xen/xenstore/xenstorevar.h new file mode 100644 index 00000000000..df41e3127cc --- /dev/null +++ b/sys/xen/xenstore/xenstorevar.h @@ -0,0 +1,338 @@ +/****************************************************************************** + * xenstorevar.h + * + * Method declarations and structures for accessing the XenStore.h + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 XenSource Ltd. + * Copyright (C) 2009,2010 Spectra Logic Corporation + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _XEN_XENSTORE_XENSTOREVAR_H +#define _XEN_XENSTORE_XENSTOREVAR_H + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "xenbus_if.h" + +/* XenStore allocations including XenStore data returned to clients. */ +MALLOC_DECLARE(M_XENSTORE); + +struct xenstore_domain_interface; +struct xs_watch; +extern struct xenstore_domain_interface *xen_store; + +typedef void (xs_watch_cb_t)(struct xs_watch *, + const char **vec, unsigned int len); + +/* Register callback to watch subtree (node) in the XenStore. */ +struct xs_watch +{ + LIST_ENTRY(xs_watch) list; + + /* Path being watched. */ + char *node; + + /* Callback (executed in a process context with no locks held). */ + xs_watch_cb_t *callback; +}; +LIST_HEAD(xs_watch_list, xs_watch); + +typedef int (*xs_event_handler_t)(void *); + +struct xs_transaction +{ + uint32_t id; +}; + +#define XST_NIL ((struct xs_transaction) { 0 }) + +/** + * Fetch the contents of a directory in the XenStore. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the path to read. + * \param node The basename of the path to read. + * \param num The returned number of directory entries. + * \param result An array of directory entry strings. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * \note The results buffer is malloced and should be free'd by the + * caller with 'free(*result, M_XENSTORE)'. + */ +int xs_directory(struct xs_transaction t, const char *dir, + const char *node, unsigned int *num, const char ***result); + +/** + * Determine if a path exists in the XenStore. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the path to read. + * \param node The basename of the path to read. + * + * \retval 1 The path exists. + * \retval 0 The path does not exist or an error occurred attempting + * to make that determination. + */ +int xs_exists(struct xs_transaction t, const char *dir, const char *node); + +/** + * Get the contents of a single "file". Returns the contents in + * *result which should be freed with free(*result, M_XENSTORE) after + * use. The length of the value in bytes is returned in *len. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the file to read. + * \param node The basename of the file to read. + * \param len The amount of data read. + * \param result The returned contents from this file. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + * + * \note The results buffer is malloced and should be free'd by the + * caller with 'free(*result, M_XENSTORE)'. + */ +int xs_read(struct xs_transaction t, const char *dir, + const char *node, unsigned int *len, void **result); + +/** + * Write to a single file. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the file to write. + * \param node The basename of the file to write. + * \param string The NUL terminated string of data to write. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_write(struct xs_transaction t, const char *dir, + const char *node, const char *string); + +/** + * Create a new directory. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the directory to create. + * \param node The basename of the directory to create. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_mkdir(struct xs_transaction t, const char *dir, + const char *node); + +/** + * Remove a file or directory (directories must be empty). + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the directory to remove. + * \param node The basename of the directory to remove. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_rm(struct xs_transaction t, const char *dir, const char *node); + +/** + * Destroy a tree of files rooted at dir/node. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the directory to remove. + * \param node The basename of the directory to remove. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_rm_tree(struct xs_transaction t, const char *dir, + const char *node); + +/** + * Start a transaction. + * + * Changes by others will not be seen during the lifetime of this + * transaction, and changes will not be visible to others until it + * is committed (xs_transaction_end). + * + * \param t The returned transaction. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_transaction_start(struct xs_transaction *t); + +/** + * End a transaction. + * + * \param t The transaction to end/commit. + * \param abort If non-zero, the transaction is discarded + * instead of committed. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_transaction_end(struct xs_transaction t, int abort); + +/* + * Single file read and scanf parsing of the result. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the path to read. + * \param node The basename of the path to read. + * \param scancountp The number of input values assigned (i.e. the result + * of scanf). + * \param fmt Scanf format string followed by a variable number of + * scanf input arguments. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of failure. + */ +int xs_scanf(struct xs_transaction t, + const char *dir, const char *node, int *scancountp, const char *fmt, ...) + __attribute__((format(scanf, 5, 6))); + +/** + * Printf formatted write to a XenStore file. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the path to read. + * \param node The basename of the path to read. + * \param fmt Printf format string followed by a variable number of + * printf arguments. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of write failure. + */ +int xs_printf(struct xs_transaction t, const char *dir, + const char *node, const char *fmt, ...) + __attribute__((format(printf, 4, 5))); + +/** + * va_list version of xenbus_printf(). + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the path to read. + * \param node The basename of the path to read. + * \param fmt Printf format string. + * \param ap Va_list of printf arguments. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of write failure. + */ +int xs_vprintf(struct xs_transaction t, const char *dir, + const char *node, const char *fmt, va_list ap); + +/** + * Multi-file read within a single directory and scanf parsing of + * the results. + * + * \param t The XenStore transaction covering this request. + * \param dir The dirname of the paths to read. + * \param ... A variable number of argument triples specifying + * the file name, scanf-style format string, and + * output variable (pointer to storage of the results). + * The last triple in the call must be terminated + * will a final NULL argument. A NULL format string + * will cause the entire contents of the given file + * to be assigned as a NUL terminated, M_XENSTORE heap + * backed, string to the output parameter of that tuple. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of read failure. + * + * Example: + * char protocol_abi[64]; + * uint32_t ring_ref; + * char *dev_type; + * int error; + * + * error = xenbus_gather(XBT_NIL, xenbus_get_node(dev), + * "ring-ref", "%" PRIu32, &ring_ref, + * "protocol", "%63s", protocol_abi, + * "device-type", NULL, &dev_type, + * NULL); + * + * ... + * + * free(dev_type, M_XENSTORE); + */ +int xs_gather(struct xs_transaction t, const char *dir, ...); + +/** + * Register a XenStore watch. + * + * XenStore watches allow a client to be notified via a callback (embedded + * within the watch object) of changes to an object in the XenStore. + * + * \param watch A xenbus_watch struct with it's node and callback fields + * properly initialized. + * + * \return On success, 0. Otherwise an errno value indicating the + * type of write failure. EEXIST errors from the XenStore + * are supressed, allowing multiple, physically different, + * xenbus_watch objects, to watch the same path in the XenStore. + */ +int xs_register_watch(struct xs_watch *watch); + +/** + * Unregister a XenStore watch. + * + * \param watch An xs_watch object previously used in a successful call + * to xs_register_watch(). + * + * The xs_watch object's node field is not altered by this call. + * It is the caller's responsibility to properly dispose of both the + * watch object and the data pointed to by watch->node. + */ +void xs_unregister_watch(struct xs_watch *watch); + +/** + * Allocate and return an sbuf containing the XenStore path string + * /. If name is the NUL string, the returned sbuf contains + * the path string . + * + * \param dir The NUL terminated directory prefix for new path. + * \param name The NUL terminated basename for the new path. + * + * \return A buffer containing the joined path. + */ +struct sbuf *xs_join(const char *, const char *); + +#endif /* _XEN_XENSTORE_XENSTOREVAR_H */