aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2010-11-12 17:20:18 +0000
committerDimitry Andric <dim@FreeBSD.org>2010-11-12 17:20:18 +0000
commit5fbbc222c809dc1da75590d2ff48592da7a34233 (patch)
treef1e172e71559ebd572f16647203a27e631184ee6 /sys
parent1170f3d12ebd03d02f8bb4f075319f461e38d7d9 (diff)
parent542aef4874baf2030a1e5fd995419e25398252d4 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/conf/CAMBRIA4
-rw-r--r--sys/arm/conf/CAMBRIA.hints4
-rw-r--r--sys/arm/xscale/ixp425/cambria_gpio.c471
-rw-r--r--sys/arm/xscale/ixp425/files.avila1
-rw-r--r--sys/conf/files2
-rw-r--r--sys/conf/files.powerpc2
-rw-r--r--sys/dev/acpica/acpi_cpu.c30
-rw-r--r--sys/dev/gpio/gpiobus.c2
-rw-r--r--sys/dev/gpio/gpioc.c2
-rw-r--r--sys/kern/kern_proc.c4
-rw-r--r--sys/kern/uipc_socket.c10
-rw-r--r--sys/netinet/cc.h161
-rw-r--r--sys/netinet/cc/cc.c340
-rw-r--r--sys/netinet/cc/cc_module.h70
-rw-r--r--sys/netinet/cc/cc_newreno.c231
-rw-r--r--sys/netinet/ip_fw.h3
-rw-r--r--sys/netinet/ipfw/ip_fw2.c33
-rw-r--r--sys/netinet/ipfw/ip_fw_sockopt.c1
-rw-r--r--sys/netinet/libalias/alias_sctp.c20
-rw-r--r--sys/netinet/libalias/alias_sctp.h20
-rw-r--r--sys/netinet/siftr.c5
-rw-r--r--sys/netinet/tcp_input.c484
-rw-r--r--sys/netinet/tcp_output.c24
-rw-r--r--sys/netinet/tcp_sack.c2
-rw-r--r--sys/netinet/tcp_subr.c33
-rw-r--r--sys/netinet/tcp_timer.c49
-rw-r--r--sys/netinet/tcp_usrreq.c62
-rw-r--r--sys/netinet/tcp_var.h30
-rw-r--r--sys/powerpc/aim/machdep.c60
-rw-r--r--sys/powerpc/aim/mmu_oea.c43
-rw-r--r--sys/powerpc/aim/mmu_oea64.c26
-rw-r--r--sys/powerpc/aim/mp_cpudep.c30
-rw-r--r--sys/powerpc/aim/slb.c55
-rw-r--r--sys/powerpc/booke/machdep.c53
-rw-r--r--sys/powerpc/include/cpufunc.h11
-rw-r--r--sys/powerpc/include/platform.h1
-rw-r--r--sys/powerpc/include/spr.h4
-rw-r--r--sys/powerpc/ofw/ofw_machdep.c (renamed from sys/powerpc/aim/ofw_machdep.c)68
-rw-r--r--sys/powerpc/powerpc/cpu.c103
-rw-r--r--sys/powerpc/powerpc/mp_machdep.c19
-rw-r--r--sys/powerpc/powerpc/platform.c51
-rw-r--r--sys/powerpc/powerpc/platform_if.m30
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/signal.h2
-rw-r--r--sys/sys/smp.h5
-rw-r--r--sys/sys/socket.h1
-rw-r--r--sys/sys/socketvar.h7
47 files changed, 2113 insertions, 558 deletions
diff --git a/sys/arm/conf/CAMBRIA b/sys/arm/conf/CAMBRIA
index 174a7c785a8f..ed16ed83fab1 100644
--- a/sys/arm/conf/CAMBRIA
+++ b/sys/arm/conf/CAMBRIA
@@ -90,6 +90,10 @@ device ad7418 # AD7418 on I2C bus
device cambria_fled # Font Panel LED on I2C bus
device cambria_led # 8-LED latch
+device gpio
+device gpioled
+device cambria_gpio # GPIO pins on J11
+
device ata
device atadisk # ATA disk drives
device avila_ata # Gateworks CF/IDE support
diff --git a/sys/arm/conf/CAMBRIA.hints b/sys/arm/conf/CAMBRIA.hints
index 6a1f889349d2..f727c367ff99 100644
--- a/sys/arm/conf/CAMBRIA.hints
+++ b/sys/arm/conf/CAMBRIA.hints
@@ -54,6 +54,10 @@ hint.fled.0.addr=0x5a
# Octal LED Latch
hint.led_cambria.0.at="ixp0"
+# GPIO pins
+hint.gpio_cambria.0.at="iicbus0"
+hint.gpio_cambria.0.addr=0x56
+
# Analog Devices AD7418 temperature sensor
hint.ad7418.0.at="iicbus0"
hint.ad7418.0.addr=0x50
diff --git a/sys/arm/xscale/ixp425/cambria_gpio.c b/sys/arm/xscale/ixp425/cambria_gpio.c
new file mode 100644
index 000000000000..89b07d852b7a
--- /dev/null
+++ b/sys/arm/xscale/ixp425/cambria_gpio.c
@@ -0,0 +1,471 @@
+/*-
+ * Copyright (c) 2010, Andrew Thompson <thompsa@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice 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 Gateworks Cambria
+ *
+ * Note:
+ * The Cambria PLD does not set the i2c ack bit after each write, if we used the
+ * regular iicbus interface it would abort the xfer after the address byte
+ * times out and not write our latch. To get around this we grab the iicbus and
+ * then do our own bit banging. This is a comprimise to changing all the iicbb
+ * device methods to allow a flag to be passed down and is similir to how Linux
+ * does it.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixdp425reg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include "iicbb_if.h"
+#include "gpio_if.h"
+
+#define IIC_M_WR 0 /* write operation */
+#define PLD_ADDR 0xac /* slave address */
+
+#define I2C_DELAY 10
+
+#define GPIO_CONF_CLR(sc, reg, mask) \
+ GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask))
+#define GPIO_CONF_SET(sc, reg, mask) \
+ GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask))
+
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
+
+#define GPIO_PINS 5
+struct cambria_gpio_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_gpio_ioh;
+ struct mtx sc_mtx;
+ struct gpio_pin sc_pins[GPIO_PINS];
+ uint8_t sc_latch;
+};
+
+struct cambria_gpio_pin {
+ const char *name;
+ int pin;
+ int flags;
+};
+
+extern struct ixp425_softc *ixp425_softc;
+
+static struct cambria_gpio_pin cambria_gpio_pins[GPIO_PINS] = {
+ { "GPIO0", 0, GPIO_PIN_OUTPUT },
+ { "GPIO1", 1, GPIO_PIN_OUTPUT },
+ { "GPIO2", 2, GPIO_PIN_OUTPUT },
+ { "GPIO3", 3, GPIO_PIN_OUTPUT },
+ { "GPIO4", 4, GPIO_PIN_OUTPUT },
+};
+
+/*
+ * Helpers
+ */
+static int cambria_gpio_read(struct cambria_gpio_softc *, uint32_t, unsigned int *);
+static int cambria_gpio_write(struct cambria_gpio_softc *);
+
+/*
+ * Driver stuff
+ */
+static int cambria_gpio_probe(device_t dev);
+static int cambria_gpio_attach(device_t dev);
+static int cambria_gpio_detach(device_t dev);
+
+/*
+ * GPIO interface
+ */
+static int cambria_gpio_pin_max(device_t dev, int *maxpin);
+static int cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
+static int cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
+ *flags);
+static int cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
+static int cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
+static int cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
+static int cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
+static int cambria_gpio_pin_toggle(device_t dev, uint32_t pin);
+
+static int
+i2c_getsda(struct cambria_gpio_softc *sc)
+{
+ uint32_t reg;
+
+ mtx_lock(&Giant);
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR);
+ mtx_unlock(&Giant);
+ return (reg & GPIO_I2C_SDA_BIT);
+}
+
+static void
+i2c_setsda(struct cambria_gpio_softc *sc, int val)
+{
+
+ mtx_lock(&Giant);
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT);
+ if (val)
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+ else
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+ mtx_unlock(&Giant);
+ DELAY(I2C_DELAY);
+}
+
+static void
+i2c_setscl(struct cambria_gpio_softc *sc, int val)
+{
+
+ mtx_lock(&Giant);
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT);
+ if (val)
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
+ else
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
+ mtx_unlock(&Giant);
+ DELAY(I2C_DELAY);
+}
+
+static void
+i2c_sendstart(struct cambria_gpio_softc *sc)
+{
+ i2c_setsda(sc, 1);
+ i2c_setscl(sc, 1);
+ i2c_setsda(sc, 0);
+ i2c_setscl(sc, 0);
+}
+
+static void
+i2c_sendstop(struct cambria_gpio_softc *sc)
+{
+ i2c_setscl(sc, 1);
+ i2c_setsda(sc, 1);
+ i2c_setscl(sc, 0);
+ i2c_setsda(sc, 0);
+}
+
+static void
+i2c_sendbyte(struct cambria_gpio_softc *sc, u_char data)
+{
+ int i;
+
+ for (i=7; i>=0; i--) {
+ i2c_setsda(sc, data & (1<<i));
+ i2c_setscl(sc, 1);
+ i2c_setscl(sc, 0);
+ }
+ i2c_setscl(sc, 1);
+ i2c_getsda(sc);
+ i2c_setscl(sc, 0);
+}
+
+static u_char
+i2c_readbyte(struct cambria_gpio_softc *sc)
+{
+ int i;
+ unsigned char data=0;
+
+ for (i=7; i>=0; i--)
+ {
+ i2c_setscl(sc, 1);
+ if (i2c_getsda(sc))
+ data |= (1<<i);
+ i2c_setscl(sc, 0);
+ }
+ return data;
+}
+
+static int
+cambria_gpio_read(struct cambria_gpio_softc *sc, uint32_t pin, unsigned int *val)
+{
+ device_t dev = sc->sc_dev;
+ int error;
+
+ error = iicbus_request_bus(device_get_parent(dev), dev,
+ IIC_DONTWAIT);
+ if (error)
+ return (error);
+
+ i2c_sendstart(sc);
+ i2c_sendbyte(sc, PLD_ADDR | LSB);
+ *val = (i2c_readbyte(sc) & (1 << pin)) != 0;
+ i2c_sendstop(sc);
+
+ iicbus_release_bus(device_get_parent(dev), dev);
+
+ return (0);
+}
+
+static int
+cambria_gpio_write(struct cambria_gpio_softc *sc)
+{
+ device_t dev = sc->sc_dev;
+ int error;
+
+ error = iicbus_request_bus(device_get_parent(dev), dev,
+ IIC_DONTWAIT);
+ if (error)
+ return (error);
+
+ i2c_sendstart(sc);
+ i2c_sendbyte(sc, PLD_ADDR & ~LSB);
+ i2c_sendbyte(sc, sc->sc_latch);
+ i2c_sendstop(sc);
+
+ iicbus_release_bus(device_get_parent(dev), dev);
+
+ return (0);
+}
+
+static int
+cambria_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = GPIO_PINS - 1;
+ return (0);
+}
+
+static int
+cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+
+ if (pin >= GPIO_PINS)
+ return (EINVAL);
+
+ *caps = sc->sc_pins[pin].gp_caps;
+ return (0);
+}
+
+static int
+cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+
+ if (pin >= GPIO_PINS)
+ return (EINVAL);
+
+ *flags = sc->sc_pins[pin].gp_flags;
+ return (0);
+}
+
+static int
+cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+
+ if (pin >= GPIO_PINS)
+ return (EINVAL);
+
+ memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
+ return (0);
+}
+
+static int
+cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+ int error;
+
+ if (pin >= GPIO_PINS)
+ return (EINVAL);
+
+ /* Filter out unwanted flags */
+ if ((flags &= sc->sc_pins[pin].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);
+
+ GPIO_LOCK(sc);
+ sc->sc_pins[pin].gp_flags = flags;
+
+ sc->sc_latch |= (1 << pin);
+ error = cambria_gpio_write(sc);
+ GPIO_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+ int error;
+
+ if (pin >= GPIO_PINS || sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ if (value)
+ sc->sc_latch |= (1 << pin);
+ else
+ sc->sc_latch &= ~(1 << pin);
+ error = cambria_gpio_write(sc);
+ GPIO_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+ int error = 0;
+
+ if (pin >= GPIO_PINS)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT)
+ *val = (sc->sc_latch & (1 << pin)) ? 1 : 0;
+ else
+ error = cambria_gpio_read(sc, pin, val);
+ GPIO_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+cambria_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+ int error;
+
+ if (pin >= GPIO_PINS || sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT)
+ return (EINVAL);
+
+ GPIO_LOCK(sc);
+ sc->sc_latch ^= (1 << pin);
+ error = cambria_gpio_write(sc);
+ GPIO_UNLOCK(sc);
+
+ return (error);
+}
+
+static int
+cambria_gpio_probe(device_t dev)
+{
+
+ device_set_desc(dev, "Gateworks Cambria GPIO driver");
+ return (0);
+}
+
+static int
+cambria_gpio_attach(device_t dev)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+ int pin;
+
+ sc->sc_dev = dev;
+ sc->sc_iot = ixp425_softc->sc_iot;
+ sc->sc_gpio_ioh = ixp425_softc->sc_gpio_ioh;
+
+ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+
+ for (pin = 0; pin < GPIO_PINS; pin++) {
+ struct cambria_gpio_pin *p = &cambria_gpio_pins[pin];
+
+ strncpy(sc->sc_pins[pin].gp_name, p->name, GPIOMAXNAME);
+ sc->sc_pins[pin].gp_pin = pin;
+ sc->sc_pins[pin].gp_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
+ sc->sc_pins[pin].gp_flags = 0;
+ cambria_gpio_pin_setflags(dev, pin, p->flags);
+ }
+
+ 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
+cambria_gpio_detach(device_t dev)
+{
+ struct cambria_gpio_softc *sc = device_get_softc(dev);
+
+ KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
+
+ bus_generic_detach(dev);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ return(0);
+}
+
+static device_method_t cambria_gpio_methods[] = {
+ DEVMETHOD(device_probe, cambria_gpio_probe),
+ DEVMETHOD(device_attach, cambria_gpio_attach),
+ DEVMETHOD(device_detach, cambria_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_pin_max, cambria_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, cambria_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, cambria_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, cambria_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, cambria_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, cambria_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, cambria_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, cambria_gpio_pin_toggle),
+ {0, 0},
+};
+
+static driver_t cambria_gpio_driver = {
+ "gpio_cambria",
+ cambria_gpio_methods,
+ sizeof(struct cambria_gpio_softc),
+};
+static devclass_t cambria_gpio_devclass;
+extern devclass_t gpiobus_devclass, gpioc_devclass;
+extern driver_t gpiobus_driver, gpioc_driver;
+
+DRIVER_MODULE(gpio_cambria, iicbus, cambria_gpio_driver, cambria_gpio_devclass, 0, 0);
+DRIVER_MODULE(gpiobus, gpio_cambria, gpiobus_driver, gpiobus_devclass, 0, 0);
+DRIVER_MODULE(gpioc, gpio_cambria, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(gpio_cambria, 1);
+MODULE_DEPEND(gpio_cambria, iicbus, 1, 1, 1);
diff --git a/sys/arm/xscale/ixp425/files.avila b/sys/arm/xscale/ixp425/files.avila
index 38b93296256b..5008e0910a12 100644
--- a/sys/arm/xscale/ixp425/files.avila
+++ b/sys/arm/xscale/ixp425/files.avila
@@ -6,4 +6,5 @@ arm/xscale/ixp425/avila_gpio.c optional avila_gpio
arm/xscale/ixp425/cambria_exp_space.c standard
arm/xscale/ixp425/cambria_fled.c optional cambria_fled
arm/xscale/ixp425/cambria_led.c optional cambria_led
+arm/xscale/ixp425/cambria_gpio.c optional cambria_gpio
arm/xscale/ixp425/ixdp425_pci.c optional pci
diff --git a/sys/conf/files b/sys/conf/files
index ce2eb82ed4ba..c859ec82b3a5 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2598,6 +2598,8 @@ netinet/ip_mroute.c optional mrouting inet | mrouting inet6
netinet/ip_options.c optional inet
netinet/ip_output.c optional inet
netinet/raw_ip.c optional inet
+netinet/cc/cc.c optional inet
+netinet/cc/cc_newreno.c optional inet
netinet/sctp_asconf.c optional inet sctp
netinet/sctp_auth.c optional inet sctp
netinet/sctp_bsd_addr.c optional inet sctp
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index 021c51d413f9..d46b39fcf936 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -85,7 +85,6 @@ powerpc/aim/mmu_oea.c optional aim powerpc
powerpc/aim/mmu_oea64.c optional aim
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/slb.c optional aim powerpc64
powerpc/aim/swtch32.S optional aim powerpc
@@ -131,6 +130,7 @@ powerpc/mpc85xx/nexus.c optional mpc85xx
powerpc/mpc85xx/openpic_fdt.c optional fdt
powerpc/mpc85xx/pci_fdt.c optional pci mpc85xx
powerpc/ofw/ofw_cpu.c optional aim
+powerpc/ofw/ofw_machdep.c optional aim
powerpc/ofw/ofw_pcibus.c optional pci aim
powerpc/ofw/ofw_pcib_pci.c optional pci aim
powerpc/ofw/ofw_real.c optional aim
diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index 52934af690ad..eb34753e4f85 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -668,9 +668,19 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
count = MAX_CX_STATES;
}
- /* Set up all valid states. */
+ sc->cpu_non_c3 = 0;
sc->cpu_cx_count = 0;
cx_ptr = sc->cpu_cx_states;
+
+ /*
+ * C1 has been required since just after ACPI 1.0.
+ * Reserve the first slot for it.
+ */
+ cx_ptr->type = ACPI_STATE_C0;
+ cx_ptr++;
+ sc->cpu_cx_count++;
+
+ /* Set up all valid states. */
for (i = 0; i < count; i++) {
pkg = &top->Package.Elements[i + 1];
if (!ACPI_PKG_VALID(pkg, 4) ||
@@ -685,9 +695,14 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
/* Validate the state to see if we should use it. */
switch (cx_ptr->type) {
case ACPI_STATE_C1:
- sc->cpu_non_c3 = i;
- cx_ptr++;
- sc->cpu_cx_count++;
+ if (sc->cpu_cx_states[0].type == ACPI_STATE_C0) {
+ /* This is the first C1 state. Use the reserved slot. */
+ sc->cpu_cx_states[0] = *cx_ptr;
+ } else {
+ sc->cpu_non_c3 = i;
+ cx_ptr++;
+ sc->cpu_cx_count++;
+ }
continue;
case ACPI_STATE_C2:
sc->cpu_non_c3 = i;
@@ -726,6 +741,13 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
}
AcpiOsFree(buf.Pointer);
+ /* If C1 state was not found, we need one now. */
+ cx_ptr = sc->cpu_cx_states;
+ if (cx_ptr->type == ACPI_STATE_C0) {
+ cx_ptr->type = ACPI_STATE_C1;
+ cx_ptr->trans_lat = 0;
+ }
+
return (0);
}
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 3a044fd75f4c..d9736949596d 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -481,7 +481,7 @@ static device_method_t gpiobus_methods[] = {
{ 0, 0 }
};
-static driver_t gpiobus_driver = {
+driver_t gpiobus_driver = {
"gpiobus",
gpiobus_methods,
sizeof(struct gpiobus_softc)
diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c
index e92326e196a2..6a4c0c91938d 100644
--- a/sys/dev/gpio/gpioc.c
+++ b/sys/dev/gpio/gpioc.c
@@ -188,7 +188,7 @@ static device_method_t gpioc_methods[] = {
{ 0, 0 }
};
-static driver_t gpioc_driver = {
+driver_t gpioc_driver = {
"gpioc",
gpioc_methods,
sizeof(struct gpioc_softc)
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index ad4e8d9c3477..9cfbc2011ca8 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -784,10 +784,10 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
calcru(p, &kp->ki_rusage.ru_utime, &kp->ki_rusage.ru_stime);
PROC_SUNLOCK(p);
calccru(p, &kp->ki_childutime, &kp->ki_childstime);
-
- /* Some callers want child-times in a single value */
+ /* Some callers want child times in a single value. */
kp->ki_childtime = kp->ki_childstime;
timevaladd(&kp->ki_childtime, &kp->ki_childutime);
+
tp = NULL;
if (p->p_pgrp) {
kp->ki_pgid = p->p_pgrp->pg_id;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index d6c9854fa1fb..e3e8e288a179 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -2386,6 +2386,7 @@ sosetopt(struct socket *so, struct sockopt *sopt)
struct linger l;
struct timeval tv;
u_long val;
+ uint32_t val32;
#ifdef MAC
struct mac extmac;
#endif
@@ -2461,6 +2462,15 @@ sosetopt(struct socket *so, struct sockopt *sopt)
so->so_fibnum = 0;
}
break;
+
+ case SO_USER_COOKIE:
+ error = sooptcopyin(sopt, &val32, sizeof val32,
+ sizeof val32);
+ if (error)
+ goto bad;
+ so->so_user_cookie = val32;
+ break;
+
case SO_SNDBUF:
case SO_RCVBUF:
case SO_SNDLOWAT:
diff --git a/sys/netinet/cc.h b/sys/netinet/cc.h
new file mode 100644
index 000000000000..6f24f117bf54
--- /dev/null
+++ b/sys/netinet/cc.h
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2007-2008
+ * Swinburne University of Technology, Melbourne, Australia.
+ * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University, by Lawrence Stewart and James Healy,
+ * made possible in part by a grant from the Cisco University Research Program
+ * Fund at Community Foundation Silicon Valley.
+ *
+ * Portions of this software were developed at the Centre for Advanced
+ * Internet Architectures, Swinburne University of Technology, Melbourne,
+ * Australia by David Hayes under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This software was first released in 2007 by James Healy and Lawrence Stewart
+ * whilst working on the NewTCP research project at Swinburne University's
+ * Centre for Advanced Internet Architectures, Melbourne, Australia, which was
+ * made possible in part by a grant from the Cisco University Research Program
+ * Fund at Community Foundation Silicon Valley. More details are available at:
+ * http://caia.swin.edu.au/urp/newtcp/
+ */
+
+#ifndef _NETINET_CC_H_
+#define _NETINET_CC_H_
+
+/* XXX: TCP_CA_NAME_MAX define lives in tcp.h for compat reasons. */
+#include <netinet/tcp.h>
+
+/* Global CC vars. */
+extern STAILQ_HEAD(cc_head, cc_algo) cc_list;
+extern const int tcprexmtthresh;
+extern struct cc_algo newreno_cc_algo;
+
+/* Define the new net.inet.tcp.cc sysctl tree. */
+SYSCTL_DECL(_net_inet_tcp_cc);
+
+/* CC housekeeping functions. */
+void cc_init(void);
+int cc_register_algo(struct cc_algo *add_cc);
+int cc_deregister_algo(struct cc_algo *remove_cc);
+
+/*
+ * Wrapper around transport structs that contain same-named congestion
+ * control variables. Allows algos to be shared amongst multiple CC aware
+ * transprots.
+ */
+struct cc_var {
+ void *cc_data; /* Per-connection private CC algorithm data. */
+ int bytes_this_ack; /* # bytes acked by the current ACK. */
+ tcp_seq curack; /* Most recent ACK. */
+ uint32_t flags; /* Flags for cc_var (see below) */
+ int type; /* Indicates which ptr is valid in ccvc. */
+ union ccv_container {
+ struct tcpcb *tcp;
+ struct sctp_nets *sctp;
+ } ccvc;
+};
+
+/* cc_var flags. */
+#define CCF_ABC_SENTAWND 0x0001 /* ABC counted cwnd worth of bytes? */
+#define CCF_CWND_LIMITED 0x0002 /* Are we currently cwnd limited? */
+
+/* ACK types passed to the ack_received() hook. */
+#define CC_ACK 0x0001 /* Regular in sequence ACK. */
+#define CC_DUPACK 0x0002 /* Duplicate ACK. */
+#define CC_PARTIALACK 0x0004 /* Not yet. */
+#define CC_SACK 0x0008 /* Not yet. */
+
+/*
+ * Congestion signal types passed to the cong_signal() hook. The highest order 8
+ * bits (0x01000000 - 0x80000000) are reserved for CC algos to declare their own
+ * congestion signal types.
+ */
+#define CC_ECN 0x000001/* ECN marked packet received. */
+#define CC_RTO 0x000002/* RTO fired. */
+#define CC_RTO_ERR 0x000004/* RTO fired in error. */
+#define CC_NDUPACK 0x000008/* Threshold of dupack's reached. */
+
+/*
+ * Structure to hold data and function pointers that together represent a
+ * congestion control algorithm.
+ */
+struct cc_algo {
+ char name[TCP_CA_NAME_MAX];
+
+ /* Init global module state on kldload. */
+ int (*mod_init)(void);
+
+ /* Cleanup global module state on kldunload. */
+ int (*mod_destroy)(void);
+
+ /* Init CC state for a new control block. */
+ int (*cb_init)(struct cc_var *ccv);
+
+ /* Cleanup CC state for a terminating control block. */
+ void (*cb_destroy)(struct cc_var *ccv);
+
+ /* Init variables for a newly established connection. */
+ void (*conn_init)(struct cc_var *ccv);
+
+ /* Called on receipt of an ack. */
+ void (*ack_received)(struct cc_var *ccv, uint16_t type);
+
+ /* Called on detection of a congestion signal. */
+ void (*cong_signal)(struct cc_var *ccv, uint32_t type);
+
+ /* Called after exiting congestion recovery. */
+ void (*post_recovery)(struct cc_var *ccv);
+
+ /* Called when data transfer resumes after an idle period. */
+ void (*after_idle)(struct cc_var *ccv);
+
+ STAILQ_ENTRY (cc_algo) entries;
+};
+
+/* Macro to obtain the CC algo's struct ptr. */
+#define CC_ALGO(tp) ((tp)->cc_algo)
+
+/* Macro to obtain the CC algo's data ptr. */
+#define CC_DATA(tp) ((tp)->ccv->cc_data)
+
+/* Macro to obtain the system default CC algo's struct ptr. */
+#define CC_DEFAULT() STAILQ_FIRST(&cc_list)
+
+extern struct rwlock cc_list_lock;
+#define CC_LIST_LOCK_INIT() rw_init(&cc_list_lock, "cc_list")
+#define CC_LIST_LOCK_DESTROY() rw_destroy(&cc_list_lock)
+#define CC_LIST_RLOCK() rw_rlock(&cc_list_lock)
+#define CC_LIST_RUNLOCK() rw_runlock(&cc_list_lock)
+#define CC_LIST_WLOCK() rw_wlock(&cc_list_lock)
+#define CC_LIST_WUNLOCK() rw_wunlock(&cc_list_lock)
+#define CC_LIST_WLOCK_ASSERT() rw_assert(&cc_list_lock, RA_WLOCKED)
+
+#endif /* _NETINET_CC_H_ */
diff --git a/sys/netinet/cc/cc.c b/sys/netinet/cc/cc.c
new file mode 100644
index 000000000000..4643ca40105e
--- /dev/null
+++ b/sys/netinet/cc/cc.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 2007-2008
+ * Swinburne University of Technology, Melbourne, Australia.
+ * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University, by Lawrence Stewart and James Healy,
+ * made possible in part by a grant from the Cisco University Research Program
+ * Fund at Community Foundation Silicon Valley.
+ *
+ * Portions of this software were developed at the Centre for Advanced
+ * Internet Architectures, Swinburne University of Technology, Melbourne,
+ * Australia by David Hayes 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.
+ */
+
+/*
+ * This software was first released in 2007 by James Healy and Lawrence Stewart
+ * whilst working on the NewTCP research project at Swinburne University's
+ * Centre for Advanced Internet Architectures, Melbourne, Australia, which was
+ * made possible in part by a grant from the Cisco University Research Program
+ * Fund at Community Foundation Silicon Valley. More details are available at:
+ * http://caia.swin.edu.au/urp/newtcp/
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/libkern.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/rwlock.h>
+#include <sys/sbuf.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/cc.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_var.h>
+
+#include <netinet/cc/cc_module.h>
+
+/*
+ * List of available cc algorithms on the current system. First element
+ * is used as the system default CC algorithm.
+ */
+struct cc_head cc_list = STAILQ_HEAD_INITIALIZER(cc_list);
+
+/* Protects the cc_list TAILQ. */
+struct rwlock cc_list_lock;
+
+/*
+ * Set the default CC algorithm to new_default. The default is identified
+ * by being the first element in the cc_list TAILQ.
+ */
+static void
+cc_set_default(struct cc_algo *new_default)
+{
+ CC_LIST_WLOCK_ASSERT();
+
+ /*
+ * Make the requested system default CC algorithm the first element in
+ * the list if it isn't already.
+ */
+ if (new_default != CC_DEFAULT()) {
+ STAILQ_REMOVE(&cc_list, new_default, cc_algo, entries);
+ STAILQ_INSERT_HEAD(&cc_list, new_default, entries);
+ }
+}
+
+/*
+ * Sysctl handler to show and change the default CC algorithm.
+ */
+static int
+cc_default_algo(SYSCTL_HANDLER_ARGS)
+{
+ struct cc_algo *funcs;
+ int err, found;
+
+ err = found = 0;
+
+ if (req->newptr == NULL) {
+ char default_cc[TCP_CA_NAME_MAX];
+
+ /* Just print the current default. */
+ CC_LIST_RLOCK();
+ strlcpy(default_cc, CC_DEFAULT()->name, TCP_CA_NAME_MAX);
+ CC_LIST_RUNLOCK();
+ err = sysctl_handle_string(oidp, default_cc, 1, req);
+ } else {
+ /* Find algo with specified name and set it to default. */
+ CC_LIST_WLOCK();
+ STAILQ_FOREACH(funcs, &cc_list, entries) {
+ if (strncmp((char *)req->newptr, funcs->name,
+ TCP_CA_NAME_MAX) == 0) {
+ found = 1;
+ cc_set_default(funcs);
+ }
+ }
+ CC_LIST_WUNLOCK();
+
+ if (!found)
+ err = ESRCH;
+ }
+
+ return (err);
+}
+
+/*
+ * Sysctl handler to display the list of available CC algorithms.
+ */
+static int
+cc_list_available(SYSCTL_HANDLER_ARGS)
+{
+ struct cc_algo *algo;
+ struct sbuf *s;
+ int err, first;
+
+ err = 0;
+ first = 1;
+ s = sbuf_new(NULL, NULL, TCP_CA_NAME_MAX, SBUF_AUTOEXTEND);
+
+ if (s == NULL)
+ return (ENOMEM);
+
+ CC_LIST_RLOCK();
+ STAILQ_FOREACH(algo, &cc_list, entries) {
+ err = sbuf_printf(s, first ? "%s" : ", %s", algo->name);
+ if (err)
+ break;
+ first = 0;
+ }
+ CC_LIST_RUNLOCK();
+
+ if (!err) {
+ sbuf_finish(s);
+ err = sysctl_handle_string(oidp, sbuf_data(s), 1, req);
+ }
+
+ sbuf_delete(s);
+ return (err);
+}
+
+/*
+ * Initialise CC subsystem on system boot.
+ */
+void
+cc_init()
+{
+ CC_LIST_LOCK_INIT();
+ STAILQ_INIT(&cc_list);
+}
+
+/*
+ * Returns non-zero on success, 0 on failure.
+ */
+int
+cc_deregister_algo(struct cc_algo *remove_cc)
+{
+ struct cc_algo *funcs, *tmpfuncs;
+ struct tcpcb *tp;
+ struct inpcb *inp;
+ int err;
+
+ err = ENOENT;
+
+ /* Never allow newreno to be deregistered. */
+ if (&newreno_cc_algo == remove_cc)
+ return (EPERM);
+
+ /* Remove algo from cc_list so that new connections can't use it. */
+ CC_LIST_WLOCK();
+ STAILQ_FOREACH_SAFE(funcs, &cc_list, entries, tmpfuncs) {
+ if (funcs == remove_cc) {
+ /*
+ * If we're removing the current system default,
+ * reset the default to newreno.
+ */
+ if (strncmp(CC_DEFAULT()->name, remove_cc->name,
+ TCP_CA_NAME_MAX) == 0)
+ cc_set_default(&newreno_cc_algo);
+
+ STAILQ_REMOVE(&cc_list, funcs, cc_algo, entries);
+ err = 0;
+ break;
+ }
+ }
+ CC_LIST_WUNLOCK();
+
+ if (!err) {
+ /*
+ * Check all active control blocks and change any that are
+ * using this algorithm back to newreno. If the algorithm that
+ * was in use requires cleanup code to be run, call it.
+ *
+ * New connections already part way through being initialised
+ * with the CC algo we're removing will not race with this code
+ * because the INP_INFO_WLOCK is held during initialisation.
+ * We therefore don't enter the loop below until the connection
+ * list has stabilised.
+ */
+ INP_INFO_RLOCK(&V_tcbinfo);
+ LIST_FOREACH(inp, &V_tcb, inp_list) {
+ INP_WLOCK(inp);
+ /* Important to skip tcptw structs. */
+ if (!(inp->inp_flags & INP_TIMEWAIT) &&
+ (tp = intotcpcb(inp)) != NULL) {
+ /*
+ * By holding INP_WLOCK here, we are
+ * assured that the connection is not
+ * currently executing inside the CC
+ * module's functions i.e. it is safe to
+ * make the switch back to newreno.
+ */
+ if (CC_ALGO(tp) == remove_cc) {
+ tmpfuncs = CC_ALGO(tp);
+ /* Newreno does not require any init. */
+ CC_ALGO(tp) = &newreno_cc_algo;
+ if (tmpfuncs->cb_destroy != NULL)
+ tmpfuncs->cb_destroy(tp->ccv);
+ }
+ }
+ INP_WUNLOCK(inp);
+ }
+ INP_INFO_RUNLOCK(&V_tcbinfo);
+ }
+
+ return (err);
+}
+
+/*
+ * Returns 0 on success, non-zero on failure.
+ */
+int
+cc_register_algo(struct cc_algo *add_cc)
+{
+ struct cc_algo *funcs;
+ int err;
+
+ err = 0;
+
+ /*
+ * Iterate over list of registered CC algorithms and make sure
+ * we're not trying to add a duplicate.
+ */
+ CC_LIST_WLOCK();
+ STAILQ_FOREACH(funcs, &cc_list, entries) {
+ if (funcs == add_cc || strncmp(funcs->name, add_cc->name,
+ TCP_CA_NAME_MAX) == 0)
+ err = EEXIST;
+ }
+
+ if (!err)
+ STAILQ_INSERT_TAIL(&cc_list, add_cc, entries);
+
+ CC_LIST_WUNLOCK();
+
+ return (err);
+}
+
+/*
+ * Handles kld related events. Returns 0 on success, non-zero on failure.
+ */
+int
+cc_modevent(module_t mod, int event_type, void *data)
+{
+ struct cc_algo *algo;
+ int err;
+
+ err = 0;
+ algo = (struct cc_algo *)data;
+
+ switch(event_type) {
+ case MOD_LOAD:
+ if (algo->mod_init != NULL)
+ err = algo->mod_init();
+ if (!err)
+ err = cc_register_algo(algo);
+ break;
+
+ case MOD_QUIESCE:
+ case MOD_SHUTDOWN:
+ case MOD_UNLOAD:
+ err = cc_deregister_algo(algo);
+ if (!err && algo->mod_destroy != NULL)
+ algo->mod_destroy();
+ if (err == ENOENT)
+ err = 0;
+ break;
+
+ default:
+ err = EINVAL;
+ break;
+ }
+
+ return (err);
+}
+
+/* Declare sysctl tree and populate it. */
+SYSCTL_NODE(_net_inet_tcp, OID_AUTO, cc, CTLFLAG_RW, NULL,
+ "congestion control related settings");
+
+SYSCTL_PROC(_net_inet_tcp_cc, OID_AUTO, algorithm, CTLTYPE_STRING|CTLFLAG_RW,
+ NULL, 0, cc_default_algo, "A", "default congestion control algorithm");
+
+SYSCTL_PROC(_net_inet_tcp_cc, OID_AUTO, available, CTLTYPE_STRING|CTLFLAG_RD,
+ NULL, 0, cc_list_available, "A",
+ "list available congestion control algorithms");
diff --git a/sys/netinet/cc/cc_module.h b/sys/netinet/cc/cc_module.h
new file mode 100644
index 000000000000..f3fe7525c5b9
--- /dev/null
+++ b/sys/netinet/cc/cc_module.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
+ * All rights reserved.
+ *
+ * This software was developed by Lawrence Stewart while studying at the Centre
+ * for Advanced Internet Architectures, Swinburne University, made possible in
+ * part by a grant from the Cisco University Research Program Fund at Community
+ * Foundation Silicon Valley.
+ *
+ * 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$
+ */
+
+/*
+ * This software was first released in 2009 by Lawrence Stewart as part of the
+ * NewTCP research project at Swinburne University's Centre for Advanced
+ * Internet Architectures, Melbourne, Australia, which was made possible in part
+ * by a grant from the Cisco University Research Program Fund at Community
+ * Foundation Silicon Valley. More details are available at:
+ * http://caia.swin.edu.au/urp/newtcp/
+ */
+
+#ifndef _NETINET_CC_MODULE_H_
+#define _NETINET_CC_MODULE_H_
+
+/*
+ * Allows a CC algorithm to manipulate a commonly named CC variable regardless
+ * of the transport protocol and associated C struct.
+ * XXXLAS: Out of action until the work to support SCTP is done.
+ *
+#define CCV(ccv, what) \
+(*( \
+ (ccv)->type == IPPROTO_TCP ? &(ccv)->ccvc.tcp->what : \
+ &(ccv)->ccvc.sctp->what \
+))
+ */
+#define CCV(ccv, what) (ccv)->ccvc.tcp->what
+
+#define DECLARE_CC_MODULE(ccname, ccalgo) \
+ static moduledata_t cc_##ccname = { \
+ .name = #ccname, \
+ .evhand = cc_modevent, \
+ .priv = ccalgo \
+ }; \
+ DECLARE_MODULE(ccname, cc_##ccname, \
+ SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY)
+
+int cc_modevent(module_t mod, int type, void *data);
+
+#endif /* _NETINET_CC_MODULE_H_ */
diff --git a/sys/netinet/cc/cc_newreno.c b/sys/netinet/cc/cc_newreno.c
new file mode 100644
index 000000000000..e3835100ddb6
--- /dev/null
+++ b/sys/netinet/cc/cc_newreno.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
+ * The Regents of the University of California.
+ * Copyright (c) 2007-2008,2010
+ * Swinburne University of Technology, Melbourne, Australia.
+ * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University, by Lawrence Stewart, James Healy and
+ * David Hayes, made possible in part by a grant from the Cisco University
+ * Research Program Fund at Community Foundation Silicon Valley.
+ *
+ * Portions of this software were developed at the Centre for Advanced
+ * Internet Architectures, Swinburne University of Technology, Melbourne,
+ * Australia by David Hayes 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.
+ */
+
+/*
+ * This software was first released in 2007 by James Healy and Lawrence Stewart
+ * whilst working on the NewTCP research project at Swinburne University's
+ * Centre for Advanced Internet Architectures, Melbourne, Australia, which was
+ * made possible in part by a grant from the Cisco University Research Program
+ * Fund at Community Foundation Silicon Valley. More details are available at:
+ * http://caia.swin.edu.au/urp/newtcp/
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/cc.h>
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_var.h>
+
+#include <netinet/cc/cc_module.h>
+
+void newreno_ack_received(struct cc_var *ccv, uint16_t type);
+void newreno_cong_signal(struct cc_var *ccv, uint32_t type);
+void newreno_post_recovery(struct cc_var *ccv);
+void newreno_after_idle(struct cc_var *ccv);
+
+struct cc_algo newreno_cc_algo = {
+ .name = "newreno",
+ .ack_received = newreno_ack_received,
+ .cong_signal = newreno_cong_signal,
+ .post_recovery = newreno_post_recovery,
+ .after_idle = newreno_after_idle
+};
+
+/*
+ * Increase cwnd on receipt of a successful ACK:
+ * if cwnd <= ssthresh, increases by 1 MSS per ACK
+ * if cwnd > ssthresh, increase by ~1 MSS per RTT
+ */
+void
+newreno_ack_received(struct cc_var *ccv, uint16_t type)
+{
+ if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) &&
+ (ccv->flags & CCF_CWND_LIMITED)) {
+ u_int cw = CCV(ccv, snd_cwnd);
+ u_int incr = CCV(ccv, t_maxseg);
+
+ /*
+ * Regular in-order ACK, open the congestion window.
+ * Method depends on which congestion control state we're
+ * in (slow start or cong avoid) and if ABC (RFC 3465) is
+ * enabled.
+ *
+ * slow start: cwnd <= ssthresh
+ * cong avoid: cwnd > ssthresh
+ *
+ * slow start and ABC (RFC 3465):
+ * Grow cwnd exponentially by the amount of data
+ * ACKed capping the max increment per ACK to
+ * (abc_l_var * maxseg) bytes.
+ *
+ * slow start without ABC (RFC 5681):
+ * Grow cwnd exponentially by maxseg per ACK.
+ *
+ * cong avoid and ABC (RFC 3465):
+ * Grow cwnd linearly by maxseg per RTT for each
+ * cwnd worth of ACKed data.
+ *
+ * cong avoid without ABC (RFC 5681):
+ * Grow cwnd linearly by approximately maxseg per RTT using
+ * maxseg^2 / cwnd per ACK as the increment.
+ * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
+ * avoid capping cwnd.
+ */
+ if (cw > CCV(ccv, snd_ssthresh)) {
+ if (V_tcp_do_rfc3465) {
+ if (ccv->flags & CCF_ABC_SENTAWND)
+ ccv->flags &= ~CCF_ABC_SENTAWND;
+ else
+ incr = 0;
+ } else
+ incr = max((incr * incr / cw), 1);
+ } else if (V_tcp_do_rfc3465) {
+ /*
+ * In slow-start with ABC enabled and no RTO in sight?
+ * (Must not use abc_l_var > 1 if slow starting after
+ * an RTO. On RTO, snd_nxt = snd_una, so the
+ * snd_nxt == snd_max check is sufficient to
+ * handle this).
+ *
+ * XXXLAS: Find a way to signal SS after RTO that
+ * doesn't rely on tcpcb vars.
+ */
+ if (CCV(ccv, snd_nxt) == CCV(ccv, snd_max))
+ incr = min(ccv->bytes_this_ack,
+ V_tcp_abc_l_var * CCV(ccv, t_maxseg));
+ else
+ incr = min(ccv->bytes_this_ack, CCV(ccv, t_maxseg));
+ }
+ /* ABC is on by default, so incr equals 0 frequently. */
+ if (incr > 0)
+ CCV(ccv, snd_cwnd) = min(cw + incr,
+ TCP_MAXWIN << CCV(ccv, snd_scale));
+ }
+}
+
+/*
+ * manage congestion signals
+ */
+void
+newreno_cong_signal(struct cc_var *ccv, uint32_t type)
+{
+ u_int win;
+
+ win = max(CCV(ccv, snd_cwnd) / 2 / CCV(ccv, t_maxseg), 2) *
+ CCV(ccv, t_maxseg);
+
+ switch (type) {
+ case CC_NDUPACK:
+ if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) {
+ if (!IN_CONGRECOVERY(CCV(ccv, t_flags)))
+ CCV(ccv, snd_ssthresh) = win;
+ ENTER_RECOVERY(CCV(ccv, t_flags));
+ }
+ break;
+ case CC_ECN:
+ if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) {
+ CCV(ccv, snd_ssthresh) = win;
+ CCV(ccv, snd_cwnd) = win;
+ ENTER_CONGRECOVERY(CCV(ccv, t_flags));
+ }
+ break;
+ }
+}
+
+/*
+ * decrease the cwnd in response to packet loss or a transmit timeout.
+ * th can be null, in which case cwnd will be set according to reno instead
+ * of new reno.
+ */
+void
+newreno_post_recovery(struct cc_var *ccv)
+{
+ if (IN_FASTRECOVERY(CCV(ccv, t_flags))) {
+ /*
+ * Fast recovery will conclude after returning from this
+ * function. Window inflation should have left us with
+ * approximately snd_ssthresh outstanding data. But in case we
+ * would be inclined to send a burst, better to do it via the
+ * slow start mechanism.
+ *
+ * XXXLAS: Find a way to do this without needing curack
+ */
+ if (SEQ_GT(ccv->curack + CCV(ccv, snd_ssthresh),
+ CCV(ccv, snd_max)))
+ CCV(ccv, snd_cwnd) = CCV(ccv, snd_max) -
+ ccv->curack + CCV(ccv, t_maxseg);
+ else
+ CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh);
+ }
+}
+
+/*
+ * if a connection has been idle for a while and more data is ready to be sent,
+ * reset cwnd
+ */
+void
+newreno_after_idle(struct cc_var *ccv)
+{
+ /*
+ * 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 (V_tcp_do_rfc3390)
+ CCV(ccv, snd_cwnd) = min(4 * CCV(ccv, t_maxseg),
+ max(2 * CCV(ccv, t_maxseg), 4380));
+ else
+ CCV(ccv, snd_cwnd) = CCV(ccv, t_maxseg) * 2;
+}
+
+
+DECLARE_CC_MODULE(newreno, &newreno_cc_algo);
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index cf5d8d03a90e..fdcc5fd4c1df 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -192,10 +192,13 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_SETFIB, /* arg1=FIB number */
O_FIB, /* arg1=FIB desired fib number */
+
+ O_SOCKARG, /* socket argument */
O_LAST_OPCODE /* not an opcode! */
};
+
/*
* The extension header are filtered only for presence using a bit
* vector with a flag for each header.
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index c291089c6f85..43b2d1114295 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -1801,6 +1801,39 @@ do { \
match = 1;
break;
+ case O_SOCKARG: {
+ struct inpcb *inp = args->inp;
+ struct inpcbinfo *pi;
+
+ if (is_ipv6) /* XXX can we remove this ? */
+ break;
+
+ if (proto == IPPROTO_TCP)
+ pi = &V_tcbinfo;
+ else if (proto == IPPROTO_UDP)
+ pi = &V_udbinfo;
+ else
+ break;
+
+ /* For incomming packet, lookup up the
+ inpcb using the src/dest ip/port tuple */
+ if (inp == NULL) {
+ INP_INFO_RLOCK(pi);
+ inp = in_pcblookup_hash(pi,
+ src_ip, htons(src_port),
+ dst_ip, htons(dst_port),
+ 0, NULL);
+ INP_INFO_RUNLOCK(pi);
+ }
+
+ if (inp && inp->inp_socket) {
+ tablearg = inp->inp_socket->so_user_cookie;
+ if (tablearg)
+ match = 1;
+ }
+ break;
+ }
+
case O_TAGGED: {
struct m_tag *mtag;
uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ?
diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c
index c50572873a16..0c903eedf5c7 100644
--- a/sys/netinet/ipfw/ip_fw_sockopt.c
+++ b/sys/netinet/ipfw/ip_fw_sockopt.c
@@ -572,6 +572,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
case O_IPTOS:
case O_IPPRECEDENCE:
case O_IPVER:
+ case O_SOCKARG:
case O_TCPWIN:
case O_TCPFLAGS:
case O_TCPOPTS:
diff --git a/sys/netinet/libalias/alias_sctp.c b/sys/netinet/libalias/alias_sctp.c
index 22cf5cd65457..3bd5331d1764 100644
--- a/sys/netinet/libalias/alias_sctp.c
+++ b/sys/netinet/libalias/alias_sctp.c
@@ -1,9 +1,7 @@
-/**
- * @file alias_sctp.c
- * Copyright (c) 2008, Centre for Advanced Internet Architectures
- * Swinburne University of Technology, Melbourne, Australia
- * (CRICOS number 00111D).
- *
+/*-
+ * Copyright (c) 2008
+ * Swinburne University of Technology, Melbourne, Australia.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,11 +10,7 @@
* 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. The names of the authors, the "Centre for Advanced Internet Architectures"
- * and "Swinburne University of Technology" may not be used to endorse
- * or promote products derived from this software without specific
- * prior written permission.
- *
+ *
* 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
@@ -28,7 +22,9 @@
* 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.
- *
+ */
+
+/*
* Alias_sctp forms part of the libalias kernel module to handle
* Network Address Translation (NAT) for the SCTP protocol.
*
diff --git a/sys/netinet/libalias/alias_sctp.h b/sys/netinet/libalias/alias_sctp.h
index b4608ee4bbe3..80ed96568d4d 100644
--- a/sys/netinet/libalias/alias_sctp.h
+++ b/sys/netinet/libalias/alias_sctp.h
@@ -1,9 +1,7 @@
-/**
- * @file alias_sctp.h
- * Copyright (c) 2008, Centre for Advanced Internet Architectures
- * Swinburne University of Technology, Melbourne, Australia
- * (CRICOS number 00111D).
- *
+/*-
+ * Copyright (c) 2008
+ * Swinburne University of Technology, Melbourne, Australia.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -12,11 +10,7 @@
* 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. The names of the authors, the "Centre for Advanced Internet Architectures"
- * and "Swinburne University of Technology" may not be used to endorse
- * or promote products derived from this software without specific
- * prior written permission.
- *
+ *
* 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
@@ -28,7 +22,9 @@
* 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.
- *
+ */
+
+/*
* Alias_sctp forms part of the libalias kernel module to handle
* Network Address Translation (NAT) for the SCTP protocol.
*
diff --git a/sys/netinet/siftr.c b/sys/netinet/siftr.c
index 176d0d0a30fe..5f2a6927b2fa 100644
--- a/sys/netinet/siftr.c
+++ b/sys/netinet/siftr.c
@@ -1,7 +1,6 @@
/*-
- * Copyright (c) 2007-2009, Centre for Advanced Internet Architectures
- * Swinburne University of Technology, Melbourne, Australia
- * (CRICOS number 00111D).
+ * Copyright (c) 2007-2009
+ * Swinburne University of Technology, Melbourne, Australia.
* Copyright (c) 2009-2010, The FreeBSD Foundation
* All rights reserved.
*
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 22a2ea4a89c7..8fb9a52dc2a8 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,6 +1,20 @@
/*-
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007-2008,2010
+ * Swinburne University of Technology, Melbourne, Australia.
+ * Copyright (c) 2009-2010 Lawrence Stewart <lstewart@freebsd.org>
+ * Copyright (c) 2010 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University, by Lawrence Stewart, James Healy and
+ * David Hayes, made possible in part by a grant from the Cisco University
+ * Research Program Fund at Community Foundation Silicon Valley.
+ *
+ * Portions of this software were developed at the Centre for Advanced
+ * Internet Architectures, Swinburne University of Technology, Melbourne,
+ * Australia by David Hayes 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
@@ -61,6 +75,7 @@ __FBSDID("$FreeBSD$");
#define TCPSTATES /* for logging */
+#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
@@ -75,7 +90,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
-#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
@@ -96,7 +110,7 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
-static const int tcprexmtthresh = 3;
+const int tcprexmtthresh = 3;
VNET_DEFINE(struct tcpstat, tcpstat);
SYSCTL_VNET_STRUCT(_net_inet_tcp, TCPCTL_STATS, stats, CTLFLAG_RW,
@@ -132,19 +146,16 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, rfc3042, CTLFLAG_RW,
"Enable RFC 3042 (Limited Transmit)");
VNET_DEFINE(int, tcp_do_rfc3390) = 1;
-#define V_tcp_do_rfc3390 VNET(tcp_do_rfc3390)
SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, rfc3390, CTLFLAG_RW,
&VNET_NAME(tcp_do_rfc3390), 0,
"Enable RFC 3390 (Increasing TCP's Initial Congestion Window)");
VNET_DEFINE(int, tcp_do_rfc3465) = 1;
-#define V_tcp_do_rfc3465 VNET(tcp_do_rfc3465)
SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, rfc3465, CTLFLAG_RW,
&VNET_NAME(tcp_do_rfc3465), 0,
"Enable RFC 3465 (Appropriate Byte Counting)");
VNET_DEFINE(int, tcp_abc_l_var) = 2;
-#define V_tcp_abc_l_var VNET(tcp_abc_l_var)
SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, abc_l_var, CTLFLAG_RW,
&VNET_NAME(tcp_abc_l_var), 2,
"Cap the max cwnd increment during slow-start to this number of segments");
@@ -203,8 +214,10 @@ static void tcp_pulloutofband(struct socket *,
struct tcphdr *, struct mbuf *, int);
static void tcp_xmit_timer(struct tcpcb *, int);
static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *);
-static void inline
- tcp_congestion_exp(struct tcpcb *);
+static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th,
+ uint16_t type);
+static void inline cc_conn_init(struct tcpcb *tp);
+static void inline cc_post_recovery(struct tcpcb *tp, struct tcphdr *th);
/*
* Kernel module interface for updating tcpstat. The argument is an index
@@ -220,20 +233,188 @@ kmod_tcpstat_inc(int statnum)
(*((u_long *)&V_tcpstat + statnum))++;
}
+/*
+ * CC wrapper hook functions
+ */
static void inline
-tcp_congestion_exp(struct tcpcb *tp)
+cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type)
{
- u_int win;
-
- win = min(tp->snd_wnd, tp->snd_cwnd) /
- 2 / tp->t_maxseg;
- if (win < 2)
- win = 2;
- tp->snd_ssthresh = win * tp->t_maxseg;
- ENTER_FASTRECOVERY(tp);
- tp->snd_recover = tp->snd_max;
- if (tp->t_flags & TF_ECN_PERMIT)
- tp->t_flags |= TF_ECN_SND_CWR;
+ INP_WLOCK_ASSERT(tp->t_inpcb);
+
+ tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th);
+ if (tp->snd_cwnd == min(tp->snd_cwnd, tp->snd_wnd))
+ tp->ccv->flags |= CCF_CWND_LIMITED;
+ else
+ tp->ccv->flags &= ~CCF_CWND_LIMITED;
+
+ if (type == CC_ACK) {
+ if (tp->snd_cwnd > tp->snd_ssthresh) {
+ tp->t_bytes_acked += min(tp->ccv->bytes_this_ack,
+ V_tcp_abc_l_var * tp->t_maxseg);
+ if (tp->t_bytes_acked >= tp->snd_cwnd) {
+ tp->t_bytes_acked -= tp->snd_cwnd;
+ tp->ccv->flags |= CCF_ABC_SENTAWND;
+ }
+ } else {
+ tp->ccv->flags &= ~CCF_ABC_SENTAWND;
+ tp->t_bytes_acked = 0;
+ }
+ }
+
+ if (CC_ALGO(tp)->ack_received != NULL) {
+ /* XXXLAS: Find a way to live without this */
+ tp->ccv->curack = th->th_ack;
+ CC_ALGO(tp)->ack_received(tp->ccv, type);
+ }
+}
+
+static void inline
+cc_conn_init(struct tcpcb *tp)
+{
+ struct hc_metrics_lite metrics;
+ struct inpcb *inp = tp->t_inpcb;
+ int rtt;
+#ifdef INET6
+ int isipv6 = ((inp->inp_vflag & INP_IPV6) != 0) ? 1 : 0;
+#endif
+
+ INP_WLOCK_ASSERT(tp->t_inpcb);
+
+ tcp_hc_get(&inp->inp_inc, &metrics);
+
+ if (tp->t_srtt == 0 && (rtt = metrics.rmx_rtt)) {
+ tp->t_srtt = rtt;
+ tp->t_rttbest = tp->t_srtt + TCP_RTT_SCALE;
+ TCPSTAT_INC(tcps_usedrtt);
+ if (metrics.rmx_rttvar) {
+ tp->t_rttvar = metrics.rmx_rttvar;
+ TCPSTAT_INC(tcps_usedrttvar);
+ } else {
+ /* default variation is +- 1 rtt */
+ tp->t_rttvar =
+ tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
+ }
+ TCPT_RANGESET(tp->t_rxtcur,
+ ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
+ tp->t_rttmin, TCPTV_REXMTMAX);
+ }
+ if (metrics.rmx_ssthresh) {
+ /*
+ * There's some sort of gateway or interface
+ * buffer limit on the path. Use this to set
+ * the slow start threshhold, but set the
+ * threshold to no less than 2*mss.
+ */
+ tp->snd_ssthresh = max(2 * tp->t_maxseg, metrics.rmx_ssthresh);
+ TCPSTAT_INC(tcps_usedssthresh);
+ }
+
+ /*
+ * Set the slow-start flight size depending on whether this
+ * is a local network or not.
+ *
+ * Extend this so we cache the cwnd too and retrieve it here.
+ * Make cwnd even bigger than RFC3390 suggests but only if we
+ * have previous experience with the remote host. Be careful
+ * not make cwnd bigger than remote receive window or our own
+ * send socket buffer. Maybe put some additional upper bound
+ * on the retrieved cwnd. Should do incremental updates to
+ * hostcache when cwnd collapses so next connection doesn't
+ * overloads the path again.
+ *
+ * XXXAO: Initializing the CWND from the hostcache is broken
+ * and in its current form not RFC conformant. It is disabled
+ * until fixed or removed entirely.
+ *
+ * RFC3390 says only do this if SYN or SYN/ACK didn't got lost.
+ * We currently check only in syncache_socket for that.
+ */
+/* #define TCP_METRICS_CWND */
+#ifdef TCP_METRICS_CWND
+ if (metrics.rmx_cwnd)
+ tp->snd_cwnd = max(tp->t_maxseg, min(metrics.rmx_cwnd / 2,
+ min(tp->snd_wnd, so->so_snd.sb_hiwat)));
+ else
+#endif
+ if (V_tcp_do_rfc3390)
+ tp->snd_cwnd = min(4 * tp->t_maxseg,
+ max(2 * tp->t_maxseg, 4380));
+#ifdef INET6
+ else if ((isipv6 && in6_localaddr(&inp->in6p_faddr)) ||
+ (!isipv6 && in_localaddr(inp->inp_faddr)))
+#else
+ else if (in_localaddr(inp->inp_faddr))
+#endif
+ tp->snd_cwnd = tp->t_maxseg * V_ss_fltsz_local;
+ else
+ tp->snd_cwnd = tp->t_maxseg * V_ss_fltsz;
+
+ if (CC_ALGO(tp)->conn_init != NULL)
+ CC_ALGO(tp)->conn_init(tp->ccv);
+}
+
+void inline
+cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type)
+{
+ INP_WLOCK_ASSERT(tp->t_inpcb);
+
+ switch(type) {
+ case CC_NDUPACK:
+ if (!IN_FASTRECOVERY(tp->t_flags)) {
+ tp->snd_recover = tp->snd_max;
+ if (tp->t_flags & TF_ECN_PERMIT)
+ tp->t_flags |= TF_ECN_SND_CWR;
+ }
+ break;
+ case CC_ECN:
+ if (!IN_CONGRECOVERY(tp->t_flags)) {
+ TCPSTAT_INC(tcps_ecn_rcwnd);
+ tp->snd_recover = tp->snd_max;
+ if (tp->t_flags & TF_ECN_PERMIT)
+ tp->t_flags |= TF_ECN_SND_CWR;
+ }
+ break;
+ case CC_RTO:
+ tp->t_dupacks = 0;
+ tp->t_bytes_acked = 0;
+ EXIT_RECOVERY(tp->t_flags);
+ tp->snd_cwnd = tp->t_maxseg;
+ break;
+ case CC_RTO_ERR:
+ TCPSTAT_INC(tcps_sndrexmitbad);
+ /* RTO was unnecessary, so reset everything. */
+ tp->snd_cwnd = tp->snd_cwnd_prev;
+ tp->snd_ssthresh = tp->snd_ssthresh_prev;
+ tp->snd_recover = tp->snd_recover_prev;
+ if (tp->t_flags & TF_WASFRECOVERY)
+ ENTER_FASTRECOVERY(tp->t_flags);
+ if (tp->t_flags & TF_WASCRECOVERY)
+ ENTER_CONGRECOVERY(tp->t_flags);
+ tp->snd_nxt = tp->snd_max;
+ tp->t_badrxtwin = 0;
+ break;
+ }
+
+ if (CC_ALGO(tp)->cong_signal != NULL) {
+ if (th != NULL)
+ tp->ccv->curack = th->th_ack;
+ CC_ALGO(tp)->cong_signal(tp->ccv, type);
+ }
+}
+
+static void inline
+cc_post_recovery(struct tcpcb *tp, struct tcphdr *th)
+{
+ INP_WLOCK_ASSERT(tp->t_inpcb);
+
+ /* XXXLAS: KASSERT that we're in recovery? */
+
+ if (CC_ALGO(tp)->post_recovery != NULL) {
+ tp->ccv->curack = th->th_ack;
+ CC_ALGO(tp)->post_recovery(tp->ccv);
+ }
+ /* XXXLAS: EXIT_RECOVERY ? */
+ tp->t_bytes_acked = 0;
}
/* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */
@@ -1157,14 +1338,9 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
TCPSTAT_INC(tcps_ecn_ect1);
break;
}
- /*
- * Congestion experienced.
- * Ignore if we are already trying to recover.
- */
- if ((thflags & TH_ECE) &&
- SEQ_LEQ(th->th_ack, tp->snd_recover)) {
- TCPSTAT_INC(tcps_ecn_rcwnd);
- tcp_congestion_exp(tp);
+ /* Congestion experienced. */
+ if (thflags & TH_ECE) {
+ cc_cong_signal(tp, th, CC_ECN);
}
}
@@ -1259,15 +1435,9 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (tlen == 0) {
if (SEQ_GT(th->th_ack, tp->snd_una) &&
SEQ_LEQ(th->th_ack, tp->snd_max) &&
- tp->snd_cwnd >= tp->snd_wnd &&
- ((!V_tcp_do_newreno &&
- !(tp->t_flags & TF_SACK_PERMIT) &&
- tp->t_dupacks < tcprexmtthresh) ||
- ((V_tcp_do_newreno ||
- (tp->t_flags & TF_SACK_PERMIT)) &&
- !IN_FASTRECOVERY(tp) &&
- (to.to_flags & TOF_SACK) == 0 &&
- TAILQ_EMPTY(&tp->snd_holes)))) {
+ !IN_RECOVERY(tp->t_flags) &&
+ (to.to_flags & TOF_SACK) == 0 &&
+ TAILQ_EMPTY(&tp->snd_holes)) {
/*
* This is a pure ack for outstanding data.
*/
@@ -1287,15 +1457,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if (tp->t_rxtshift == 1 &&
(int)(ticks - tp->t_badrxtwin) < 0) {
- TCPSTAT_INC(tcps_sndrexmitbad);
- tp->snd_cwnd = tp->snd_cwnd_prev;
- tp->snd_ssthresh =
- tp->snd_ssthresh_prev;
- tp->snd_recover = tp->snd_recover_prev;
- if (tp->t_flags & TF_WASFRECOVERY)
- ENTER_FASTRECOVERY(tp);
- tp->snd_nxt = tp->snd_max;
- tp->t_badrxtwin = 0;
+ cc_cong_signal(tp, th, CC_RTO_ERR);
}
/*
@@ -1321,13 +1483,22 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
tcp_xmit_timer(tp,
ticks - tp->t_rtttime);
}
- acked = th->th_ack - tp->snd_una;
+ acked = BYTES_THIS_ACK(tp, th);
TCPSTAT_INC(tcps_rcvackpack);
TCPSTAT_ADD(tcps_rcvackbyte, acked);
sbdrop(&so->so_snd, acked);
if (SEQ_GT(tp->snd_una, tp->snd_recover) &&
SEQ_LEQ(th->th_ack, tp->snd_recover))
tp->snd_recover = th->th_ack - 1;
+
+ /*
+ * Let the congestion control algorithm update
+ * congestion control related information. This
+ * typically means increasing the congestion
+ * window.
+ */
+ cc_ack_received(tp, th, CC_ACK);
+
tp->snd_una = th->th_ack;
/*
* Pull snd_wl2 up to prevent seq wrap relative
@@ -1587,6 +1758,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
thflags &= ~TH_SYN;
} else {
tp->t_state = TCPS_ESTABLISHED;
+ cc_conn_init(tp);
tcp_timer_activate(tp, TT_KEEP, tcp_keepidle);
}
} else {
@@ -1990,6 +2162,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
tp->t_flags &= ~TF_NEEDFIN;
} else {
tp->t_state = TCPS_ESTABLISHED;
+ cc_conn_init(tp);
tcp_timer_activate(tp, TT_KEEP, tcp_keepidle);
}
/*
@@ -2058,11 +2231,10 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
th->th_ack != tp->snd_una)
tp->t_dupacks = 0;
else if (++tp->t_dupacks > tcprexmtthresh ||
- ((V_tcp_do_newreno ||
- (tp->t_flags & TF_SACK_PERMIT)) &&
- IN_FASTRECOVERY(tp))) {
+ IN_FASTRECOVERY(tp->t_flags)) {
+ cc_ack_received(tp, th, CC_DUPACK);
if ((tp->t_flags & TF_SACK_PERMIT) &&
- IN_FASTRECOVERY(tp)) {
+ IN_FASTRECOVERY(tp->t_flags)) {
int awnd;
/*
@@ -2093,19 +2265,20 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
* recovery.
*/
if (tp->t_flags & TF_SACK_PERMIT) {
- if (IN_FASTRECOVERY(tp)) {
+ if (IN_FASTRECOVERY(tp->t_flags)) {
tp->t_dupacks = 0;
break;
}
- } else if (V_tcp_do_newreno ||
- V_tcp_do_ecn) {
+ } else {
if (SEQ_LEQ(th->th_ack,
tp->snd_recover)) {
tp->t_dupacks = 0;
break;
}
}
- tcp_congestion_exp(tp);
+ /* Congestion signal before ack. */
+ cc_cong_signal(tp, th, CC_NDUPACK);
+ cc_ack_received(tp, th, CC_DUPACK);
tcp_timer_activate(tp, TT_REXMT, 0);
tp->t_rtttime = 0;
if (tp->t_flags & TF_SACK_PERMIT) {
@@ -2129,6 +2302,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
tp->snd_nxt = onxt;
goto drop;
} else if (V_tcp_do_rfc3042) {
+ cc_ack_received(tp, th, CC_DUPACK);
u_long oldcwnd = tp->snd_cwnd;
tcp_seq oldsndmax = tp->snd_max;
u_int sent;
@@ -2170,37 +2344,14 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
* If the congestion window was inflated to account
* for the other side's cached packets, retract it.
*/
- if (V_tcp_do_newreno || (tp->t_flags & TF_SACK_PERMIT)) {
- if (IN_FASTRECOVERY(tp)) {
- if (SEQ_LT(th->th_ack, tp->snd_recover)) {
- if (tp->t_flags & TF_SACK_PERMIT)
- tcp_sack_partialack(tp, th);
- else
- tcp_newreno_partial_ack(tp, th);
- } else {
- /*
- * Out of fast recovery.
- * Window inflation should have left us
- * with approximately snd_ssthresh
- * outstanding data.
- * But in case we would be inclined to
- * send a burst, better to do it via
- * the slow start mechanism.
- */
- if (SEQ_GT(th->th_ack +
- tp->snd_ssthresh,
- tp->snd_max))
- tp->snd_cwnd = tp->snd_max -
- th->th_ack +
- tp->t_maxseg;
- else
- tp->snd_cwnd = tp->snd_ssthresh;
- }
- }
- } else {
- if (tp->t_dupacks >= tcprexmtthresh &&
- tp->snd_cwnd > tp->snd_ssthresh)
- tp->snd_cwnd = tp->snd_ssthresh;
+ if (IN_FASTRECOVERY(tp->t_flags)) {
+ if (SEQ_LT(th->th_ack, tp->snd_recover)) {
+ if (tp->t_flags & TF_SACK_PERMIT)
+ tcp_sack_partialack(tp, th);
+ else
+ tcp_newreno_partial_ack(tp, th);
+ } else
+ cc_post_recovery(tp, th);
}
tp->t_dupacks = 0;
/*
@@ -2231,7 +2382,7 @@ process_ACK:
("tcp_input: process_ACK ti_locked %d", ti_locked));
INP_WLOCK_ASSERT(tp->t_inpcb);
- acked = th->th_ack - tp->snd_una;
+ acked = BYTES_THIS_ACK(tp, th);
TCPSTAT_INC(tcps_rcvackpack);
TCPSTAT_ADD(tcps_rcvackbyte, acked);
@@ -2242,16 +2393,8 @@ process_ACK:
* original cwnd and ssthresh, and proceed to transmit where
* we left off.
*/
- if (tp->t_rxtshift == 1 && (int)(ticks - tp->t_badrxtwin) < 0) {
- TCPSTAT_INC(tcps_sndrexmitbad);
- tp->snd_cwnd = tp->snd_cwnd_prev;
- tp->snd_ssthresh = tp->snd_ssthresh_prev;
- tp->snd_recover = tp->snd_recover_prev;
- if (tp->t_flags & TF_WASFRECOVERY)
- ENTER_FASTRECOVERY(tp);
- tp->snd_nxt = tp->snd_max;
- tp->t_badrxtwin = 0; /* XXX probably not required */
- }
+ if (tp->t_rxtshift == 1 && (int)(ticks - tp->t_badrxtwin) < 0)
+ cc_cong_signal(tp, th, CC_RTO_ERR);
/*
* If we have a timestamp reply, update smoothed
@@ -2298,61 +2441,12 @@ process_ACK:
goto step6;
/*
- * When new data is acked, open the congestion window.
- * Method depends on which congestion control state we're
- * in (slow start or cong avoid) and if ABC (RFC 3465) is
- * enabled.
- *
- * slow start: cwnd <= ssthresh
- * cong avoid: cwnd > ssthresh
- *
- * slow start and ABC (RFC 3465):
- * Grow cwnd exponentially by the amount of data
- * ACKed capping the max increment per ACK to
- * (abc_l_var * maxseg) bytes.
- *
- * slow start without ABC (RFC 2581):
- * Grow cwnd exponentially by maxseg per ACK.
- *
- * cong avoid and ABC (RFC 3465):
- * Grow cwnd linearly by maxseg per RTT for each
- * cwnd worth of ACKed data.
- *
- * cong avoid without ABC (RFC 2581):
- * Grow cwnd linearly by approximately maxseg per RTT using
- * maxseg^2 / cwnd per ACK as the increment.
- * If cwnd > maxseg^2, fix the cwnd increment at 1 byte to
- * avoid capping cwnd.
+ * Let the congestion control algorithm update congestion
+ * control related information. This typically means increasing
+ * the congestion window.
*/
- if ((!V_tcp_do_newreno && !(tp->t_flags & TF_SACK_PERMIT)) ||
- !IN_FASTRECOVERY(tp)) {
- u_int cw = tp->snd_cwnd;
- u_int incr = tp->t_maxseg;
- /* In congestion avoidance? */
- if (cw > tp->snd_ssthresh) {
- if (V_tcp_do_rfc3465) {
- tp->t_bytes_acked += acked;
- if (tp->t_bytes_acked >= tp->snd_cwnd)
- tp->t_bytes_acked -= cw;
- else
- incr = 0;
- }
- else
- incr = max((incr * incr / cw), 1);
- /*
- * In slow-start with ABC enabled and no RTO in sight?
- * (Must not use abc_l_var > 1 if slow starting after an
- * RTO. On RTO, snd_nxt = snd_una, so the snd_nxt ==
- * snd_max check is sufficient to handle this).
- */
- } else if (V_tcp_do_rfc3465 &&
- tp->snd_nxt == tp->snd_max)
- incr = min(acked,
- V_tcp_abc_l_var * tp->t_maxseg);
- /* ABC is on by default, so (incr == 0) frequently. */
- if (incr > 0)
- tp->snd_cwnd = min(cw+incr, TCP_MAXWIN<<tp->snd_scale);
- }
+ cc_ack_received(tp, th, CC_ACK);
+
SOCKBUF_LOCK(&so->so_snd);
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
@@ -2366,16 +2460,14 @@ process_ACK:
/* NB: sowwakeup_locked() does an implicit unlock. */
sowwakeup_locked(so);
/* Detect una wraparound. */
- if ((V_tcp_do_newreno || (tp->t_flags & TF_SACK_PERMIT)) &&
- !IN_FASTRECOVERY(tp) &&
+ if (!IN_RECOVERY(tp->t_flags) &&
SEQ_GT(tp->snd_una, tp->snd_recover) &&
SEQ_LEQ(th->th_ack, tp->snd_recover))
tp->snd_recover = th->th_ack - 1;
- if ((V_tcp_do_newreno || (tp->t_flags & TF_SACK_PERMIT)) &&
- IN_FASTRECOVERY(tp) &&
+ /* XXXLAS: Can this be moved up into cc_post_recovery? */
+ if (IN_RECOVERY(tp->t_flags) &&
SEQ_GEQ(th->th_ack, tp->snd_recover)) {
- EXIT_FASTRECOVERY(tp);
- tp->t_bytes_acked = 0;
+ EXIT_RECOVERY(tp->t_flags);
}
tp->snd_una = th->th_ack;
if (tp->t_flags & TF_SACK_PERMIT) {
@@ -3240,24 +3332,19 @@ tcp_mss_update(struct tcpcb *tp, int offer,
void
tcp_mss(struct tcpcb *tp, int offer)
{
- int rtt, mss;
+ int mss;
u_long bufsize;
struct inpcb *inp;
struct socket *so;
struct hc_metrics_lite metrics;
int mtuflags = 0;
-#ifdef INET6
- int isipv6;
-#endif
+
KASSERT(tp != NULL, ("%s: tp == NULL", __func__));
tcp_mss_update(tp, offer, &metrics, &mtuflags);
mss = tp->t_maxseg;
inp = tp->t_inpcb;
-#ifdef INET6
- isipv6 = ((inp->inp_vflag & INP_IPV6) != 0) ? 1 : 0;
-#endif
/*
* If there's a pipesize, change the socket buffer to that size,
@@ -3297,71 +3384,6 @@ tcp_mss(struct tcpcb *tp, int offer)
(void)sbreserve_locked(&so->so_rcv, bufsize, so, NULL);
}
SOCKBUF_UNLOCK(&so->so_rcv);
- /*
- * While we're here, check the others too.
- */
- if (tp->t_srtt == 0 && (rtt = metrics.rmx_rtt)) {
- tp->t_srtt = rtt;
- tp->t_rttbest = tp->t_srtt + TCP_RTT_SCALE;
- TCPSTAT_INC(tcps_usedrtt);
- if (metrics.rmx_rttvar) {
- tp->t_rttvar = metrics.rmx_rttvar;
- TCPSTAT_INC(tcps_usedrttvar);
- } else {
- /* default variation is +- 1 rtt */
- tp->t_rttvar =
- tp->t_srtt * TCP_RTTVAR_SCALE / TCP_RTT_SCALE;
- }
- TCPT_RANGESET(tp->t_rxtcur,
- ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1,
- tp->t_rttmin, TCPTV_REXMTMAX);
- }
- if (metrics.rmx_ssthresh) {
- /*
- * There's some sort of gateway or interface
- * buffer limit on the path. Use this to set
- * the slow start threshhold, but set the
- * threshold to no less than 2*mss.
- */
- tp->snd_ssthresh = max(2 * mss, metrics.rmx_ssthresh);
- TCPSTAT_INC(tcps_usedssthresh);
- }
-
- /*
- * Set the slow-start flight size depending on whether this
- * is a local network or not.
- *
- * Extend this so we cache the cwnd too and retrieve it here.
- * Make cwnd even bigger than RFC3390 suggests but only if we
- * have previous experience with the remote host. Be careful
- * not make cwnd bigger than remote receive window or our own
- * send socket buffer. Maybe put some additional upper bound
- * on the retrieved cwnd. Should do incremental updates to
- * hostcache when cwnd collapses so next connection doesn't
- * overloads the path again.
- *
- * RFC3390 says only do this if SYN or SYN/ACK didn't got lost.
- * We currently check only in syncache_socket for that.
- */
-#define TCP_METRICS_CWND
-#ifdef TCP_METRICS_CWND
- if (metrics.rmx_cwnd)
- tp->snd_cwnd = max(mss,
- min(metrics.rmx_cwnd / 2,
- min(tp->snd_wnd, so->so_snd.sb_hiwat)));
- else
-#endif
- if (V_tcp_do_rfc3390)
- tp->snd_cwnd = min(4 * mss, max(2 * mss, 4380));
-#ifdef INET6
- else if ((isipv6 && in6_localaddr(&inp->in6p_faddr)) ||
- (!isipv6 && in_localaddr(inp->inp_faddr)))
-#else
- else if (in_localaddr(inp->inp_faddr))
-#endif
- tp->snd_cwnd = mss * V_ss_fltsz_local;
- else
- tp->snd_cwnd = mss * V_ss_fltsz;
/* Check the interface for TSO capabilities. */
if (mtuflags & CSUM_TSO)
@@ -3425,7 +3447,7 @@ tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th)
* Set snd_cwnd to one segment beyond acknowledged offset.
* (tp->snd_una has not yet been updated when this function is called.)
*/
- tp->snd_cwnd = tp->t_maxseg + (th->th_ack - tp->snd_una);
+ tp->snd_cwnd = tp->t_maxseg + BYTES_THIS_ACK(tp, th);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
tp->snd_cwnd = ocwnd;
@@ -3435,8 +3457,8 @@ tcp_newreno_partial_ack(struct tcpcb *tp, struct tcphdr *th)
* Partial window deflation. Relies on fact that tp->snd_una
* not updated yet.
*/
- if (tp->snd_cwnd > th->th_ack - tp->snd_una)
- tp->snd_cwnd -= th->th_ack - tp->snd_una;
+ if (tp->snd_cwnd > BYTES_THIS_ACK(tp, th))
+ tp->snd_cwnd -= BYTES_THIS_ACK(tp, th);
else
tp->snd_cwnd = 0;
tp->snd_cwnd += tp->t_maxseg;
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index b5bc3d985520..7db0adb42ded 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
+#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -64,7 +65,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#endif
-#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
@@ -102,11 +102,6 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, local_slowstart_flightsize,
CTLFLAG_RW, &VNET_NAME(ss_fltsz_local), 1,
"Slow start flight size for local networks");
-VNET_DEFINE(int, tcp_do_newreno) = 1;
-SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, newreno, CTLFLAG_RW,
- &VNET_NAME(tcp_do_newreno), 0,
- "Enable NewReno Algorithms");
-
VNET_DEFINE(int, tcp_do_tso) = 1;
#define V_tcp_do_tso VNET(tcp_do_tso)
SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, tso, CTLFLAG_RW,
@@ -131,6 +126,19 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, sendbuf_max, CTLFLAG_RW,
&VNET_NAME(tcp_autosndbuf_max), 0,
"Max size of automatic send buffer");
+static void inline cc_after_idle(struct tcpcb *tp);
+
+/*
+ * CC wrapper hook functions
+ */
+static void inline
+cc_after_idle(struct tcpcb *tp)
+{
+ INP_WLOCK_ASSERT(tp->t_inpcb);
+
+ if (CC_ALGO(tp)->after_idle != NULL)
+ CC_ALGO(tp)->after_idle(tp->ccv);
+}
/*
* Tcp output routine: figure out what should be sent and send it.
@@ -241,7 +249,7 @@ again:
sack_bytes_rxmt = 0;
len = 0;
p = NULL;
- if ((tp->t_flags & TF_SACK_PERMIT) && IN_FASTRECOVERY(tp) &&
+ if ((tp->t_flags & TF_SACK_PERMIT) && IN_FASTRECOVERY(tp->t_flags) &&
(p = tcp_sack_output(tp, &sack_bytes_rxmt))) {
long cwin;
@@ -1315,7 +1323,7 @@ out:
* on the transmitter effectively destroys the TCP window, forcing
* it to four packets (1.5Kx4 = 6K window).
*/
- if (sendalot && (!V_tcp_do_newreno || --maxburst))
+ if (sendalot && --maxburst)
goto again;
#endif
if (sendalot)
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index 737c2b2af099..47d44ec16b91 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -576,7 +576,7 @@ tcp_sack_partialack(struct tcpcb *tp, struct tcphdr *th)
tcp_timer_activate(tp, TT_REXMT, 0);
tp->t_rtttime = 0;
/* Send one or 2 segments based on how much new data was acked. */
- if (((th->th_ack - tp->snd_una) / tp->t_maxseg) > 2)
+ if ((BYTES_THIS_ACK(tp, th) / tp->t_maxseg) > 2)
num_segs = 2;
tp->snd_cwnd = (tp->sackhint.sack_bytes_rexmit +
(tp->snd_nxt - tp->sack_newdata) + num_segs * tp->t_maxseg);
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index dc4395dc6137..8596e234f807 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/vnet.h>
+#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -80,7 +81,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/nd6.h>
#endif
#include <netinet/ip_icmp.h>
-#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
@@ -238,6 +238,7 @@ static char * tcp_log_addr(struct in_conninfo *inc, struct tcphdr *th,
struct tcpcb_mem {
struct tcpcb tcb;
struct tcp_timer tt;
+ struct cc_var ccv;
};
static VNET_DEFINE(uma_zone_t, tcpcb_zone);
@@ -277,6 +278,8 @@ tcp_init(void)
{
int hashsize;
+ cc_init();
+
hashsize = TCBHASHSIZE;
TUNABLE_INT_FETCH("net.inet.tcp.tcbhashsize", &hashsize);
if (!powerof2(hashsize)) {
@@ -640,6 +643,26 @@ tcp_newtcpcb(struct inpcb *inp)
if (tm == NULL)
return (NULL);
tp = &tm->tcb;
+
+ /* Initialise cc_var struct for this tcpcb. */
+ tp->ccv = &tm->ccv;
+ tp->ccv->type = IPPROTO_TCP;
+ tp->ccv->ccvc.tcp = tp;
+
+ /*
+ * Use the current system default CC algorithm.
+ */
+ CC_LIST_RLOCK();
+ KASSERT(!STAILQ_EMPTY(&cc_list), ("cc_list is empty!"));
+ CC_ALGO(tp) = CC_DEFAULT();
+ CC_LIST_RUNLOCK();
+
+ if (CC_ALGO(tp)->cb_init != NULL)
+ if (CC_ALGO(tp)->cb_init(tp->ccv) > 0) {
+ uma_zfree(V_tcpcb_zone, tm);
+ return (NULL);
+ }
+
#ifdef VIMAGE
tp->t_vnet = inp->inp_vnet;
#endif
@@ -805,6 +828,12 @@ tcp_discardcb(struct tcpcb *tp)
tcp_offload_detach(tp);
tcp_free_sackholes(tp);
+
+ /* Allow the CC algorithm to clean up after itself. */
+ if (CC_ALGO(tp)->cb_destroy != NULL)
+ CC_ALGO(tp)->cb_destroy(tp->ccv);
+
+ CC_ALGO(tp) = NULL;
inp->inp_ppcb = NULL;
tp->t_inpcb = NULL;
uma_zfree(V_tcpcb_zone, tp);
@@ -1572,7 +1601,7 @@ tcp_mtudisc(struct inpcb *inp, int errno)
tcp_free_sackholes(tp);
tp->snd_recover = tp->snd_max;
if (tp->t_flags & TF_SACK_PERMIT)
- EXIT_FASTRECOVERY(tp);
+ EXIT_FASTRECOVERY(tp->t_flags);
tcp_output_send(tp);
return (inp);
}
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 65c6a3ec41ab..2748e64601df 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
+#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
@@ -58,7 +59,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_pcb.h>
#endif
#include <netinet/ip_var.h>
-#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
@@ -515,10 +515,14 @@ tcp_timer_rexmt(void * xtp)
tp->snd_cwnd_prev = tp->snd_cwnd;
tp->snd_ssthresh_prev = tp->snd_ssthresh;
tp->snd_recover_prev = tp->snd_recover;
- if (IN_FASTRECOVERY(tp))
- tp->t_flags |= TF_WASFRECOVERY;
+ if (IN_FASTRECOVERY(tp->t_flags))
+ tp->t_flags |= TF_WASFRECOVERY;
else
- tp->t_flags &= ~TF_WASFRECOVERY;
+ tp->t_flags &= ~TF_WASFRECOVERY;
+ if (IN_CONGRECOVERY(tp->t_flags))
+ tp->t_flags |= TF_WASCRECOVERY;
+ else
+ tp->t_flags &= ~TF_WASCRECOVERY;
tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1));
}
TCPSTAT_INC(tcps_rexmttimeo);
@@ -562,40 +566,9 @@ tcp_timer_rexmt(void * xtp)
* If timing a segment in this window, stop the timer.
*/
tp->t_rtttime = 0;
- /*
- * Close the congestion window down to one segment
- * (we'll open it by one segment for each ack we get).
- * Since we probably have a window's worth of unacked
- * data accumulated, this "slow start" keeps us from
- * dumping all that data as back-to-back packets (which
- * might overwhelm an intermediate gateway).
- *
- * There are two phases to the opening: Initially we
- * open by one mss on each ack. This makes the window
- * size increase exponentially with time. If the
- * window is larger than the path can handle, this
- * exponential growth results in dropped packet(s)
- * almost immediately. To get more time between
- * drops but still "push" the network to take advantage
- * of improving conditions, we switch from exponential
- * to linear window opening at some threshhold size.
- * For a threshhold, we use half the current window
- * size, truncated to a multiple of the mss.
- *
- * (the minimum cwnd that will give us exponential
- * growth is 2 mss. We don't allow the threshhold
- * to go below this.)
- */
- {
- u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
- if (win < 2)
- win = 2;
- tp->snd_cwnd = tp->t_maxseg;
- tp->snd_ssthresh = win * tp->t_maxseg;
- tp->t_dupacks = 0;
- }
- EXIT_FASTRECOVERY(tp);
- tp->t_bytes_acked = 0;
+
+ cc_cong_signal(tp, 0, CC_RTO);
+
(void) tcp_output(tp);
out:
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index f35890bee192..a28ddef232a7 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <net/vnet.h>
+#include <netinet/cc.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#ifdef INET6
@@ -77,7 +78,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#endif
-#include <netinet/tcp.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
@@ -1242,6 +1242,8 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
struct inpcb *inp;
struct tcpcb *tp;
struct tcp_info ti;
+ char buf[TCP_CA_NAME_MAX];
+ struct cc_algo *algo;
error = 0;
inp = sotoinpcb(so);
@@ -1351,6 +1353,54 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
error = EINVAL;
break;
+ case TCP_CONGESTION:
+ INP_WUNLOCK(inp);
+ bzero(buf, sizeof(buf));
+ error = sooptcopyin(sopt, &buf, sizeof(buf), 1);
+ if (error)
+ break;
+ INP_WLOCK_RECHECK(inp);
+ /*
+ * Return EINVAL if we can't find the requested cc algo.
+ */
+ error = EINVAL;
+ CC_LIST_RLOCK();
+ STAILQ_FOREACH(algo, &cc_list, entries) {
+ if (strncmp(buf, algo->name, TCP_CA_NAME_MAX)
+ == 0) {
+ /* We've found the requested algo. */
+ error = 0;
+ /*
+ * We hold a write lock over the tcb
+ * so it's safe to do these things
+ * without ordering concerns.
+ */
+ if (CC_ALGO(tp)->cb_destroy != NULL)
+ CC_ALGO(tp)->cb_destroy(tp->ccv);
+ CC_ALGO(tp) = algo;
+ /*
+ * If something goes pear shaped
+ * initialising the new algo,
+ * fall back to newreno (which
+ * does not require initialisation).
+ */
+ if (algo->cb_init != NULL)
+ if (algo->cb_init(tp->ccv) > 0) {
+ CC_ALGO(tp) = &newreno_cc_algo;
+ /*
+ * The only reason init
+ * should fail is
+ * because of malloc.
+ */
+ error = ENOMEM;
+ }
+ break; /* Break the STAILQ_FOREACH. */
+ }
+ }
+ CC_LIST_RUNLOCK();
+ INP_WUNLOCK(inp);
+ break;
+
default:
INP_WUNLOCK(inp);
error = ENOPROTOOPT;
@@ -1394,6 +1444,12 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
INP_WUNLOCK(inp);
error = sooptcopyout(sopt, &ti, sizeof ti);
break;
+ case TCP_CONGESTION:
+ bzero(buf, sizeof(buf));
+ strlcpy(buf, CC_ALGO(tp)->name, TCP_CA_NAME_MAX);
+ INP_WUNLOCK(inp);
+ error = sooptcopyout(sopt, buf, TCP_CA_NAME_MAX);
+ break;
default:
INP_WUNLOCK(inp);
error = ENOPROTOOPT;
@@ -1707,6 +1763,10 @@ db_print_tflags(u_int t_flags)
db_printf("%sTF_FASTRECOVERY", comma ? ", " : "");
comma = 1;
}
+ if (t_flags & TF_CONGRECOVERY) {
+ db_printf("%sTF_CONGRECOVERY", comma ? ", " : "");
+ comma = 1;
+ }
if (t_flags & TF_WASFRECOVERY) {
db_printf("%sTF_WASFRECOVERY", comma ? ", " : "");
comma = 1;
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 0b286812f1f1..442c73621b85 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -195,9 +195,11 @@ struct tcpcb {
struct toe_usrreqs *t_tu; /* offload operations vector */
void *t_toe; /* TOE pcb pointer */
int t_bytes_acked; /* # bytes acked during current RTT */
+ struct cc_algo *cc_algo; /* congestion control algorithm */
+ struct cc_var *ccv;
int t_ispare; /* explicit pad for 64bit alignment */
- void *t_pspare2[6]; /* 2 CC / 4 TBD */
+ void *t_pspare2[4]; /* 4 TBD */
uint64_t _pad[12]; /* 7 UTO, 5 TBD (1-2 CC/RTT?) */
};
@@ -230,10 +232,22 @@ struct tcpcb {
#define TF_ECN_PERMIT 0x4000000 /* connection ECN-ready */
#define TF_ECN_SND_CWR 0x8000000 /* ECN CWR in queue */
#define TF_ECN_SND_ECE 0x10000000 /* ECN ECE in queue */
+#define TF_CONGRECOVERY 0x20000000 /* congestion recovery mode */
+#define TF_WASCRECOVERY 0x40000000 /* was in congestion recovery */
-#define IN_FASTRECOVERY(tp) (tp->t_flags & TF_FASTRECOVERY)
-#define ENTER_FASTRECOVERY(tp) tp->t_flags |= TF_FASTRECOVERY
-#define EXIT_FASTRECOVERY(tp) tp->t_flags &= ~TF_FASTRECOVERY
+#define IN_FASTRECOVERY(t_flags) (t_flags & TF_FASTRECOVERY)
+#define ENTER_FASTRECOVERY(t_flags) t_flags |= TF_FASTRECOVERY
+#define EXIT_FASTRECOVERY(t_flags) t_flags &= ~TF_FASTRECOVERY
+
+#define IN_CONGRECOVERY(t_flags) (t_flags & TF_CONGRECOVERY)
+#define ENTER_CONGRECOVERY(t_flags) t_flags |= TF_CONGRECOVERY
+#define EXIT_CONGRECOVERY(t_flags) t_flags &= ~TF_CONGRECOVERY
+
+#define IN_RECOVERY(t_flags) (t_flags & (TF_CONGRECOVERY | TF_FASTRECOVERY))
+#define ENTER_RECOVERY(t_flags) t_flags |= (TF_CONGRECOVERY | TF_FASTRECOVERY)
+#define EXIT_RECOVERY(t_flags) t_flags &= ~(TF_CONGRECOVERY | TF_FASTRECOVERY)
+
+#define BYTES_THIS_ACK(tp, th) (th->th_ack - tp->snd_una)
/*
* Flags for the t_oobflags field.
@@ -562,10 +576,11 @@ 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);
VNET_DECLARE(int, ss_fltsz_local);
+VNET_DECLARE(int, tcp_do_rfc3465);
+VNET_DECLARE(int, tcp_abc_l_var);
#define V_tcb VNET(tcb)
#define V_tcbinfo VNET(tcbinfo)
#define V_tcpstat VNET(tcpstat)
@@ -573,10 +588,11 @@ VNET_DECLARE(int, ss_fltsz_local);
#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)
#define V_ss_fltsz_local VNET(ss_fltsz_local)
+#define V_tcp_do_rfc3465 VNET(tcp_do_rfc3465)
+#define V_tcp_abc_l_var VNET(tcp_abc_l_var)
VNET_DECLARE(int, tcp_do_sack); /* SACK enabled/disabled */
VNET_DECLARE(int, tcp_sc_rst_sock_fail); /* RST on sock alloc failure */
@@ -678,6 +694,8 @@ void tcp_free_sackholes(struct tcpcb *tp);
int tcp_newreno(struct tcpcb *, struct tcphdr *);
u_long tcp_seq_subtract(u_long, u_long );
+void cc_cong_signal(struct tcpcb *tp, struct tcphdr *th, uint32_t type);
+
#endif /* _KERNEL */
#endif /* _NETINET_TCP_VAR_H_ */
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index f52f7a4f5b97..87aa482b9d4b 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -159,8 +159,6 @@ int setfault(faultbuf); /* defined in locore.S */
long Maxmem = 0;
long realmem = 0;
-struct pmap ofw_pmap;
-
#ifndef __powerpc64__
struct bat battable[16];
#endif
@@ -639,64 +637,6 @@ cpu_halt(void)
OF_exit();
}
-void
-cpu_idle(int busy)
-{
- register_t msr;
- uint16_t vers;
-
- msr = mfmsr();
- vers = mfpvr() >> 16;
-
-#ifdef INVARIANTS
- if ((msr & PSL_EE) != PSL_EE) {
- struct thread *td = curthread;
- printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
- 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:
- case IBM970MP:
- case MPC7447A:
- case MPC7448:
- case MPC7450:
- case MPC7455:
- case MPC7457:
- __asm __volatile("\
- dssall; sync; mtmsr %0; isync"
- :: "r"(msr | PSL_POW));
- break;
- default:
- powerpc_sync();
- mtmsr(msr | PSL_POW);
- isync();
- break;
- }
- if (!busy) {
- cpu_activeclock();
- critical_exit();
- }
- }
- CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
- busy, curcpu);
-}
-
-int
-cpu_idle_wakeup(int cpu)
-{
-
- return (0);
-}
-
int
ptrace_set_pc(struct thread *td, unsigned long addr)
{
diff --git a/sys/powerpc/aim/mmu_oea.c b/sys/powerpc/aim/mmu_oea.c
index 5ba029c3f5cf..7bd07e113725 100644
--- a/sys/powerpc/aim/mmu_oea.c
+++ b/sys/powerpc/aim/mmu_oea.c
@@ -197,8 +197,6 @@ static u_int phys_avail_count;
static int regions_sz, pregions_sz;
static struct ofw_map *translations;
-extern struct pmap ofw_pmap;
-
/*
* Lock for the pteg and pvo tables.
*/
@@ -669,10 +667,7 @@ moea_cpu_bootstrap(mmu_t mmup, int ap)
isync();
for (i = 0; i < 16; i++)
- mtsrin(i << ADDR_SR_SHFT, EMPTY_SEGMENT);
-
- __asm __volatile("mtsr %0,%1" :: "n"(KERNEL_SR), "r"(KERNEL_SEGMENT));
- __asm __volatile("mtsr %0,%1" :: "n"(KERNEL2_SR), "r"(KERNEL2_SEGMENT));
+ mtsrin(i << ADDR_SR_SHFT, kernel_pmap->pm_sr[i]);
powerpc_sync();
sdr = (u_int)moea_pteg_table | (moea_pteg_mask >> 10);
@@ -859,11 +854,16 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
moea_vsid_bitmap[0] |= 1;
/*
- * Set up the Open Firmware pmap and add it's mappings.
+ * Initialize the kernel pmap (which is statically allocated).
+ */
+ PMAP_LOCK_INIT(kernel_pmap);
+ for (i = 0; i < 16; i++)
+ kernel_pmap->pm_sr[i] = EMPTY_SEGMENT + i;
+ kernel_pmap->pm_active = ~0;
+
+ /*
+ * Set up the Open Firmware mappings
*/
- moea_pinit(mmup, &ofw_pmap);
- ofw_pmap.pm_sr[KERNEL_SR] = KERNEL_SEGMENT;
- ofw_pmap.pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT;
if ((chosen = OF_finddevice("/chosen")) == -1)
panic("moea_bootstrap: can't find /chosen");
OF_getprop(chosen, "mmu", &mmui, 4);
@@ -900,16 +900,8 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
/* Enter the pages */
for (off = 0; off < translations[i].om_len; off += PAGE_SIZE) {
- 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,
- translations[i].om_va + off, &m,
- VM_PROT_ALL, 1);
- PMAP_UNLOCK(&ofw_pmap);
+ moea_kenter(mmup, translations[i].om_va + off,
+ translations[i].om_pa + off);
ofw_mappings++;
}
}
@@ -921,17 +913,6 @@ moea_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
;
Maxmem = powerpc_btop(phys_avail[i + 1]);
- /*
- * Initialize the kernel pmap (which is statically allocated).
- */
- PMAP_LOCK_INIT(kernel_pmap);
- for (i = 0; i < 16; i++) {
- kernel_pmap->pm_sr[i] = EMPTY_SEGMENT;
- }
- kernel_pmap->pm_sr[KERNEL_SR] = KERNEL_SEGMENT;
- kernel_pmap->pm_sr[KERNEL2_SR] = KERNEL2_SEGMENT;
- kernel_pmap->pm_active = ~0;
-
moea_cpu_bootstrap(mmup,0);
pmap_bootstrapped++;
diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c
index 3e336c9e6ab6..506676fa2264 100644
--- a/sys/powerpc/aim/mmu_oea64.c
+++ b/sys/powerpc/aim/mmu_oea64.c
@@ -275,8 +275,6 @@ static struct mem_region *pregions;
static u_int phys_avail_count;
static int regions_sz, pregions_sz;
-extern struct pmap ofw_pmap;
-
extern void bs_remap_earlyboot(void);
@@ -1119,27 +1117,16 @@ moea64_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend)
chosen = OF_finddevice("/chosen");
if (chosen != -1 && OF_getprop(chosen, "mmu", &mmui, 4) != -1) {
- #ifndef __powerpc64__
- moea64_pinit(mmup, &ofw_pmap);
-
- for (i = 0; i < 16; i++)
- ofw_pmap.pm_sr[i] = kernel_pmap->pm_sr[i];
- #endif
-
- if ((mmu = OF_instance_to_package(mmui)) == -1)
- panic("moea64_bootstrap: can't get mmu package");
- if ((sz = OF_getproplen(mmu, "translations")) == -1)
- panic("moea64_bootstrap: can't get ofw translation count");
+ mmu = OF_instance_to_package(mmui);
+ if (mmu == -1 || (sz = OF_getproplen(mmu, "translations")) == -1)
+ sz = 0;
if (sz > 6144 /* tmpstksz - 2 KB headroom */)
panic("moea64_bootstrap: too many ofw translations");
- moea64_add_ofw_mappings(mmup, mmu, sz);
+ if (sz > 0)
+ moea64_add_ofw_mappings(mmup, mmu, sz);
}
-#ifdef SMP
- TLBSYNC();
-#endif
-
/*
* Calculate the last available physical address.
*/
@@ -2385,6 +2372,9 @@ moea64_bootstrap_alloc(vm_size_t size, u_int align)
if (s < phys_avail[i] || e > phys_avail[i + 1])
continue;
+ if (s + size > platform_real_maxaddr())
+ continue;
+
if (s == phys_avail[i]) {
phys_avail[i] += size;
} else if (e == phys_avail[i + 1]) {
diff --git a/sys/powerpc/aim/mp_cpudep.c b/sys/powerpc/aim/mp_cpudep.c
index b0423659f431..312164e04174 100644
--- a/sys/powerpc/aim/mp_cpudep.c
+++ b/sys/powerpc/aim/mp_cpudep.c
@@ -228,6 +228,21 @@ cpudep_save_config(void *dummy)
powerpc_sync();
break;
+#ifdef __powerpc64__
+ case IBMCELLBE:
+ if (mfmsr() & PSL_HV) {
+ bsp_state[0] = mfspr(SPR_HID0);
+ bsp_state[1] = mfspr(SPR_HID1);
+ bsp_state[2] = mfspr(SPR_HID4);
+ bsp_state[3] = mfspr(SPR_HID6);
+
+ bsp_state[4] = mfspr(SPR_CELL_TSCR);
+ }
+
+ bsp_state[5] = mfspr(SPR_CELL_TSRL);
+
+ break;
+#endif
case MPC7450:
case MPC7455:
case MPC7457:
@@ -288,6 +303,21 @@ cpudep_ap_setup()
powerpc_sync();
break;
+#ifdef __powerpc64__
+ case IBMCELLBE:
+ if (mfmsr() & PSL_HV) {
+ mtspr(SPR_HID0, bsp_state[0]);
+ mtspr(SPR_HID1, bsp_state[1]);
+ mtspr(SPR_HID4, bsp_state[2]);
+ mtspr(SPR_HID6, bsp_state[3]);
+
+ mtspr(SPR_CELL_TSCR, bsp_state[4]);
+ }
+
+ mtspr(SPR_CELL_TSRL, bsp_state[5]);
+
+ break;
+#endif
case MPC7450:
case MPC7455:
case MPC7457:
diff --git a/sys/powerpc/aim/slb.c b/sys/powerpc/aim/slb.c
index 9d8828ac2daa..d5fb12e779f6 100644
--- a/sys/powerpc/aim/slb.c
+++ b/sys/powerpc/aim/slb.c
@@ -36,9 +36,14 @@
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/uma.h>
+#include <vm/vm.h>
#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_phys.h>
#include <machine/md_var.h>
+#include <machine/platform.h>
#include <machine/pmap.h>
#include <machine/vmparam.h>
@@ -474,6 +479,51 @@ slb_insert_user(pmap_t pm, struct slb *slb)
pm->pm_slb[i] = slb;
}
+static void *
+slb_uma_real_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
+{
+ static vm_offset_t realmax = 0;
+ void *va;
+ vm_page_t m;
+ int pflags;
+
+ if (realmax == 0)
+ realmax = platform_real_maxaddr();
+
+ *flags = UMA_SLAB_PRIV;
+ if ((wait & (M_NOWAIT|M_USE_RESERVE)) == M_NOWAIT)
+ pflags = VM_ALLOC_INTERRUPT | VM_ALLOC_WIRED;
+ else
+ pflags = VM_ALLOC_SYSTEM | VM_ALLOC_WIRED;
+ if (wait & M_ZERO)
+ pflags |= VM_ALLOC_ZERO;
+
+ for (;;) {
+ m = vm_phys_alloc_contig(1, 0, realmax, PAGE_SIZE,
+ PAGE_SIZE);
+ if (m == NULL) {
+ if (wait & M_NOWAIT)
+ return (NULL);
+ VM_WAIT;
+ } else
+ break;
+ }
+
+ va = (void *) VM_PAGE_TO_PHYS(m);
+
+ if (!hw_direct_map)
+ pmap_kenter((vm_offset_t)va, VM_PAGE_TO_PHYS(m));
+
+ if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0)
+ bzero(va, PAGE_SIZE);
+
+ /* vm_phys_alloc_contig does not track wiring */
+ atomic_add_int(&cnt.v_wire_count, 1);
+ m->wire_count = 1;
+
+ return (va);
+}
+
static void
slb_zone_init(void *dummy)
{
@@ -482,6 +532,11 @@ slb_zone_init(void *dummy)
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM);
slb_cache_zone = uma_zcreate("SLB cache", 64*sizeof(struct slb *),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM);
+
+ if (platform_real_maxaddr() != VM_MAX_ADDRESS) {
+ uma_zone_set_allocf(slb_cache_zone, slb_uma_real_alloc);
+ uma_zone_set_allocf(slbt_zone, slb_uma_real_alloc);
+ }
}
struct slb **
diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c
index b8a77a59b063..921dfbf81f9b 100644
--- a/sys/powerpc/booke/machdep.c
+++ b/sys/powerpc/booke/machdep.c
@@ -468,50 +468,6 @@ cpu_flush_dcache(void *ptr, size_t len)
/* TBD */
}
-/*
- * cpu_idle
- *
- * Set Wait state enable.
- */
-void
-cpu_idle (int busy)
-{
- register_t msr;
-
- msr = mfmsr();
-
-#ifdef INVARIANTS
- if ((msr & PSL_EE) != PSL_EE) {
- struct thread *td = curthread;
- printf("td msr %x\n", td->td_md.md_saved_msr);
- panic("ints disabled in idleproc!");
- }
-#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
-cpu_idle_wakeup(int cpu)
-{
-
- return (0);
-}
-
void
spinlock_enter(void)
{
@@ -641,12 +597,3 @@ bzero(void *buf, size_t len)
}
}
-/*
- * XXX what is the better/proper place for this routine?
- */
-int
-mem_valid(vm_offset_t addr, int len)
-{
-
- return (1);
-}
diff --git a/sys/powerpc/include/cpufunc.h b/sys/powerpc/include/cpufunc.h
index 775ef19f2eb1..914935f5e775 100644
--- a/sys/powerpc/include/cpufunc.h
+++ b/sys/powerpc/include/cpufunc.h
@@ -106,6 +106,17 @@ mfsrin(vm_offset_t va)
}
#endif
+static __inline register_t
+mfctrl(void)
+{
+ register_t value;
+
+ __asm __volatile ("mfspr %0,136" : "=r"(value));
+
+ return (value);
+}
+
+
static __inline void
mtdec(register_t value)
{
diff --git a/sys/powerpc/include/platform.h b/sys/powerpc/include/platform.h
index cfa7a0d0890c..48ea0e603250 100644
--- a/sys/powerpc/include/platform.h
+++ b/sys/powerpc/include/platform.h
@@ -44,6 +44,7 @@ struct mem_region {
};
void mem_regions(struct mem_region **, int *, struct mem_region **, int *);
+vm_offset_t platform_real_maxaddr(void);
u_long platform_timebase_freq(struct cpuref *);
diff --git a/sys/powerpc/include/spr.h b/sys/powerpc/include/spr.h
index 317f4d117629..4027461259ed 100644
--- a/sys/powerpc/include/spr.h
+++ b/sys/powerpc/include/spr.h
@@ -420,6 +420,10 @@
#define SPR_HID1 0x3f1 /* ..8 Hardware Implementation Register 1 */
#define SPR_HID4 0x3f4 /* ..8 Hardware Implementation Register 4 */
#define SPR_HID5 0x3f6 /* ..8 Hardware Implementation Register 5 */
+#define SPR_HID6 0x3f9 /* ..8 Hardware Implementation Register 6 */
+
+#define SPR_CELL_TSRL 0x380 /* ... Cell BE Thread Status Register */
+#define SPR_CELL_TSCR 0x399 /* ... Cell BE Thread Switch Register */
#if defined(AIM)
#define SPR_DBSR 0x3f0 /* 4.. Debug Status Register */
diff --git a/sys/powerpc/aim/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c
index 1ebcd0cb7d85..f0daa4f28139 100644
--- a/sys/powerpc/aim/ofw_machdep.c
+++ b/sys/powerpc/ofw/ofw_machdep.c
@@ -66,7 +66,6 @@ static struct mem_region OFfree[OFMEM_REGIONS + 3];
static int nOFmem;
extern register_t ofmsr[5];
-extern struct pmap ofw_pmap;
static int (*ofwcall)(void *);
static void *fdt;
int ofw_real_mode;
@@ -417,59 +416,27 @@ openfirmware_core(void *args)
{
int result;
register_t oldmsr;
- #ifndef __powerpc64__
- register_t srsave[16];
- u_int i;
- #endif
/*
* Turn off exceptions - we really don't want to end up
- * anywhere unexpected with PCPU set to something strange,
- * the stack pointer wrong, or the OFW mapping enabled.
+ * anywhere unexpected with PCPU set to something strange
+ * or the stack pointer wrong.
*/
oldmsr = intr_disable();
ofw_sprg_prepare();
- #ifndef __powerpc64__
- if (pmap_bootstrapped && !ofw_real_mode) {
- /*
- * Swap the kernel's address space with Open Firmware's
- */
-
- for (i = 0; i < 16; i++) {
- srsave[i] = mfsrin(i << ADDR_SR_SHFT);
- mtsrin(i << ADDR_SR_SHFT, ofw_pmap.pm_sr[i]);
- }
-
- /*
- * Clear battable[] translations
- */
- if (!(cpu_features & PPC_FEATURE_64)) {
- __asm __volatile("mtdbatu 2, %0\n"
- "mtdbatu 3, %0" : : "r" (0));
- }
- isync();
- }
- #endif
+#if defined(AIM) && !defined(__powerpc64__)
+ /*
+ * Clear battable[] translations
+ */
+ if (!(cpu_features & PPC_FEATURE_64))
+ __asm __volatile("mtdbatu 2, %0\n"
+ "mtdbatu 3, %0" : : "r" (0));
+ isync();
+#endif
result = ofwcall(args);
-
- #ifndef __powerpc64__
- if (pmap_bootstrapped && !ofw_real_mode) {
- /*
- * Restore the kernel's addr space. The isync() doesn;t
- * work outside the loop unless mtsrin() is open-coded
- * in an asm statement :(
- */
-
- for (i = 0; i < 16; i++) {
- mtsrin(i << ADDR_SR_SHFT, srsave[i]);
- isync();
- }
- }
- #endif
-
ofw_sprg_restore();
intr_restore(oldmsr);
@@ -692,16 +659,3 @@ OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
return (bus_space_map(*tag, addr, size, 0, handle));
}
-int
-mem_valid(vm_offset_t addr, int len)
-{
- int i;
-
- for (i = 0; i < nOFmem; i++)
- if ((addr >= OFmem[i].mr_start)
- && (addr + len < OFmem[i].mr_start + OFmem[i].mr_size))
- return (0);
-
- return (EFAULT);
-}
-
diff --git a/sys/powerpc/powerpc/cpu.c b/sys/powerpc/powerpc/cpu.c
index 4bbfcac82bbe..97011562a8e2 100644
--- a/sys/powerpc/powerpc/cpu.c
+++ b/sys/powerpc/powerpc/cpu.c
@@ -64,6 +64,7 @@
#include <sys/conf.h>
#include <sys/cpu.h>
#include <sys/kernel.h>
+#include <sys/proc.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
@@ -73,12 +74,15 @@
#include <machine/smp.h>
#include <machine/spr.h>
-int powerpc_pow_enabled;
-
static void cpu_6xx_setup(int cpuid, uint16_t vers);
static void cpu_e500_setup(int cpuid, uint16_t vers);
static void cpu_970_setup(int cpuid, uint16_t vers);
+int powerpc_pow_enabled;
+void (*cpu_idle_hook)(void) = NULL;
+static void cpu_idle_60x(void);
+static void cpu_idle_e500(void);
+
struct cputab {
const char *name;
uint16_t version;
@@ -145,6 +149,9 @@ static const struct cputab models[] = {
0, cpu_e500_setup },
{ "Freescale e500v2 core", FSL_E500v2, REVFMT_MAJMIN,
0, cpu_e500_setup },
+ { "IBM Cell Broadband Engine", IBMCELLBE, REVFMT_MAJMIN,
+ PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
+ NULL},
{ "Unknown PowerPC CPU", 0, REVFMT_HEX, 0, NULL },
};
@@ -374,6 +381,9 @@ cpu_6xx_setup(int cpuid, uint16_t vers)
}
printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
+
+ if (cpu_idle_hook == NULL)
+ cpu_idle_hook = cpu_idle_60x;
}
@@ -441,6 +451,9 @@ cpu_e500_setup(int cpuid, uint16_t vers)
mtspr(SPR_HID0, hid0);
printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, HID0_E500_BITMASK);
+
+ if (cpu_idle_hook == NULL)
+ cpu_idle_hook = cpu_idle_e500;
}
static void
@@ -478,6 +491,8 @@ cpu_970_setup(int cpuid, uint16_t vers)
: "=r" (hid0_hi) : "K" (SPR_HID0));
printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
#endif
+
+ cpu_idle_hook = cpu_idle_60x;
}
static int
@@ -490,3 +505,87 @@ cpu_feature_bit(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_int(oidp, &result, 0, req));
}
+void
+cpu_idle(int busy)
+{
+
+#ifdef INVARIANTS
+ if ((mfmsr() & PSL_EE) != PSL_EE) {
+ struct thread *td = curthread;
+ printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
+ panic("ints disabled in idleproc!");
+ }
+#endif
+
+ CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
+ busy, curcpu);
+ if (cpu_idle_hook != NULL) {
+ if (!busy) {
+ critical_enter();
+ cpu_idleclock();
+ }
+ cpu_idle_hook();
+ if (!busy) {
+ cpu_activeclock();
+ critical_exit();
+ }
+ }
+ CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
+ busy, curcpu);
+}
+
+int
+cpu_idle_wakeup(int cpu)
+{
+ return (0);
+}
+
+static void
+cpu_idle_60x(void)
+{
+ register_t msr;
+ uint16_t vers;
+
+ if (!powerpc_pow_enabled)
+ return;
+
+ msr = mfmsr();
+ vers = mfpvr() >> 16;
+
+#ifdef AIM
+ switch (vers) {
+ case IBM970:
+ case IBM970FX:
+ case IBM970MP:
+ case MPC7447A:
+ case MPC7448:
+ case MPC7450:
+ case MPC7455:
+ case MPC7457:
+ __asm __volatile("\
+ dssall; sync; mtmsr %0; isync"
+ :: "r"(msr | PSL_POW));
+ break;
+ default:
+ powerpc_sync();
+ mtmsr(msr | PSL_POW);
+ isync();
+ break;
+ }
+#endif
+}
+
+static void
+cpu_idle_e500(void)
+{
+ register_t msr;
+
+ msr = mfmsr();
+
+#ifdef E500
+ /* Freescale E500 core RM section 6.4.1. */
+ __asm __volatile("msync; mtmsr %0; isync" ::
+ "r" (msr | PSL_WE));
+#endif
+}
+
diff --git a/sys/powerpc/powerpc/mp_machdep.c b/sys/powerpc/powerpc/mp_machdep.c
index 9086db5299c0..81c5481a7878 100644
--- a/sys/powerpc/powerpc/mp_machdep.c
+++ b/sys/powerpc/powerpc/mp_machdep.c
@@ -78,7 +78,13 @@ machdep_ap_bootstrap(void)
;
/* Initialize DEC and TB, sync with the BSP values */
+#ifdef __powerpc64__
+ /* Writing to the time base register is hypervisor-privileged */
+ if (mfmsr() & PSL_HV)
+ mttb(ap_timebase);
+#else
mttb(ap_timebase);
+#endif
decr_ap_init();
/* Serialize console output and AP count increment */
@@ -98,13 +104,6 @@ machdep_ap_bootstrap(void)
sched_throw(NULL);
}
-struct cpu_group *
-cpu_topo(void)
-{
-
- return (smp_topo_none());
-}
-
void
cpu_mp_setmaxid(void)
{
@@ -247,7 +246,13 @@ cpu_mp_unleash(void *dummy)
/* Let APs continue */
atomic_store_rel_int(&ap_letgo, 1);
+#ifdef __powerpc64__
+ /* Writing to the time base register is hypervisor-privileged */
+ if (mfmsr() & PSL_HV)
+ mttb(ap_timebase);
+#else
mttb(ap_timebase);
+#endif
while (ap_awake < smp_cpus)
;
diff --git a/sys/powerpc/powerpc/platform.c b/sys/powerpc/powerpc/platform.c
index 2b5c60792db3..02d89ee3dae2 100644
--- a/sys/powerpc/powerpc/platform.c
+++ b/sys/powerpc/powerpc/platform.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ktr.h>
#include <sys/mutex.h>
#include <sys/systm.h>
+#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/types.h>
@@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_page.h>
#include <machine/cpu.h>
+#include <machine/md_var.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
#include <machine/smp.h>
@@ -62,11 +64,45 @@ static char plat_name[64] = "";
SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RD | CTLFLAG_TUN,
plat_name, 0, "Platform currently in use");
+static struct mem_region *pregions = NULL;
+static struct mem_region *aregions = NULL;
+static int npregions, naregions;
+
void
mem_regions(struct mem_region **phys, int *physsz, struct mem_region **avail,
int *availsz)
{
- PLATFORM_MEM_REGIONS(plat_obj, phys, physsz, avail, availsz);
+ if (pregions == NULL)
+ PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
+ &aregions, &naregions);
+
+ *phys = pregions;
+ *avail = aregions;
+ *physsz = npregions;
+ *availsz = naregions;
+}
+
+int
+mem_valid(vm_offset_t addr, int len)
+{
+ int i;
+
+ if (pregions == NULL)
+ PLATFORM_MEM_REGIONS(plat_obj, &pregions, &npregions,
+ &aregions, &naregions);
+
+ for (i = 0; i < npregions; i++)
+ if ((addr >= pregions[i].mr_start)
+ && (addr + len < pregions[i].mr_start + pregions[i].mr_size))
+ return (0);
+
+ return (EFAULT);
+}
+
+vm_offset_t
+platform_real_maxaddr(void)
+{
+ return (PLATFORM_REAL_MAXADDR(plat_obj));
}
const char *
@@ -105,6 +141,14 @@ platform_smp_start_cpu(struct pcpu *cpu)
return (PLATFORM_SMP_START_CPU(plat_obj, cpu));
}
+#ifdef SMP
+struct cpu_group *
+cpu_topo(void)
+{
+ return (PLATFORM_SMP_TOPO(plat_obj));
+}
+#endif
+
/*
* Reset back to firmware.
*/
@@ -164,9 +208,10 @@ platform_probe_and_attach()
}
/*
- * We can't free the KOBJ, since it is static. Luckily,
- * this has no ill effects since it gets reset every time.
+ * We can't free the KOBJ, since it is static. Reset the ops
+ * member of this class so that we can come back later.
*/
+ platp->ops = NULL;
}
if (plat_def_impl == NULL)
diff --git a/sys/powerpc/powerpc/platform_if.m b/sys/powerpc/powerpc/platform_if.m
index 07e49bc884cd..94383c327d6e 100644
--- a/sys/powerpc/powerpc/platform_if.m
+++ b/sys/powerpc/powerpc/platform_if.m
@@ -30,10 +30,12 @@
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
+#include <sys/smp.h>
#include <machine/platform.h>
#include <machine/platformvar.h>
#include <machine/smp.h>
+#include <machine/vmparam.h>
/**
* @defgroup PLATFORM platform - KObj methods for PowerPC platform
@@ -66,6 +68,18 @@ CODE {
{
return (ENOENT);
}
+ static struct cpu_group *platform_null_smp_topo(platform_t plat)
+ {
+#ifdef SMP
+ return (smp_topo_none());
+#else
+ return (NULL);
+#endif
+ }
+ static vm_offset_t platform_null_real_maxaddr(platform_t plat)
+ {
+ return (VM_MAX_ADDRESS);
+ }
};
/**
@@ -109,6 +123,15 @@ METHOD void mem_regions {
};
/**
+ * @brief Return the maximum address accessible in real mode
+ * (for use with hypervisors)
+ */
+METHOD vm_offset_t real_maxaddr {
+ platform_t _plat;
+} DEFAULT platform_null_real_maxaddr;
+
+
+/**
* @brief Get the CPU's timebase frequency, in ticks per second.
*
* @param _cpu CPU whose timebase to query
@@ -162,6 +185,13 @@ METHOD int smp_start_cpu {
};
/**
+ * @brief Return SMP topology
+ */
+METHOD cpu_group_t smp_topo {
+ platform_t _plat;
+} DEFAULT platform_null_smp_topo;
+
+/**
* @brief Reset system
*/
METHOD void reset {
diff --git a/sys/sys/param.h b/sys/sys/param.h
index a64c77b2601c..acd1f519e383 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 900024 /* Master, propagated to newvers */
+#define __FreeBSD_version 900025 /* Master, propagated to newvers */
#ifndef LOCORE
#include <sys/types.h>
diff --git a/sys/sys/signal.h b/sys/sys/signal.h
index 85116430fccc..971683516e3c 100644
--- a/sys/sys/signal.h
+++ b/sys/sys/signal.h
@@ -284,7 +284,7 @@ typedef struct __siginfo {
#define POLL_MSG 3 /* Input message available */
#define POLL_ERR 4 /* I/O Error */
#define POLL_PRI 5 /* High priority input available */
-#define POLL_HUP 4 /* Device disconnected */
+#define POLL_HUP 6 /* Device disconnected */
#endif
diff --git a/sys/sys/smp.h b/sys/sys/smp.h
index 619eba813f5a..6104d3e22422 100644
--- a/sys/sys/smp.h
+++ b/sys/sys/smp.h
@@ -16,8 +16,6 @@
#ifndef LOCORE
-#ifdef SMP
-
/*
* Topology of a NUMA or HTT system.
*
@@ -41,6 +39,8 @@ struct cpu_group {
int8_t cg_flags; /* Traversal modifiers. */
};
+typedef struct cpu_group *cpu_group_t;
+
/*
* Defines common resources for CPUs in the group. The highest level
* resource should be used when multiple are shared.
@@ -60,6 +60,7 @@ struct cpu_group {
/*
* Convenience routines for building topologies.
*/
+#ifdef SMP
struct cpu_group *smp_topo(void);
struct cpu_group *smp_topo_none(void);
struct cpu_group *smp_topo_1level(int l1share, int l1count, int l1flags);
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 9f227482f170..6a5821988c2d 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -137,6 +137,7 @@ typedef __uid_t uid_t;
#define SO_LISTENQLEN 0x1012 /* socket's complete queue length */
#define SO_LISTENINCQLEN 0x1013 /* socket's incomplete queue length */
#define SO_SETFIB 0x1014 /* use this FIB to route */
+#define SO_USER_COOKIE 0x1015 /* user cookie (dummynet etc.) */
#endif
/*
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
index 6d6578b68abe..94c3b24e5c3e 100644
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -117,7 +117,14 @@ struct socket {
void *so_accept_filter_arg; /* saved filter args */
char *so_accept_filter_str; /* saved user args */
} *so_accf;
+ /*
+ * so_fibnum, so_user_cookie and friends can be used to attach
+ * some user-specified metadata to a socket, which then can be
+ * used by the kernel for various actions.
+ * so_user_cookie is used by ipfw/dummynet.
+ */
int so_fibnum; /* routing domain for this socket */
+ uint32_t so_user_cookie;
};
/*