diff --git a/lib/libutil/flopen.c b/lib/libutil/flopen.c index 754c9c037fa..bc4119dcb1c 100644 --- a/lib/libutil/flopen.c +++ b/lib/libutil/flopen.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2007 Dag-Erling Coïdan Smørgrav + * Copyright (c) 2007-2009 Dag-Erling Coïdan Smørgrav * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,14 @@ __FBSDID("$FreeBSD$"); #include +/* + * Reliably open and lock a file. + * + * DO NOT, UNDER PAIN OF DEATH, modify this code without first reading the + * revision history and discussing your changes with . + * Don't be fooled by the code's apparent simplicity; there would be no + * need for this function if it was as easy to get right as you think. + */ int flopen(const char *path, int flags, ...) { @@ -100,6 +108,14 @@ flopen(const char *path, int flags, ...) errno = serrno; return (-1); } +#ifdef DONT_EVEN_THINK_ABOUT_IT + if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { + serrno = errno; + (void)close(fd); + errno = serrno; + return (-1); + } +#endif return (fd); } } diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 79bfa0d44ca..bba20f66589 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -47,6 +47,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_cpsw.h" + #include #include #include @@ -78,6 +80,11 @@ __FBSDID("$FreeBSD$"); #include #include + +#ifdef CPSW_ETHERSWITCH +#include +#include "etherswitch_if.h" +#endif #include "if_cpswreg.h" #include "if_cpswvar.h" @@ -142,6 +149,19 @@ static void cpsw_add_sysctls(struct cpsw_softc *); static void cpsw_stats_collect(struct cpsw_softc *); static int cpsw_stats_sysctl(SYSCTL_HANDLER_ARGS); +#ifdef CPSW_ETHERSWITCH +static etherswitch_info_t *cpsw_getinfo(device_t); +static int cpsw_getport(device_t, etherswitch_port_t *); +static int cpsw_setport(device_t, etherswitch_port_t *); +static int cpsw_getconf(device_t, etherswitch_conf_t *); +static int cpsw_getvgroup(device_t, etherswitch_vlangroup_t *); +static int cpsw_setvgroup(device_t, etherswitch_vlangroup_t *); +static int cpsw_readreg(device_t, int); +static int cpsw_writereg(device_t, int, int); +static int cpsw_readphy(device_t, int, int); +static int cpsw_writephy(device_t, int, int, int); +#endif + /* * Arbitrary limit on number of segments in an mbuf to be transmitted. * Packets with more segments than this will be defragmented before @@ -158,8 +178,23 @@ static device_method_t cpsw_methods[] = { DEVMETHOD(device_shutdown, cpsw_shutdown), DEVMETHOD(device_suspend, cpsw_suspend), DEVMETHOD(device_resume, cpsw_resume), + /* Bus interface */ + DEVMETHOD(bus_add_child, device_add_child_ordered), /* OFW methods */ DEVMETHOD(ofw_bus_get_node, cpsw_get_node), +#ifdef CPSW_ETHERSWITCH + /* etherswitch interface */ + DEVMETHOD(etherswitch_getinfo, cpsw_getinfo), + DEVMETHOD(etherswitch_readreg, cpsw_readreg), + DEVMETHOD(etherswitch_writereg, cpsw_writereg), + DEVMETHOD(etherswitch_readphyreg, cpsw_readphy), + DEVMETHOD(etherswitch_writephyreg, cpsw_writephy), + DEVMETHOD(etherswitch_getport, cpsw_getport), + DEVMETHOD(etherswitch_setport, cpsw_setport), + DEVMETHOD(etherswitch_getvgroup, cpsw_getvgroup), + DEVMETHOD(etherswitch_setvgroup, cpsw_setvgroup), + DEVMETHOD(etherswitch_getconf, cpsw_getconf), +#endif DEVMETHOD_END }; @@ -194,11 +229,20 @@ static driver_t cpswp_driver = { static devclass_t cpswp_devclass; +#ifdef CPSW_ETHERSWITCH +DRIVER_MODULE(etherswitch, cpswss, etherswitch_driver, etherswitch_devclass, 0, 0); +MODULE_DEPEND(cpswss, etherswitch, 1, 1, 1); +#endif + DRIVER_MODULE(cpsw, cpswss, cpswp_driver, cpswp_devclass, 0, 0); DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(cpsw, ether, 1, 1, 1); MODULE_DEPEND(cpsw, miibus, 1, 1, 1); +#ifdef CPSW_ETHERSWITCH +static struct cpsw_vlangroups cpsw_vgroups[CPSW_VLANS]; +#endif + static uint32_t slave_mdio_addr[] = { 0x4a100200, 0x4a100300 }; static struct resource_spec irq_res_spec[] = { @@ -576,7 +620,8 @@ cpsw_init(struct cpsw_softc *sc) cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0); /* Initialize ALE: set host port to forwarding(3). */ - cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3); + cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), + ALE_PORTCTL_INGRESS | ALE_PORTCTL_FORWARD); cpsw_write_4(sc, CPSW_SS_PTYPE, 0); @@ -851,6 +896,11 @@ cpsw_attach(device_t dev) return (ENXIO); } +#ifdef CPSW_ETHERSWITCH + for (i = 0; i < CPSW_VLANS; i++) + cpsw_vgroups[i].vid = -1; +#endif + /* Reset the controller. */ cpsw_reset(sc); cpsw_init(sc); @@ -864,6 +914,7 @@ cpsw_attach(device_t dev) return (ENXIO); } } + bus_generic_probe(dev); bus_generic_attach(dev); return (0); @@ -918,7 +969,12 @@ cpsw_detach(device_t dev) mtx_destroy(&sc->rx.lock); mtx_destroy(&sc->tx.lock); - return (0); + /* Detach the switch device, if present. */ + error = bus_generic_detach(dev); + if (error != 0) + return (error); + + return (device_delete_children(dev)); } static phandle_t @@ -1085,6 +1141,9 @@ cpswp_init(void *arg) static void cpswp_init_locked(void *arg) { +#ifdef CPSW_ETHERSWITCH + int i; +#endif struct cpswp_softc *sc = arg; struct ifnet *ifp; uint32_t reg; @@ -1115,8 +1174,9 @@ cpswp_init_locked(void *arg) reg |= CPSW_SL_MACTL_GMII_ENABLE; cpsw_write_4(sc->swsc, CPSW_SL_MACCONTROL(sc->unit), reg); - /* Initialize ALE: set port to forwarding(3), initialize addrs */ - cpsw_write_4(sc->swsc, CPSW_ALE_PORTCTL(sc->unit + 1), 3); + /* Initialize ALE: set port to forwarding, initialize addrs */ + cpsw_write_4(sc->swsc, CPSW_ALE_PORTCTL(sc->unit + 1), + ALE_PORTCTL_INGRESS | ALE_PORTCTL_FORWARD); cpswp_ale_update_addresses(sc, 1); if (sc->swsc->dualemac) { @@ -1127,6 +1187,14 @@ cpswp_init_locked(void *arg) (1 << (sc->unit + 1)) | (1 << 0), /* Member list */ (1 << (sc->unit + 1)) | (1 << 0), /* Untagged egress */ (1 << (sc->unit + 1)) | (1 << 0), 0); /* mcast reg flood */ +#ifdef CPSW_ETHERSWITCH + for (i = 0; i < CPSW_VLANS; i++) { + if (cpsw_vgroups[i].vid != -1) + continue; + cpsw_vgroups[i].vid = sc->vlan; + break; + } +#endif } mii_mediachg(sc->mii); @@ -2699,3 +2767,229 @@ cpsw_add_sysctls(struct cpsw_softc *sc) CTLFLAG_RD, NULL, "Watchdog Statistics"); cpsw_add_watchdog_sysctls(ctx, node, sc); } + +#ifdef CPSW_ETHERSWITCH +static etherswitch_info_t etherswitch_info = { + .es_nports = CPSW_PORTS + 1, + .es_nvlangroups = CPSW_VLANS, + .es_name = "TI Common Platform Ethernet Switch (CPSW)", + .es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q, +}; + +static etherswitch_info_t * +cpsw_getinfo(device_t dev) +{ + return (ðerswitch_info); +} + +static int +cpsw_getport(device_t dev, etherswitch_port_t *p) +{ + int err; + struct cpsw_softc *sc; + struct cpswp_softc *psc; + struct ifmediareq *ifmr; + uint32_t reg; + + if (p->es_port < 0 || p->es_port > CPSW_PORTS) + return (ENXIO); + + err = 0; + sc = device_get_softc(dev); + if (p->es_port == CPSW_CPU_PORT) { + p->es_flags |= ETHERSWITCH_PORT_CPU; + ifmr = &p->es_ifmr; + ifmr->ifm_current = ifmr->ifm_active = + IFM_ETHER | IFM_1000_T | IFM_FDX; + ifmr->ifm_mask = 0; + ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; + ifmr->ifm_count = 0; + } else { + psc = device_get_softc(sc->port[p->es_port - 1].dev); + err = ifmedia_ioctl(psc->ifp, &p->es_ifr, + &psc->mii->mii_media, SIOCGIFMEDIA); + } + reg = cpsw_read_4(sc, CPSW_PORT_P_VLAN(p->es_port)); + p->es_pvid = reg & ETHERSWITCH_VID_MASK; + + reg = cpsw_read_4(sc, CPSW_ALE_PORTCTL(p->es_port)); + if (reg & ALE_PORTCTL_DROP_UNTAGGED) + p->es_flags |= ETHERSWITCH_PORT_DROPUNTAGGED; + if (reg & ALE_PORTCTL_INGRESS) + p->es_flags |= ETHERSWITCH_PORT_INGRESS; + + return (err); +} + +static int +cpsw_setport(device_t dev, etherswitch_port_t *p) +{ + struct cpsw_softc *sc; + struct cpswp_softc *psc; + struct ifmedia *ifm; + uint32_t reg; + + if (p->es_port < 0 || p->es_port > CPSW_PORTS) + return (ENXIO); + + sc = device_get_softc(dev); + if (p->es_pvid != 0) { + cpsw_write_4(sc, CPSW_PORT_P_VLAN(p->es_port), + p->es_pvid & ETHERSWITCH_VID_MASK); + } + + reg = cpsw_read_4(sc, CPSW_ALE_PORTCTL(p->es_port)); + if (p->es_flags & ETHERSWITCH_PORT_DROPUNTAGGED) + reg |= ALE_PORTCTL_DROP_UNTAGGED; + else + reg &= ~ALE_PORTCTL_DROP_UNTAGGED; + if (p->es_flags & ETHERSWITCH_PORT_INGRESS) + reg |= ALE_PORTCTL_INGRESS; + else + reg &= ~ALE_PORTCTL_INGRESS; + cpsw_write_4(sc, CPSW_ALE_PORTCTL(p->es_port), reg); + + /* CPU port does not allow media settings. */ + if (p->es_port == CPSW_CPU_PORT) + return (0); + + psc = device_get_softc(sc->port[p->es_port - 1].dev); + ifm = &psc->mii->mii_media; + + return (ifmedia_ioctl(psc->ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); +} + +static int +cpsw_getconf(device_t dev, etherswitch_conf_t *conf) +{ + + /* Return the VLAN mode. */ + conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; + conf->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; + + return (0); +} + +static int +cpsw_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) +{ + int i, vid; + uint32_t ale_entry[3]; + struct cpsw_softc *sc; + + sc = device_get_softc(dev); + + if (vg->es_vlangroup >= CPSW_VLANS) + return (EINVAL); + + vg->es_vid = 0; + vid = cpsw_vgroups[vg->es_vlangroup].vid; + if (vid == -1) + return (0); + + for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) { + cpsw_ale_read_entry(sc, i, ale_entry); + if (ALE_TYPE(ale_entry) != ALE_TYPE_VLAN) + continue; + if (vid != ALE_VLAN(ale_entry)) + continue; + + vg->es_fid = 0; + vg->es_vid = ALE_VLAN(ale_entry) | ETHERSWITCH_VID_VALID; + vg->es_member_ports = ALE_VLAN_MEMBERS(ale_entry); + vg->es_untagged_ports = ALE_VLAN_UNTAG(ale_entry); + } + + return (0); +} + +static void +cpsw_remove_vlan(struct cpsw_softc *sc, int vlan) +{ + int i; + uint32_t ale_entry[3]; + + for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) { + cpsw_ale_read_entry(sc, i, ale_entry); + if (ALE_TYPE(ale_entry) != ALE_TYPE_VLAN) + continue; + if (vlan != ALE_VLAN(ale_entry)) + continue; + ale_entry[0] = ale_entry[1] = ale_entry[2] = 0; + cpsw_ale_write_entry(sc, i, ale_entry); + break; + } +} + +static int +cpsw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) +{ + int i; + struct cpsw_softc *sc; + + sc = device_get_softc(dev); + + for (i = 0; i < CPSW_VLANS; i++) { + /* Is this Vlan ID in use by another vlangroup ? */ + if (vg->es_vlangroup != i && cpsw_vgroups[i].vid == vg->es_vid) + return (EINVAL); + } + + if (vg->es_vid == 0) { + if (cpsw_vgroups[vg->es_vlangroup].vid == -1) + return (0); + cpsw_remove_vlan(sc, cpsw_vgroups[vg->es_vlangroup].vid); + cpsw_vgroups[vg->es_vlangroup].vid = -1; + vg->es_untagged_ports = 0; + vg->es_member_ports = 0; + vg->es_vid = 0; + return (0); + } + + vg->es_vid &= ETHERSWITCH_VID_MASK; + vg->es_member_ports &= CPSW_PORTS_MASK; + vg->es_untagged_ports &= CPSW_PORTS_MASK; + + if (cpsw_vgroups[vg->es_vlangroup].vid != -1 && + cpsw_vgroups[vg->es_vlangroup].vid != vg->es_vid) + return (EINVAL); + + cpsw_vgroups[vg->es_vlangroup].vid = vg->es_vid; + cpsw_ale_update_vlan_table(sc, vg->es_vid, vg->es_member_ports, + vg->es_untagged_ports, vg->es_member_ports, 0); + + return (0); +} + +static int +cpsw_readreg(device_t dev, int addr) +{ + + /* Not supported. */ + return (0); +} + +static int +cpsw_writereg(device_t dev, int addr, int value) +{ + + /* Not supported. */ + return (0); +} + +static int +cpsw_readphy(device_t dev, int phy, int reg) +{ + + /* Not supported. */ + return (0); +} + +static int +cpsw_writephy(device_t dev, int phy, int reg, int data) +{ + + /* Not supported. */ + return (0); +} +#endif diff --git a/sys/arm/ti/cpsw/if_cpswreg.h b/sys/arm/ti/cpsw/if_cpswreg.h index 64af54db84f..6d6a647565c 100644 --- a/sys/arm/ti/cpsw/if_cpswreg.h +++ b/sys/arm/ti/cpsw/if_cpswreg.h @@ -106,6 +106,14 @@ #define ALE_VLAN_UNTAG(_a) ((_a[0] >> 24) & 7) #define ALE_VLAN_MEMBERS(_a) (_a[0] & 7) #define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04)) +#define ALE_PORTCTL_NO_SA_UPDATE (1 << 5) +#define ALE_PORTCTL_NO_LEARN (1 << 4) +#define ALE_PORTCTL_INGRESS (1 << 3) +#define ALE_PORTCTL_DROP_UNTAGGED (1 << 2) +#define ALE_PORTCTL_FORWARD 3 +#define ALE_PORTCTL_LEARN 2 +#define ALE_PORTCTL_BLOCKED 1 +#define ALE_PORTCTL_DISABLED 0 /* SL1 is at 0x0D80, SL2 is at 0x0DC0 */ #define CPSW_SL_OFFSET 0x0D80 diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h index e8b7256c380..4024c52d107 100644 --- a/sys/arm/ti/cpsw/if_cpswvar.h +++ b/sys/arm/ti/cpsw/if_cpswvar.h @@ -40,6 +40,16 @@ #define CPSW_SYSCTL_COUNT 34 +#ifdef CPSW_ETHERSWITCH +#define CPSW_CPU_PORT 0 +#define CPSW_PORTS_MASK 0x7 +#define CPSW_VLANS 128 /* Arbitrary number. */ + +struct cpsw_vlangroups { + int vid; +}; +#endif + struct cpsw_slot { uint32_t bd_offset; /* Offset of corresponding BD within CPPI RAM. */ bus_dmamap_t dmamap; diff --git a/sys/conf/options.arm b/sys/conf/options.arm index b65c5804169..614741a94d3 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -7,6 +7,7 @@ ARM_MANY_BOARD opt_global.h NKPT2PG opt_pmap.h ARM_WANT_TP_ADDRESS opt_global.h COUNTS_PER_SEC opt_timer.h +CPSW_ETHERSWITCH opt_cpsw.h CPU_ARM9 opt_global.h CPU_ARM9E opt_global.h CPU_ARM1176 opt_global.h diff --git a/sys/dev/virtio/console/virtio_console.c b/sys/dev/virtio/console/virtio_console.c index 4c673c8d129..23a0dd4bdd1 100644 --- a/sys/dev/virtio/console/virtio_console.c +++ b/sys/dev/virtio/console/virtio_console.c @@ -888,9 +888,9 @@ vtcon_ctrl_task_cb(void *xsc, int pending) if (control == NULL) break; - if (len > sizeof(control)) { + if (len > sizeof(*control)) { payload = (void *)(control + 1); - plen = len - sizeof(control); + plen = len - sizeof(*control); } VTCON_UNLOCK(sc); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index b06e246c9bd..79372ce0639 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1061,7 +1061,6 @@ proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, proc_reap(td, p, status, options); return (-1); } - PROC_UNLOCK(p); return (1); } @@ -1162,7 +1161,7 @@ loop: return (0); } - PROC_LOCK(p); + PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK(p); if ((options & WTRAPPED) != 0 && @@ -1263,6 +1262,7 @@ loop: if (ret != 0) { KASSERT(ret != -1, ("reaped an orphan (pid %d)", (int)td->td_retval[0])); + PROC_UNLOCK(p); nfound++; break; } diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 30e85396187..6e3d5a5e1dd 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -552,7 +552,6 @@ _an= an _aout= aout _bktr= bktr _bxe= bxe -_bytgpio= bytgpio _cardbus= cardbus _cbb= cbb _cpuctl= cpuctl @@ -609,6 +608,7 @@ _amdsbwd= amdsbwd _amdtemp= amdtemp _arcmsr= arcmsr _asmc= asmc +_bytgpio= bytgpio _ciss= ciss _chromebook_platform= chromebook_platform _cmx= cmx diff --git a/sys/powerpc/include/pcpu.h b/sys/powerpc/include/pcpu.h index 2c79cd696e7..79cdd3039ff 100644 --- a/sys/powerpc/include/pcpu.h +++ b/sys/powerpc/include/pcpu.h @@ -88,7 +88,7 @@ struct pvo_entry; vm_offset_t pc_qmap_addr; \ uint32_t *pc_booke_tlb_lock; \ int pc_tid_next; \ - char __pad[165] + char __pad[173] /* Definitions for register offsets within the exception tmp save areas */ #define CPUSAVE_R27 0 /* where r27 gets saved */