summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorgjb <gjb@FreeBSD.org>2016-04-04 23:55:32 +0000
committergjb <gjb@FreeBSD.org>2016-04-04 23:55:32 +0000
commit1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f (patch)
treea027fe5a27446f32854d6a07b34b5f2a992bf283 /sys/dev
parent3669a0dced7e344be71d234ffc3a71530ef0ae08 (diff)
parent589cedfe0cde2b49d5f47fc240de37c8bf307abd (diff)
downloadFreeBSD-src-1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f.zip
FreeBSD-src-1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f.tar.gz
MFH
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/acpica/acpi.c12
-rw-r--r--sys/dev/acpica/acpi_hpet.c2
-rw-r--r--sys/dev/acpica/acpi_timer.c2
-rw-r--r--sys/dev/advansys/adv_isa.c2
-rw-r--r--sys/dev/ahci/ahci.c2
-rw-r--r--sys/dev/ahci/ahci.h4
-rw-r--r--sys/dev/ahci/ahci_pci.c5
-rw-r--r--sys/dev/amdsbwd/amdsbwd.c20
-rw-r--r--sys/dev/arcmsr/arcmsr.c23
-rw-r--r--sys/dev/ata/ata-lowlevel.c2
-rw-r--r--sys/dev/ath/if_ath_lna_div.c2
-rw-r--r--sys/dev/atkbdc/atkbdc_subr.c2
-rw-r--r--sys/dev/bhnd/bhnd.c4
-rw-r--r--sys/dev/bhnd/bhndb/bhndb.c4
-rw-r--r--sys/dev/bwn/if_bwn.c8
-rw-r--r--sys/dev/bxe/bxe.c94
-rw-r--r--sys/dev/bxe/bxe.h11
-rw-r--r--sys/dev/cardbus/cardbus_cis.c3
-rw-r--r--sys/dev/ctau/if_ct.c6
-rw-r--r--sys/dev/cxgb/cxgb_sge.c6
-rw-r--r--sys/dev/cxgbe/adapter.h22
-rw-r--r--sys/dev/cxgbe/common/t4_hw.c15
-rw-r--r--sys/dev/cxgbe/firmware/t4fw_cfg.txt157
-rw-r--r--sys/dev/cxgbe/firmware/t5fw_cfg.txt197
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/cm.c271
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/cq.c6
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h14
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/mem.c34
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/qp.c16
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/t4.h3
-rw-r--r--sys/dev/cxgbe/iw_cxgbe/user.h1
-rw-r--r--sys/dev/cxgbe/offload.h2
-rw-r--r--sys/dev/cxgbe/t4_main.c46
-rw-r--r--sys/dev/cxgbe/t4_sge.c9
-rw-r--r--sys/dev/drm2/i915/i915_gem.c24
-rw-r--r--sys/dev/drm2/i915/intel_pm.c30
-rw-r--r--sys/dev/drm2/ttm/ttm_bo_vm.c27
-rw-r--r--sys/dev/e1000/if_igb.c60
-rw-r--r--sys/dev/e1000/if_igb.h6
-rw-r--r--sys/dev/ed/if_ed_3c503.c2
-rw-r--r--sys/dev/ed/if_ed_cbus.c22
-rw-r--r--sys/dev/extres/clk/clk.c79
-rw-r--r--sys/dev/extres/clk/clk.h3
-rw-r--r--sys/dev/extres/clk/clk_bus.c93
-rw-r--r--sys/dev/extres/clk/clk_div.c13
-rw-r--r--sys/dev/extres/clk/clk_fixed.c194
-rw-r--r--sys/dev/extres/clk/clk_fixed.h3
-rw-r--r--sys/dev/extres/clk/clk_gate.c13
-rw-r--r--sys/dev/extres/clk/clk_mux.c16
-rw-r--r--sys/dev/extres/clk/clkdev_if.m85
-rw-r--r--sys/dev/extres/phy/phy.c235
-rw-r--r--sys/dev/extres/phy/phy.h63
-rw-r--r--sys/dev/extres/phy/phy_if.m84
-rw-r--r--sys/dev/extres/regulator/regdev_if.m56
-rw-r--r--sys/dev/extres/regulator/regnode_if.m82
-rw-r--r--sys/dev/extres/regulator/regulator.c984
-rw-r--r--sys/dev/extres/regulator/regulator.h127
-rw-r--r--sys/dev/extres/regulator/regulator_bus.c89
-rw-r--r--sys/dev/extres/regulator/regulator_fixed.c456
-rw-r--r--sys/dev/extres/regulator/regulator_fixed.h (renamed from sys/dev/filemon/filemon_lock.c)47
-rw-r--r--sys/dev/fdt/fdt_common.c13
-rw-r--r--sys/dev/fdt/fdt_common.h1
-rw-r--r--sys/dev/fdt/simplebus.c6
-rw-r--r--sys/dev/filemon/filemon.c356
-rw-r--r--sys/dev/filemon/filemon_wrapper.c423
-rw-r--r--sys/dev/flash/mx25l.c127
-rw-r--r--sys/dev/flash/mx25lreg.h2
-rw-r--r--sys/dev/gpio/gpiobus.c4
-rw-r--r--sys/dev/gpio/ofw_gpiobus.c3
-rw-r--r--sys/dev/hyperv/include/hyperv.h2
-rw-r--r--sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c50
-rw-r--r--sys/dev/hyperv/utilities/hv_heartbeat.c4
-rw-r--r--sys/dev/hyperv/utilities/hv_kvp.c33
-rw-r--r--sys/dev/hyperv/utilities/hv_shutdown.c4
-rw-r--r--sys/dev/hyperv/utilities/hv_timesync.c4
-rw-r--r--sys/dev/hyperv/vmbus/hv_connection.c40
-rw-r--r--sys/dev/hyperv/vmbus/hv_et.c2
-rw-r--r--sys/dev/hyperv/vmbus/hv_hv.c30
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c110
-rw-r--r--sys/dev/hyperv/vmbus/hv_vmbus_priv.h8
-rw-r--r--sys/dev/ichwd/ichwd.c14
-rw-r--r--sys/dev/iicbus/iicbus.c2
-rw-r--r--sys/dev/iir/iir.c6
-rw-r--r--sys/dev/iir/iir_pci.c2
-rw-r--r--sys/dev/ipmi/ipmi.c53
-rw-r--r--sys/dev/isci/isci_controller.c10
-rw-r--r--sys/dev/isci/isci_io_request.c18
-rw-r--r--sys/dev/iscsi/iscsi.c3
-rw-r--r--sys/dev/iwn/if_iwn.c18
-rw-r--r--sys/dev/ixgbe/if_ix.c8
-rw-r--r--sys/dev/ixgbe/ix_txrx.c6
-rw-r--r--sys/dev/ixl/ixl_txrx.c6
-rw-r--r--sys/dev/le/lebuffer_sbus.c4
-rw-r--r--sys/dev/mca/mca_bus.c12
-rw-r--r--sys/dev/mfi/mfi.c4
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_rx.c8
-rw-r--r--sys/dev/mmc/host/dwmmc.c1
-rw-r--r--sys/dev/mmc/mmc.c2
-rw-r--r--sys/dev/mmc/mmcreg.h7
-rw-r--r--sys/dev/mvs/mvs_pci.c2
-rw-r--r--sys/dev/mvs/mvs_soc.c2
-rw-r--r--sys/dev/mxge/if_mxge.c12
-rw-r--r--sys/dev/ncr/ncr.c14
-rw-r--r--sys/dev/nctgpio/nctgpio.c802
-rw-r--r--sys/dev/netmap/netmap_generic.c3
-rw-r--r--sys/dev/oce/oce_if.c6
-rw-r--r--sys/dev/ofw/ofw_iicbus.c6
-rw-r--r--sys/dev/ofw/ofwbus.c4
-rw-r--r--sys/dev/ofw/ofwpci.c628
-rw-r--r--sys/dev/ofw/ofwpci.h83
-rw-r--r--sys/dev/pccard/pccard.c34
-rw-r--r--sys/dev/pccard/pccard_cis.c12
-rw-r--r--sys/dev/pccbb/pccbb.c10
-rw-r--r--sys/dev/pccbb/pccbb_pci.c2
-rw-r--r--sys/dev/pci/pci.c22
-rw-r--r--sys/dev/pci/pci_host_generic.c6
-rw-r--r--sys/dev/pci/pci_pci.c34
-rw-r--r--sys/dev/pci/pci_subr.c8
-rw-r--r--sys/dev/ppbus/vpo.c16
-rw-r--r--sys/dev/ppc/ppc.c4
-rw-r--r--sys/dev/proto/proto_bus_isa.c2
-rw-r--r--sys/dev/qlxgb/qla_isr.c7
-rw-r--r--sys/dev/qlxge/qls_isr.c7
-rw-r--r--sys/dev/random/random_harvestq.c3
-rw-r--r--sys/dev/sdhci/sdhci_fdt.c1
-rw-r--r--sys/dev/sdhci/sdhci_pci.c1
-rw-r--r--sys/dev/sfxge/sfxge_mcdi.c5
-rw-r--r--sys/dev/sfxge/sfxge_nvram.c5
-rw-r--r--sys/dev/siba/siba.c4
-rw-r--r--sys/dev/siis/siis.c2
-rw-r--r--sys/dev/sound/isa/ad1816.c4
-rw-r--r--sys/dev/sound/isa/ess.c6
-rw-r--r--sys/dev/sound/isa/mss.c4
-rw-r--r--sys/dev/sound/isa/sb16.c4
-rw-r--r--sys/dev/sound/isa/sb8.c2
-rw-r--r--sys/dev/sound/pci/als4000.c2
-rw-r--r--sys/dev/sound/pci/atiixp.c2
-rw-r--r--sys/dev/sound/pci/aureal.c2
-rw-r--r--sys/dev/sound/pci/cmi.c2
-rw-r--r--sys/dev/sound/pci/cs4281.c2
-rw-r--r--sys/dev/sound/pci/csapcm.c2
-rw-r--r--sys/dev/sound/pci/ds1.c2
-rw-r--r--sys/dev/sound/pci/emu10k1.c2
-rw-r--r--sys/dev/sound/pci/emu10kx.c2
-rw-r--r--sys/dev/sound/pci/envy24.c2
-rw-r--r--sys/dev/sound/pci/envy24ht.c2
-rw-r--r--sys/dev/sound/pci/es137x.c2
-rw-r--r--sys/dev/sound/pci/fm801.c2
-rw-r--r--sys/dev/sound/pci/hda/hdac.c2
-rw-r--r--sys/dev/sound/pci/hda/hdac.h4
-rw-r--r--sys/dev/sound/pci/hdspe-pcm.c2
-rw-r--r--sys/dev/sound/pci/ich.c2
-rw-r--r--sys/dev/sound/pci/maestro.c2
-rw-r--r--sys/dev/sound/pci/maestro3.c2
-rw-r--r--sys/dev/sound/pci/neomagic.c2
-rw-r--r--sys/dev/sound/pci/solo.c2
-rw-r--r--sys/dev/sound/pci/t4dwave.c2
-rw-r--r--sys/dev/sound/pci/via8233.c2
-rw-r--r--sys/dev/sound/pci/via82c686.c2
-rw-r--r--sys/dev/sound/pci/vibes.c4
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c13
-rw-r--r--sys/dev/uart/uart_dev_snps.c283
-rw-r--r--sys/dev/urtwn/if_urtwn.c (renamed from sys/dev/usb/wlan/if_urtwn.c)137
-rw-r--r--sys/dev/urtwn/if_urtwnreg.h (renamed from sys/dev/usb/wlan/if_urtwnreg.h)0
-rw-r--r--sys/dev/urtwn/if_urtwnvar.h (renamed from sys/dev/usb/wlan/if_urtwnvar.h)0
-rw-r--r--sys/dev/usb/controller/ehci_pci.c6
-rw-r--r--sys/dev/usb/controller/ohci_pci.c3
-rw-r--r--sys/dev/usb/controller/uhci_pci.c6
-rw-r--r--sys/dev/usb/controller/xhci_pci.c5
-rw-r--r--sys/dev/usb/usb_busdma.c27
-rw-r--r--sys/dev/usb/usbdevs1
-rw-r--r--sys/dev/usb/video/udl.c3
-rw-r--r--sys/dev/usb/wlan/if_rum.c275
-rw-r--r--sys/dev/usb/wlan/if_rumreg.h13
-rw-r--r--sys/dev/usb/wlan/if_rumvar.h10
-rw-r--r--sys/dev/vnic/nic_main.c24
-rw-r--r--sys/dev/vnic/nicvf_main.c26
-rw-r--r--sys/dev/vnic/nicvf_queues.c123
-rw-r--r--sys/dev/vnic/nicvf_queues.h2
-rw-r--r--sys/dev/vnic/thunder_bgx_fdt.c22
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c8
-rw-r--r--sys/dev/vxge/vxge.c9
-rw-r--r--sys/dev/wbwd/wbwd.c390
-rw-r--r--sys/dev/wl/if_wl.c2
-rw-r--r--sys/dev/wpi/if_wpi.c53
-rw-r--r--sys/dev/wpi/if_wpivar.h4
-rw-r--r--sys/dev/xe/if_xe.c4
-rw-r--r--sys/dev/xe/if_xe_pccard.c2
-rw-r--r--sys/dev/xen/blkfront/blkfront.c28
-rw-r--r--sys/dev/xen/blkfront/block.h7
-rw-r--r--sys/dev/xen/netfront/netfront.c7
191 files changed, 7124 insertions, 1496 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 70d4bce..6f5a11f 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -795,10 +795,10 @@ acpi_print_child(device_t bus, device_t child)
int retval = 0;
retval += bus_print_child_header(bus, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
- retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
+ retval += resource_list_print_type(rl, "drq", SYS_RES_DRQ, "%jd");
if (device_get_flags(child))
retval += printf(" flags %#x", device_get_flags(child));
retval += bus_print_child_domain(bus, child);
@@ -1156,7 +1156,7 @@ acpi_sysres_alloc(device_t dev)
rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
STAILQ_FOREACH(rle, rl, link) {
if (rle->res != NULL) {
- device_printf(dev, "duplicate resource for %lx\n", rle->start);
+ device_printf(dev, "duplicate resource for %jx\n", rle->start);
continue;
}
@@ -1179,7 +1179,7 @@ acpi_sysres_alloc(device_t dev)
rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
rle->res = res;
} else if (bootverbose)
- device_printf(dev, "reservation of %lx, %lx (%d) failed\n",
+ device_printf(dev, "reservation of %jx, %jx (%d) failed\n",
rle->start, rle->count, rle->type);
}
return (0);
diff --git a/sys/dev/acpica/acpi_hpet.c b/sys/dev/acpica/acpi_hpet.c
index 76fbd5a..da1e160e 100644
--- a/sys/dev/acpica/acpi_hpet.c
+++ b/sys/dev/acpica/acpi_hpet.c
@@ -453,7 +453,7 @@ hpet_attach(device_t dev)
/* Validate that we can access the whole region. */
if (rman_get_size(sc->mem_res) < HPET_MEM_WIDTH) {
- device_printf(dev, "memory region width %ld too small\n",
+ device_printf(dev, "memory region width %jd too small\n",
rman_get_size(sc->mem_res));
bus_free_resource(dev, SYS_RES_MEMORY, sc->mem_res);
return (ENXIO);
diff --git a/sys/dev/acpica/acpi_timer.c b/sys/dev/acpica/acpi_timer.c
index 2cdf908..34a8320 100644
--- a/sys/dev/acpica/acpi_timer.c
+++ b/sys/dev/acpica/acpi_timer.c
@@ -152,7 +152,7 @@ acpi_timer_identify(driver_t *driver, device_t parent)
rlen = AcpiGbl_FADT.PmTimerLength;
rstart = AcpiGbl_FADT.XPmTimerBlock.Address;
if (bus_set_resource(dev, rtype, rid, rstart, rlen))
- device_printf(dev, "couldn't set resource (%s 0x%lx+0x%lx)\n",
+ device_printf(dev, "couldn't set resource (%s 0x%jx+0x%jx)\n",
(rtype == SYS_RES_IOPORT) ? "port" : "mem", rstart, rlen);
return_VOID;
}
diff --git a/sys/dev/advansys/adv_isa.c b/sys/dev/advansys/adv_isa.c
index 00381a3..3b3a45b 100644
--- a/sys/dev/advansys/adv_isa.c
+++ b/sys/dev/advansys/adv_isa.c
@@ -136,7 +136,7 @@ adv_isa_probe(device_t dev)
|| (iobase != adv_isa_ioports[port_index])) {
if (bootverbose)
device_printf(dev,
- "Invalid baseport of 0x%lx specified. "
+ "Invalid baseport of 0x%jx specified. "
"Nearest valid baseport is 0x%x. Failing "
"probe.\n", iobase,
(port_index <= max_port_index) ?
diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c
index 25ebbf7..8341f66 100644
--- a/sys/dev/ahci/ahci.c
+++ b/sys/dev/ahci/ahci.c
@@ -527,7 +527,7 @@ ahci_alloc_resource(device_t dev, device_t child, int type, int *rid,
{
struct ahci_controller *ctlr = device_get_softc(dev);
struct resource *res;
- long st;
+ rman_res_t st;
int offset, size, unit;
unit = (intptr_t)device_get_ivars(child);
diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h
index 86bdf2b..868a376 100644
--- a/sys/dev/ahci/ahci.h
+++ b/sys/dev/ahci/ahci.h
@@ -597,6 +597,7 @@ enum ahci_err_type {
#define AHCI_Q_1MSI 0x00020000
#define AHCI_Q_FORCE_PI 0x00040000
#define AHCI_Q_RESTORE_CAP 0x00080000
+#define AHCI_Q_NOMSIX 0x00100000
#define AHCI_Q_BIT_STRING \
"\020" \
@@ -619,7 +620,8 @@ enum ahci_err_type {
"\021ABAR0" \
"\0221MSI" \
"\023FORCE_PI" \
- "\024RESTORE_CAP"
+ "\024RESTORE_CAP" \
+ "\025NOMSIX"
int ahci_attach(device_t dev);
int ahci_detach(device_t dev);
diff --git a/sys/dev/ahci/ahci_pci.c b/sys/dev/ahci/ahci_pci.c
index 5c236ce..57f7ea9 100644
--- a/sys/dev/ahci/ahci_pci.c
+++ b/sys/dev/ahci/ahci_pci.c
@@ -293,7 +293,7 @@ static const struct {
{0x11851039, 0x00, "SiS 968", 0},
{0x01861039, 0x00, "SiS 968", 0},
{0xa01c177d, 0x00, "ThunderX", AHCI_Q_ABAR0|AHCI_Q_1MSI},
- {0x00311c36, 0x00, "Annapurna", AHCI_Q_FORCE_PI|AHCI_Q_RESTORE_CAP},
+ {0x00311c36, 0x00, "Annapurna", AHCI_Q_FORCE_PI|AHCI_Q_RESTORE_CAP|AHCI_Q_NOMSIX},
{0x00000000, 0x00, NULL, 0}
};
@@ -437,6 +437,9 @@ ahci_pci_attach(device_t dev)
&ctlr->r_rid, RF_ACTIVE)))
return ENXIO;
+ if (ctlr->quirks & AHCI_Q_NOMSIX)
+ msix_count = 0;
+
/* Read MSI-x BAR IDs if supported */
if (msix_count > 0) {
error = ahci_pci_read_msix_bars(dev, &table_bar, &pba_bar);
diff --git a/sys/dev/amdsbwd/amdsbwd.c b/sys/dev/amdsbwd/amdsbwd.c
index 7221db4..207d0b9 100644
--- a/sys/dev/amdsbwd/amdsbwd.c
+++ b/sys/dev/amdsbwd/amdsbwd.c
@@ -106,6 +106,8 @@ __FBSDID("$FreeBSD$");
/* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1. */
#define AMDSB_SMBUS_DEVID 0x43851002
#define AMDSB8_SMBUS_REVID 0x40
+#define AMDHUDSON_SMBUS_DEVID 0x780b1022
+#define AMDKERNCZ_SMBUS_DEVID 0x790b1022
#define amdsbwd_verbose_printf(dev, ...) \
do { \
@@ -279,7 +281,9 @@ amdsbwd_identify(driver_t *driver, device_t parent)
smb_dev = pci_find_bsf(0, 20, 0);
if (smb_dev == NULL)
return;
- if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID)
+ if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
+ pci_get_devid(smb_dev) != AMDHUDSON_SMBUS_DEVID &&
+ pci_get_devid(smb_dev) != AMDKERNCZ_SMBUS_DEVID)
return;
child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
@@ -309,10 +313,12 @@ amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
*addr <<= 8;
*addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
}
+ *addr &= ~0x07u;
+
/* Set watchdog timer tick to 1s. */
val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
val &= ~AMDSB_WDT_RES_MASK;
- val |= AMDSB_WDT_RES_10MS;
+ val |= AMDSB_WDT_RES_1S;
pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
/* Enable watchdog device (in stopped state). */
@@ -372,7 +378,7 @@ amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val);
#endif
- device_set_desc(dev, "AMD SB8xx Watchdog Timer");
+ device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
}
static int
@@ -404,7 +410,8 @@ amdsbwd_probe(device_t dev)
smb_dev = pci_find_bsf(0, 20, 0);
KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
- if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
+ if (pci_get_devid(smb_dev) == AMDSB_SMBUS_DEVID &&
+ pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
amdsbwd_probe_sb7xx(dev, res, &addr);
else
amdsbwd_probe_sb8xx(dev, res, &addr);
@@ -440,10 +447,7 @@ amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
smb_dev = pci_find_bsf(0, 20, 0);
KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
- if (pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
- sc->ms_per_tick = 10;
- else
- sc->ms_per_tick = 1000;
+ sc->ms_per_tick = 1000;
sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
&sc->rid_ctrl, RF_ACTIVE);
diff --git a/sys/dev/arcmsr/arcmsr.c b/sys/dev/arcmsr/arcmsr.c
index 3cf7fce..cabb99a 100644
--- a/sys/dev/arcmsr/arcmsr.c
+++ b/sys/dev/arcmsr/arcmsr.c
@@ -872,7 +872,7 @@ static void arcmsr_srb_timeout(void *arg)
ARCMSR_LOCK_ACQUIRE(&acb->isr_lock);
if(srb->srb_state == ARCMSR_SRB_START)
{
- cmd = srb->pccb->csio.cdb_io.cdb_bytes[0];
+ cmd = scsiio_cdb_ptr(&srb->pccb->csio)[0];
srb->srb_state = ARCMSR_SRB_TIMEOUT;
srb->pccb->ccb_h.status |= CAM_CMD_TIMEOUT;
arcmsr_srb_complete(srb, 1);
@@ -997,7 +997,7 @@ static void arcmsr_build_srb(struct CommandControlBlock *srb,
arcmsr_cdb->LUN = pccb->ccb_h.target_lun;
arcmsr_cdb->Function = 1;
arcmsr_cdb->CdbLength = (u_int8_t)pcsio->cdb_len;
- bcopy(pcsio->cdb_io.cdb_bytes, arcmsr_cdb->Cdb, pcsio->cdb_len);
+ bcopy(scsiio_cdb_ptr(pcsio), arcmsr_cdb->Cdb, pcsio->cdb_len);
if(nseg != 0) {
struct AdapterControlBlock *acb = srb->acb;
bus_dmasync_op_t op;
@@ -2453,10 +2453,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, union ccb *p
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
- u_int32_t controlcode = (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[5] << 24 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[6] << 16 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[7] << 8 |
- (u_int32_t ) pccb->csio.cdb_io.cdb_bytes[8];
+ uint8_t *ptr = scsiio_cdb_ptr(&pccb->csio);
+ u_int32_t controlcode = (u_int32_t ) ptr[5] << 24 |
+ (u_int32_t ) ptr[6] << 16 |
+ (u_int32_t ) ptr[7] << 8 |
+ (u_int32_t ) ptr[8];
/* 4 bytes: Areca io control code */
if ((pccb->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) {
buffer = pccb->csio.data_ptr;
@@ -2683,7 +2684,7 @@ static void arcmsr_execute_srb(void *arg, bus_dma_segment_t *dm_segs, int nseg,
if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
u_int8_t block_cmd, cmd;
- cmd = pccb->csio.cdb_io.cdb_bytes[0];
+ cmd = scsiio_cdb_ptr(&pccb->csio)[0];
block_cmd = cmd & 0x0f;
if(block_cmd == 0x08 || block_cmd == 0x0a) {
printf("arcmsr%d:block 'read/write' command "
@@ -2800,7 +2801,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
return;
}
pccb->ccb_h.status |= CAM_REQ_CMP;
- switch (pccb->csio.cdb_io.cdb_bytes[0]) {
+ switch (scsiio_cdb_ptr(&pccb->csio)[0]) {
case INQUIRY: {
unsigned char inqdata[36];
char *buffer = pccb->csio.data_ptr;
@@ -2853,6 +2854,12 @@ static void arcmsr_action(struct cam_sim *psim, union ccb *pccb)
int target = pccb->ccb_h.target_id;
int error;
+ if (pccb->ccb_h.flags & CAM_CDB_PHYS) {
+ pccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(pccb);
+ return;
+ }
+
if(target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, pccb);
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
index 6b825c0..1c81c6f 100644
--- a/sys/dev/ata/ata-lowlevel.c
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -851,7 +851,7 @@ ata_pio_read(struct ata_request *request, int length)
panic("ata_pio_read: Unsupported CAM data type %x\n",
(request->ccb->ccb_h.flags & CAM_DATA_MASK));
- /* We may have extra byte already red but not stored. */
+ /* We may have extra byte already read but not stored. */
if (resid) {
addr[0] = buf[1];
addr++;
diff --git a/sys/dev/ath/if_ath_lna_div.c b/sys/dev/ath/if_ath_lna_div.c
index f0a33a5..5c770c0 100644
--- a/sys/dev/ath/if_ath_lna_div.c
+++ b/sys/dev/ath/if_ath_lna_div.c
@@ -766,7 +766,7 @@ ath_lna_rx_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs,
/* Short scan check */
if (antcomb->scan && antcomb->alt_good) {
- if (time_after(ticks, antcomb->scan_start_time +
+ if (ieee80211_time_after(ticks, antcomb->scan_start_time +
msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
short_scan = AH_TRUE;
else
diff --git a/sys/dev/atkbdc/atkbdc_subr.c b/sys/dev/atkbdc/atkbdc_subr.c
index 28730c6..436d97a 100644
--- a/sys/dev/atkbdc/atkbdc_subr.c
+++ b/sys/dev/atkbdc/atkbdc_subr.c
@@ -63,7 +63,7 @@ atkbdc_print_child(device_t bus, device_t dev)
retval += printf(" flags 0x%x", flags);
irq = bus_get_resource_start(dev, SYS_RES_IRQ, kbdcdev->rid);
if (irq != 0)
- retval += printf(" irq %ld", irq);
+ retval += printf(" irq %jd", irq);
retval += bus_print_child_footer(bus, dev);
return (retval);
diff --git a/sys/dev/bhnd/bhnd.c b/sys/dev/bhnd/bhnd.c
index 674094a..860d58d 100644
--- a/sys/dev/bhnd/bhnd.c
+++ b/sys/dev/bhnd/bhnd.c
@@ -451,7 +451,7 @@ bhnd_generic_print_child(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL) {
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
}
retval += printf(" at core %u", bhnd_get_core_index(child));
@@ -499,7 +499,7 @@ bhnd_generic_probe_nomatch(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL)
- resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
printf(" at core %u (no driver attached)\n",
bhnd_get_core_index(child));
diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c
index 238d4ee..43580b7 100644
--- a/sys/dev/bhnd/bhndb/bhndb.c
+++ b/sys/dev/bhnd/bhndb/bhndb.c
@@ -143,9 +143,9 @@ bhndb_print_child(device_t dev, device_t child)
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL) {
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
- "%#lx");
+ "%#jx");
retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
- "%ld");
+ "%jd");
}
retval += bus_print_child_domain(dev, child);
diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c
index 2f474d1..decef5f 100644
--- a/sys/dev/bwn/if_bwn.c
+++ b/sys/dev/bwn/if_bwn.c
@@ -2612,7 +2612,7 @@ bwn_phy_g_task_15s(struct bwn_mac *mac)
BWN_GETTIME(now);
if (bwn_has_hwpctl(mac)) {
expire = now - BWN_LO_PWRVEC_EXPIRE;
- if (time_before(lo->pwr_vec_read_time, expire)) {
+ if (ieee80211_time_before(lo->pwr_vec_read_time, expire)) {
bwn_lo_get_powervector(mac);
bwn_phy_g_dc_lookup_init(mac, 0);
}
@@ -2621,7 +2621,7 @@ bwn_phy_g_task_15s(struct bwn_mac *mac)
expire = now - BWN_LO_CALIB_EXPIRE;
TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
- if (!time_before(cal->calib_time, expire))
+ if (!ieee80211_time_before(cal->calib_time, expire))
continue;
if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
@@ -6149,7 +6149,7 @@ bwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
nanouptime(&ts);
- if (time_before(lo->txctl_measured_time,
+ if (ieee80211_time_before(lo->txctl_measured_time,
(ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
bwn_lo_measure_txctl_values(mac);
@@ -9365,7 +9365,7 @@ bwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
BWN_GETTIME(now);
- if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
+ if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime))
return;
phy->nexttime = now + 2 * 1000;
diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c
index d944395..53d8e97 100644
--- a/sys/dev/bxe/bxe.c
+++ b/sys/dev/bxe/bxe.c
@@ -3063,7 +3063,7 @@ bxe_tpa_stop(struct bxe_softc *sc,
#if __FreeBSD_version >= 800000
/* specify what RSS queue was used for this flow */
m->m_pkthdr.flowid = fp->index;
- M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+ BXE_SET_FLOWID(m);
#endif
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
@@ -3352,7 +3352,7 @@ bxe_rxeof(struct bxe_softc *sc,
#if __FreeBSD_version >= 800000
/* specify what RSS queue was used for this flow */
m->m_pkthdr.flowid = fp->index;
- M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
+ BXE_SET_FLOWID(m);
#endif
next_rx:
@@ -4829,6 +4829,8 @@ bxe_dump_mbuf(struct bxe_softc *sc,
}
while (m) {
+
+#if __FreeBSD_version >= 1000000
BLOGD(sc, DBG_MBUF,
"%02d: mbuf=%p m_len=%d m_flags=0x%b m_data=%p\n",
i, m, m->m_len, m->m_flags, M_FLAG_BITS, m->m_data);
@@ -4839,6 +4841,26 @@ bxe_dump_mbuf(struct bxe_softc *sc,
i, m->m_pkthdr.len, m->m_flags, M_FLAG_BITS,
(int)m->m_pkthdr.csum_flags, CSUM_BITS);
}
+#else
+ BLOGD(sc, DBG_MBUF,
+ "%02d: mbuf=%p m_len=%d m_flags=0x%b m_data=%p\n",
+ i, m, m->m_len, m->m_flags,
+ "\20\1M_EXT\2M_PKTHDR\3M_EOR\4M_RDONLY", m->m_data);
+
+ if (m->m_flags & M_PKTHDR) {
+ BLOGD(sc, DBG_MBUF,
+ "%02d: - m_pkthdr: tot_len=%d flags=0x%b csum_flags=%b\n",
+ i, m->m_pkthdr.len, m->m_flags,
+ "\20\12M_BCAST\13M_MCAST\14M_FRAG"
+ "\15M_FIRSTFRAG\16M_LASTFRAG\21M_VLANTAG"
+ "\22M_PROMISC\23M_NOFREE",
+ (int)m->m_pkthdr.csum_flags,
+ "\20\1CSUM_IP\2CSUM_TCP\3CSUM_UDP\4CSUM_IP_FRAGS"
+ "\5CSUM_FRAGMENT\6CSUM_TSO\11CSUM_IP_CHECKED"
+ "\12CSUM_IP_VALID\13CSUM_DATA_VALID"
+ "\14CSUM_PSEUDO_HDR");
+ }
+#endif /* #if __FreeBSD_version >= 1000000 */
if (m->m_flags & M_EXT) {
switch (m->m_ext.ext_type) {
@@ -5222,7 +5244,9 @@ bxe_tx_encap(struct bxe_fastpath *fp, struct mbuf **m_head)
sc = fp->sc;
+#if __FreeBSD_version >= 800000
M_ASSERTPKTHDR(*m_head);
+#endif /* #if __FreeBSD_version >= 800000 */
m0 = *m_head;
rc = defragged = nbds = ovlan = vlan_off = total_pkt_size = 0;
@@ -5741,7 +5765,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
if (!sc->link_vars.link_up ||
(if_getdrvflags(ifp) &
(IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) {
- rc = drbr_enqueue_drv(ifp, tx_br, m);
+ rc = drbr_enqueue(ifp, tx_br, m);
goto bxe_tx_mq_start_locked_exit;
}
@@ -5756,7 +5780,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
next = drbr_dequeue_drv(ifp, tx_br);
} else if (drbr_needs_enqueue_drv(ifp, tx_br)) {
/* have both new and pending work, maintain packet order */
- rc = drbr_enqueue_drv(ifp, tx_br, m);
+ rc = drbr_enqueue(ifp, tx_br, m);
if (rc != 0) {
fp->eth_q_stats.tx_soft_errors++;
goto bxe_tx_mq_start_locked_exit;
@@ -5785,7 +5809,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc,
/* mark the TX queue as full and save the frame */
if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
/* XXX this may reorder the frame */
- rc = drbr_enqueue_drv(ifp, tx_br, next);
+ rc = drbr_enqueue(ifp, tx_br, next);
fp->eth_q_stats.mbuf_alloc_tx--;
fp->eth_q_stats.tx_frames_deferred++;
}
@@ -5837,7 +5861,8 @@ bxe_tx_mq_start(struct ifnet *ifp,
fp_index = 0; /* default is the first queue */
/* check if flowid is set */
- if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
+
+ if (BXE_VALID_FLOWID(m))
fp_index = (m->m_pkthdr.flowid % sc->num_queues);
fp = &sc->fp[fp_index];
@@ -5846,7 +5871,7 @@ bxe_tx_mq_start(struct ifnet *ifp,
rc = bxe_tx_mq_start_locked(sc, ifp, fp, m);
BXE_FP_TX_UNLOCK(fp);
} else
- rc = drbr_enqueue_drv(ifp, fp->tx_br, m);
+ rc = drbr_enqueue(ifp, fp->tx_br, m);
return (rc);
}
@@ -12845,7 +12870,7 @@ bxe_allocate_bars(struct bxe_softc *sc)
sc->bar[i].handle = rman_get_bushandle(sc->bar[i].resource);
sc->bar[i].kva = (vm_offset_t)rman_get_virtual(sc->bar[i].resource);
- BLOGI(sc, "PCI BAR%d [%02x] memory allocated: %p-%p (%ld) -> %p\n",
+ BLOGI(sc, "PCI BAR%d [%02x] memory allocated: %p-%p (%jd) -> %p\n",
i, PCIR_BAR(i),
(void *)rman_get_start(sc->bar[i].resource),
(void *)rman_get_end(sc->bar[i].resource),
@@ -15677,18 +15702,11 @@ bxe_add_sysctls(struct bxe_softc *sc)
CTLFLAG_RD, BXE_DRIVER_VERSION, 0,
"version");
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
- CTLFLAG_RD, sc->devinfo.bc_ver_str, 0,
- "bootcode version");
-
snprintf(sc->fw_ver_str, sizeof(sc->fw_ver_str), "%d.%d.%d.%d",
BCM_5710_FW_MAJOR_VERSION,
BCM_5710_FW_MINOR_VERSION,
BCM_5710_FW_REVISION_VERSION,
BCM_5710_FW_ENGINEERING_VERSION);
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
- CTLFLAG_RD, sc->fw_ver_str, 0,
- "firmware version");
snprintf(sc->mf_mode_str, sizeof(sc->mf_mode_str), "%s",
((sc->devinfo.mf_info.mf_mode == SINGLE_FUNCTION) ? "Single" :
@@ -15696,32 +15714,58 @@ bxe_add_sysctls(struct bxe_softc *sc)
(sc->devinfo.mf_info.mf_mode == MULTI_FUNCTION_SI) ? "MF-SI" :
(sc->devinfo.mf_info.mf_mode == MULTI_FUNCTION_AFEX) ? "MF-AFEX" :
"Unknown"));
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
- CTLFLAG_RD, sc->mf_mode_str, 0,
- "multifunction mode");
-
SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "mf_vnics",
CTLFLAG_RD, &sc->devinfo.mf_info.vnics_per_port, 0,
"multifunction vnics per port");
- SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
- CTLFLAG_RD, sc->mac_addr_str, 0,
- "mac address");
-
snprintf(sc->pci_link_str, sizeof(sc->pci_link_str), "%s x%d",
((sc->devinfo.pcie_link_speed == 1) ? "2.5GT/s" :
(sc->devinfo.pcie_link_speed == 2) ? "5.0GT/s" :
(sc->devinfo.pcie_link_speed == 4) ? "8.0GT/s" :
"???GT/s"),
sc->devinfo.pcie_link_width);
+
+ sc->debug = bxe_debug;
+
+#if __FreeBSD_version >= 900000
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
+ CTLFLAG_RD, sc->devinfo.bc_ver_str, 0,
+ "bootcode version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
+ CTLFLAG_RD, sc->fw_ver_str, 0,
+ "firmware version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
+ CTLFLAG_RD, sc->mf_mode_str, 0,
+ "multifunction mode");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
+ CTLFLAG_RD, sc->mac_addr_str, 0,
+ "mac address");
SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pci_link",
CTLFLAG_RD, sc->pci_link_str, 0,
"pci link status");
-
- sc->debug = bxe_debug;
SYSCTL_ADD_ULONG(ctx, children, OID_AUTO, "debug",
CTLFLAG_RW, &sc->debug,
"debug logging mode");
+#else
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bc_version",
+ CTLFLAG_RD, &sc->devinfo.bc_ver_str, 0,
+ "bootcode version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "fw_version",
+ CTLFLAG_RD, &sc->fw_ver_str, 0,
+ "firmware version");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mf_mode",
+ CTLFLAG_RD, &sc->mf_mode_str, 0,
+ "multifunction mode");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "mac_addr",
+ CTLFLAG_RD, &sc->mac_addr_str, 0,
+ "mac address");
+ SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pci_link",
+ CTLFLAG_RD, &sc->pci_link_str, 0,
+ "pci link status");
+ SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "debug",
+ CTLFLAG_RW, &sc->debug, 0,
+ "debug logging mode");
+#endif /* #if __FreeBSD_version >= 900000 */
SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "trigger_grcdump",
CTLTYPE_UINT | CTLFLAG_RW, sc, 0,
diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h
index e87c65b..73f72ce 100644
--- a/sys/dev/bxe/bxe.h
+++ b/sys/dev/bxe/bxe.h
@@ -2271,6 +2271,17 @@ void bxe_dump_mem(struct bxe_softc *sc, char *tag,
void bxe_dump_mbuf_data(struct bxe_softc *sc, char *pTag,
struct mbuf *m, uint8_t contents);
+
+#if __FreeBSD_version >= 800000
+#if __FreeBSD_version >= 1000000
+#define BXE_SET_FLOWID(m) M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE)
+#define BXE_VALID_FLOWID(m) (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
+#else
+#define BXE_VALID_FLOWID(m) ((m->m_flags & M_FLOWID) != 0)
+#define BXE_SET_FLOWID(m) m->m_flags |= M_FLOWID
+#endif
+#endif /* #if __FreeBSD_version >= 800000 */
+
/***********/
/* INLINES */
/***********/
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c
index 5d7704a..f9f7816 100644
--- a/sys/dev/cardbus/cardbus_cis.c
+++ b/sys/dev/cardbus/cardbus_cis.c
@@ -485,7 +485,8 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
"to read CIS.\n");
return (NULL);
}
- DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
+ DEVPRINTF((cbdev, "CIS Mapped to %#jx\n",
+ rman_get_start(res)));
/* Flip to the right ROM image if CIS is in ROM */
if (space == PCIM_CIS_ASI_ROM) {
diff --git a/sys/dev/ctau/if_ct.c b/sys/dev/ctau/if_ct.c
index da8d32c..a3df2a8 100644
--- a/sys/dev/ctau/if_ct.c
+++ b/sys/dev/ctau/if_ct.c
@@ -459,7 +459,7 @@ static int ct_probe (device_t dev)
}
if (!ct_probe_board (iobase, -1, -1)) {
- printf ("ct%d: probing for Tau-ISA at %lx faild\n", unit, iobase);
+ printf ("ct%d: probing for Tau-ISA at %jx faild\n", unit, iobase);
return ENXIO;
}
@@ -632,7 +632,7 @@ static int ct_attach (device_t dev)
ct_ln[2] = '0' + unit;
mtx_init (&bd->ct_mtx, ct_ln, MTX_NETWORK_LOCK, MTX_DEF|MTX_RECURSE);
if (! probe_irq (b, irq)) {
- printf ("ct%d: irq %ld not functional\n", unit, irq);
+ printf ("ct%d: irq %jd not functional\n", unit, irq);
bd->board = 0;
adapter [unit] = 0;
free (b, M_DEVBUF);
@@ -651,7 +651,7 @@ static int ct_attach (device_t dev)
if (bus_setup_intr (dev, bd->irq_res,
INTR_TYPE_NET|INTR_MPSAFE,
NULL, ct_intr, bd, &bd->intrhand)) {
- printf ("ct%d: Can't setup irq %ld\n", unit, irq);
+ printf ("ct%d: Can't setup irq %jd\n", unit, irq);
bd->board = 0;
adapter [unit] = 0;
free (b, M_DEVBUF);
diff --git a/sys/dev/cxgb/cxgb_sge.c b/sys/dev/cxgb/cxgb_sge.c
index a622fcf..c83bd66 100644
--- a/sys/dev/cxgb/cxgb_sge.c
+++ b/sys/dev/cxgb/cxgb_sge.c
@@ -2976,11 +2976,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
#if defined(INET6) || defined(INET)
/* Flush LRO */
- while (!SLIST_EMPTY(&lro_ctrl->lro_active)) {
- struct lro_entry *queued = SLIST_FIRST(&lro_ctrl->lro_active);
- SLIST_REMOVE_HEAD(&lro_ctrl->lro_active, next);
- tcp_lro_flush(lro_ctrl, queued);
- }
+ tcp_lro_flush_all(lro_ctrl);
#endif
if (sleeping)
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h
index ee14712..2193142 100644
--- a/sys/dev/cxgbe/adapter.h
+++ b/sys/dev/cxgbe/adapter.h
@@ -246,12 +246,10 @@ struct vi_info {
int rsrv_noflowq; /* Reserve queue 0 for non-flowid packets */
int nrxq; /* # of rx queues */
int first_rxq; /* index of first rx queue */
-#ifdef TCP_OFFLOAD
int nofldtxq; /* # of offload tx queues */
int first_ofld_txq; /* index of first offload tx queue */
int nofldrxq; /* # of offload rx queues */
int first_ofld_rxq; /* index of first offload rx queue */
-#endif
int tmr_idx;
int pktc_idx;
int qsize_rxq;
@@ -311,9 +309,7 @@ struct cluster_layout {
struct cluster_metadata {
u_int refcount;
-#ifdef INVARIANTS
struct fl_sdesc *sd; /* For debug only. Could easily be stale */
-#endif
};
struct fl_sdesc {
@@ -571,7 +567,6 @@ iq_to_rxq(struct sge_iq *iq)
}
-#ifdef TCP_OFFLOAD
/* ofld_rxq: SGE ingress queue + SGE free list + miscellaneous items */
struct sge_ofld_rxq {
struct sge_iq iq; /* MUST be first */
@@ -584,7 +579,6 @@ iq_to_ofld_rxq(struct sge_iq *iq)
return (__containerof(iq, struct sge_ofld_rxq, iq));
}
-#endif
struct wrqe {
STAILQ_ENTRY(wrqe) link;
@@ -636,7 +630,6 @@ struct sge_wrq {
} __aligned(CACHE_LINE_SIZE);
-#ifdef DEV_NETMAP
struct sge_nm_rxq {
struct vi_info *vi;
@@ -691,19 +684,14 @@ struct sge_nm_txq {
bus_addr_t ba;
int iqidx;
} __aligned(CACHE_LINE_SIZE);
-#endif
struct sge {
int nrxq; /* total # of Ethernet rx queues */
int ntxq; /* total # of Ethernet tx tx queues */
-#ifdef TCP_OFFLOAD
int nofldrxq; /* total # of TOE rx queues */
int nofldtxq; /* total # of TOE tx queues */
-#endif
-#ifdef DEV_NETMAP
int nnmrxq; /* total # of netmap rx queues */
int nnmtxq; /* total # of netmap tx queues */
-#endif
int niq; /* total # of ingress queues */
int neq; /* total # of egress queues */
@@ -712,14 +700,10 @@ struct sge {
struct sge_wrq *ctrlq; /* Control queues */
struct sge_txq *txq; /* NIC tx queues */
struct sge_rxq *rxq; /* NIC rx queues */
-#ifdef TCP_OFFLOAD
struct sge_wrq *ofld_txq; /* TOE tx queues */
struct sge_ofld_rxq *ofld_rxq; /* TOE rx queues */
-#endif
-#ifdef DEV_NETMAP
struct sge_nm_txq *nm_txq; /* netmap tx queues */
struct sge_nm_rxq *nm_rxq; /* netmap rx queues */
-#endif
uint16_t iq_start;
int eq_start;
@@ -778,20 +762,16 @@ struct adapter {
struct port_info *port[MAX_NPORTS];
uint8_t chan_map[MAX_NCHAN];
-#ifdef TCP_OFFLOAD
void *tom_softc; /* (struct tom_data *) */
struct tom_tunables tt;
void *iwarp_softc; /* (struct c4iw_dev *) */
void *iscsi_ulp_softc; /* (struct cxgbei_data *) */
-#endif
struct l2t_data *l2t; /* L2 table */
struct tid_info tids;
uint16_t doorbells;
-#ifdef TCP_OFFLOAD
int offload_map; /* ports with IFCAP_TOE enabled */
int active_ulds; /* ULDs activated on this adapter */
-#endif
int flags;
int debug_flags;
@@ -840,11 +820,9 @@ struct adapter {
fw_msg_handler_t fw_msg_handler[7]; /* NUM_FW6_TYPES */
cpl_handler_t cpl_handler[0xef]; /* NUM_CPL_CMDS */
-#ifdef INVARIANTS
const char *last_op;
const void *last_op_thr;
int last_op_flags;
-#endif
int sc_do_rxcopy;
};
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c
index 92104c8..588f6fd 100644
--- a/sys/dev/cxgbe/common/t4_hw.c
+++ b/sys/dev/cxgbe/common/t4_hw.c
@@ -5615,6 +5615,7 @@ void t4_get_port_stats_offset(struct adapter *adap, int idx,
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
u32 bgmap = t4_get_mps_bg_map(adap, idx);
+ u32 stat_ctl;
#define GET_STAT(name) \
t4_read_reg64(adap, \
@@ -5622,6 +5623,8 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
T5_PORT_REG(idx, A_MPS_PORT_STAT_##name##_L)))
#define GET_STAT_COM(name) t4_read_reg64(adap, A_MPS_STAT_##name##_L)
+ stat_ctl = t4_read_reg(adap, A_MPS_STAT_CTL);
+
p->tx_pause = GET_STAT(TX_PORT_PAUSE);
p->tx_octets = GET_STAT(TX_PORT_BYTES);
p->tx_frames = GET_STAT(TX_PORT_FRAMES);
@@ -5646,6 +5649,12 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
p->tx_ppp6 = GET_STAT(TX_PORT_PPP6);
p->tx_ppp7 = GET_STAT(TX_PORT_PPP7);
+ if (stat_ctl & F_COUNTPAUSESTATTX) {
+ p->tx_frames -= p->tx_pause;
+ p->tx_octets -= p->tx_pause * 64;
+ p->tx_mcast_frames -= p->tx_pause;
+ }
+
p->rx_pause = GET_STAT(RX_PORT_PAUSE);
p->rx_octets = GET_STAT(RX_PORT_BYTES);
p->rx_frames = GET_STAT(RX_PORT_FRAMES);
@@ -5674,6 +5683,12 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
p->rx_ppp6 = GET_STAT(RX_PORT_PPP6);
p->rx_ppp7 = GET_STAT(RX_PORT_PPP7);
+ if (stat_ctl & F_COUNTPAUSESTATRX) {
+ p->rx_frames -= p->rx_pause;
+ p->rx_octets -= p->rx_pause * 64;
+ p->rx_mcast_frames -= p->rx_pause;
+ }
+
p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
diff --git a/sys/dev/cxgbe/firmware/t4fw_cfg.txt b/sys/dev/cxgbe/firmware/t4fw_cfg.txt
index 0e13122..43820a0 100644
--- a/sys/dev/cxgbe/firmware/t4fw_cfg.txt
+++ b/sys/dev/cxgbe/firmware/t4fw_cfg.txt
@@ -10,7 +10,7 @@
[global]
rss_glb_config_mode = basicvirtual
- rss_glb_config_options = tnlmapen, hashtoeplitz, tnlalllkp
+ rss_glb_config_options = tnlmapen,hashtoeplitz,tnlalllkp
sge_timer_value = 1, 5, 10, 50, 100, 200 # usecs
@@ -20,61 +20,82 @@
# disable TP_PARA_REG3.RxFragEn
reg[0x7d6c] = 0x00000000/0x00007000
- # TP_SHIFT_CNT
- reg[0x7dc0] = 0x62f8849
+ reg[0x7dc0] = 0x0e2f8849 # TP_SHIFT_CNT
filterMode = fragmentation, mpshittype, protocol, vlan, port, fcoe
filterMask = protocol, fcoe
- # TP rx and tx channels (0 = auto).
+ tp_pmrx = 36, 512
+ tp_pmrx_pagesize = 64K
+
+ # TP number of RX channels (0 = auto)
tp_nrxch = 0
- tp_ntxch = 0
- # TP rx and tx payload memory (% of the total EDRAM + DDR3).
- tp_pmrx = 38, 512
- tp_pmtx = 60, 512
- tp_pmrx_pagesize = 64K
+ tp_pmtx = 46, 512
tp_pmtx_pagesize = 64K
- # cluster, lan, or wan.
- tp_tcptuning = lan
+ # TP number of TX channels (0 = auto)
+ tp_ntxch = 0
# TP OFLD MTUs
tp_mtus = 88, 256, 512, 576, 808, 1024, 1280, 1488, 1500, 2002, 2048, 4096, 4352, 8192, 9000, 9600
+ # cluster, lan, or wan.
+ tp_tcptuning = lan
+
# PFs 0-3. These get 8 MSI/8 MSI-X vectors each. VFs are supported by
-# these 4 PFs only. Not used here at all.
+# these 4 PFs only.
[function "0"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "0/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x1
[function "1"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "1/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x2
[function "2"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "2/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x4
[function "3"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "3/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x8
# PF4 is the resource-rich PF that the bus/nexus driver attaches to.
# It gets 32 MSI/128 MSI-X vectors.
@@ -86,15 +107,19 @@
niqflint = 512
nethctrl = 1024
neq = 2048
- nexactf = 328
+ nexactf = 280
cmask = all
pmask = all
# driver will mask off features it won't use
- protocol = ofld
+ protocol = ofld, rddp, rdmac, iscsi_initiator_pdu, iscsi_target_pdu
tp_l2t = 4096
tp_ddp = 2
+ tp_ddp_iscsi = 2
+ tp_stag = 2
+ tp_pbl = 5
+ tp_rq = 7
# TCAM has 8K cells; each region must start at a multiple of 128 cell.
# Each entry in these categories takes 4 cells each. nhash will use the
@@ -130,6 +155,60 @@
nexactf = 8
nfilter = 16
+# For Virtual functions, we only allow NIC functionality and we only allow
+# access to one port (1 << PF). Note that because of limitations in the
+# Scatter Gather Engine (SGE) hardware which checks writes to VF KDOORBELL
+# and GTS registers, the number of Ingress and Egress Queues must be a power
+# of 2.
+#
+[function "0/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x1
+
+[function "1/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x2
+
+[function "2/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x4
+
+[function "3/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x8
+
# MPS has 192K buffer space for ingress packets from the wire as well as
# loopback path of the L2 switch.
[port "0"]
@@ -166,7 +245,7 @@
[fini]
version = 0x1
- checksum = 0x98210e18
+ checksum = 0xbec0621
#
# $FreeBSD$
#
diff --git a/sys/dev/cxgbe/firmware/t5fw_cfg.txt b/sys/dev/cxgbe/firmware/t5fw_cfg.txt
index 4ae6c99..9e16da5 100644
--- a/sys/dev/cxgbe/firmware/t5fw_cfg.txt
+++ b/sys/dev/cxgbe/firmware/t5fw_cfg.txt
@@ -10,12 +10,33 @@
[global]
rss_glb_config_mode = basicvirtual
- rss_glb_config_options = tnlmapen, hashtoeplitz, tnlalllkp
+ rss_glb_config_options = tnlmapen,hashtoeplitz,tnlalllkp
# PL_TIMEOUT register
- pl_timeout_value = 200 # the timeout value in units of us
+ pl_timeout_value = 10000 # the timeout value in units of us
- sge_timer_value = 1, 5, 10, 50, 100, 200 # usecs
+ # SGE_THROTTLE_CONTROL
+ bar2throttlecount = 500 # bar2throttlecount in us
+
+ sge_timer_value = 1, 5, 10, 50, 100, 200 # SGE_TIMER_VALUE* in usecs
+
+ reg[0x1124] = 0x00000400/0x00000400 # SGE_CONTROL2, enable VFIFO; if
+ # SGE_VFIFO_SIZE is not set, then
+ # firmware will set it up in function
+ # of number of egress queues used
+
+ reg[0x1130] = 0x00d5ffeb # SGE_DBP_FETCH_THRESHOLD, fetch
+ # threshold set to queue depth
+ # minus 128-entries for FL and HP
+ # queues, and 0xfff for LP which
+ # prompts the firmware to set it up
+ # in function of egress queues
+ # used
+
+ reg[0x113c] = 0x0002ffc0 # SGE_VFIFO_SIZE, set to 0x2ffc0 which
+ # prompts the firmware to set it up in
+ # function of number of egress queues
+ # used
# enable TP_OUT_CONFIG.IPIDSPLITMODE
reg[0x7d04] = 0x00010000/0x00010000
@@ -26,34 +47,38 @@
# enable TP_PARA_REG6.EnableCSnd
reg[0x7d78] = 0x00000400/0x00000000
- # TP_SHIFT_CNT
- reg[0x7dc0] = 0x62f8849
-
- # TP_GLOBAL_CONFIG
- reg[0x7d08] = 0x00000800/0x00000800 # set IssFromCplEnable
-
- # TP_PARA_REG0
- reg[0x7d60] = 0x06000000/0x07000000 # set InitCWND to 6
+ reg[0x7dc0] = 0x0e2f8849 # TP_SHIFT_CNT
filterMode = fragmentation, mpshittype, protocol, vlan, port, fcoe
filterMask = protocol, fcoe
- # TP rx and tx channels (0 = auto).
+ tp_pmrx = 36, 512
+ tp_pmrx_pagesize = 64K
+
+ # TP number of RX channels (0 = auto)
tp_nrxch = 0
- tp_ntxch = 0
- # TP rx and tx payload memory (% of the total EDRAM + DDR3).
- tp_pmrx = 38, 512
- tp_pmtx = 60, 512
- tp_pmrx_pagesize = 64K
+ tp_pmtx = 46, 512
tp_pmtx_pagesize = 64K
- # cluster, lan, or wan.
- tp_tcptuning = lan
+ # TP number of TX channels (0 = auto)
+ tp_ntxch = 0
# TP OFLD MTUs
tp_mtus = 88, 256, 512, 576, 808, 1024, 1280, 1488, 1500, 2002, 2048, 4096, 4352, 8192, 9000, 9600
+ # TP_GLOBAL_CONFIG
+ reg[0x7d08] = 0x00000800/0x00000800 # set IssFromCplEnable
+
+ # TP_PC_CONFIG
+ reg[0x7d48] = 0x00000000/0x00000400 # clear EnableFLMError
+
+ # TP_PARA_REG0
+ reg[0x7d60] = 0x06000000/0x07000000 # set InitCWND to 6
+
+ # cluster, lan, or wan.
+ tp_tcptuning = lan
+
# MC configuration
mc_mode_brc[0] = 1 # mc0 - 1: enable BRC, 0: enable RBC
mc_mode_brc[1] = 1 # mc1 - 1: enable BRC, 0: enable RBC
@@ -63,38 +88,58 @@
# TPT error.
# PFs 0-3. These get 8 MSI/8 MSI-X vectors each. VFs are supported by
-# these 4 PFs only. Not used here at all.
+# these 4 PFs only.
[function "0"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "0/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x1
[function "1"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "1/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x2
[function "2"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "2/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x4
[function "3"]
- nvf = 16
- nvi = 1
- rssnvi = 0
-[function "3/*"]
- nvi = 1
- rssnvi = 0
+ nvf = 4
+ wx_caps = all
+ r_caps = all
+ nvi = 2
+ rssnvi = 2
+ niqflint = 4
+ nethctrl = 4
+ neq = 8
+ nexactf = 4
+ cmask = all
+ pmask = 0x8
# PF4 is the resource-rich PF that the bus/nexus driver attaches to.
# It gets 32 MSI/128 MSI-X vectors.
@@ -106,15 +151,19 @@
niqflint = 512
nethctrl = 1024
neq = 2048
- nexactf = 328
+ nexactf = 456
cmask = all
pmask = all
# driver will mask off features it won't use
- protocol = ofld
+ protocol = ofld, rddp, rdmac, iscsi_initiator_pdu, iscsi_target_pdu, iscsi_t10dif
tp_l2t = 4096
tp_ddp = 2
+ tp_ddp_iscsi = 2
+ tp_stag = 2
+ tp_pbl = 5
+ tp_rq = 7
# TCAM has 8K cells; each region must start at a multiple of 128 cell.
# Each entry in these categories takes 4 cells each. nhash will use the
@@ -150,6 +199,60 @@
nexactf = 8
nfilter = 16
+# For Virtual functions, we only allow NIC functionality and we only allow
+# access to one port (1 << PF). Note that because of limitations in the
+# Scatter Gather Engine (SGE) hardware which checks writes to VF KDOORBELL
+# and GTS registers, the number of Ingress and Egress Queues must be a power
+# of 2.
+#
+[function "0/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x1
+
+[function "1/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x2
+
+[function "2/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x4
+
+[function "3/*"]
+ wx_caps = 0x82
+ r_caps = 0x86
+ nvi = 1
+ rssnvi = 1
+ niqflint = 2
+ nethctrl = 2
+ neq = 4
+ nexactf = 2
+ cmask = all
+ pmask = 0x8
+
# MPS has 192K buffer space for ingress packets from the wire as well as
# loopback path of the L2 switch.
[port "0"]
@@ -186,7 +289,7 @@
[fini]
version = 0x1
- checksum = 0x7044b7fd
+ checksum = 0x2d7417e5
#
# $FreeBSD$
#
diff --git a/sys/dev/cxgbe/iw_cxgbe/cm.c b/sys/dev/cxgbe/iw_cxgbe/cm.c
index c884f5a..c2b72fa 100644
--- a/sys/dev/cxgbe/iw_cxgbe/cm.c
+++ b/sys/dev/cxgbe/iw_cxgbe/cm.c
@@ -80,7 +80,7 @@ static spinlock_t timeout_lock;
static void process_req(struct work_struct *ctx);
static void start_ep_timer(struct c4iw_ep *ep);
-static void stop_ep_timer(struct c4iw_ep *ep);
+static int stop_ep_timer(struct c4iw_ep *ep);
static int set_tcpinfo(struct c4iw_ep *ep);
static enum c4iw_ep_state state_read(struct c4iw_ep_common *epc);
static void __state_set(struct c4iw_ep_common *epc, enum c4iw_ep_state tostate);
@@ -96,14 +96,14 @@ static void send_mpa_req(struct c4iw_ep *ep);
static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen);
static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen);
static void close_complete_upcall(struct c4iw_ep *ep, int status);
-static int abort_connection(struct c4iw_ep *ep);
+static int send_abort(struct c4iw_ep *ep);
static void peer_close_upcall(struct c4iw_ep *ep);
static void peer_abort_upcall(struct c4iw_ep *ep);
static void connect_reply_upcall(struct c4iw_ep *ep, int status);
static int connect_request_upcall(struct c4iw_ep *ep);
static void established_upcall(struct c4iw_ep *ep);
-static void process_mpa_reply(struct c4iw_ep *ep);
-static void process_mpa_request(struct c4iw_ep *ep);
+static int process_mpa_reply(struct c4iw_ep *ep);
+static int process_mpa_request(struct c4iw_ep *ep);
static void process_peer_close(struct c4iw_ep *ep);
static void process_conn_error(struct c4iw_ep *ep);
static void process_close_complete(struct c4iw_ep *ep);
@@ -123,11 +123,11 @@ static void release_ep_resources(struct c4iw_ep *ep);
} while (0)
#define STOP_EP_TIMER(ep) \
- do { \
+ ({ \
CTR3(KTR_IW_CXGBE, "stop_ep_timer (%s:%d) ep %p", \
__func__, __LINE__, (ep)); \
stop_ep_timer(ep); \
- } while (0)
+ })
#ifdef KTR
static char *states[] = {
@@ -147,6 +147,34 @@ static char *states[] = {
};
#endif
+
+static void deref_cm_id(struct c4iw_ep_common *epc)
+{
+ epc->cm_id->rem_ref(epc->cm_id);
+ epc->cm_id = NULL;
+ set_bit(CM_ID_DEREFED, &epc->history);
+}
+
+static void ref_cm_id(struct c4iw_ep_common *epc)
+{
+ set_bit(CM_ID_REFED, &epc->history);
+ epc->cm_id->add_ref(epc->cm_id);
+}
+
+static void deref_qp(struct c4iw_ep *ep)
+{
+ c4iw_qp_rem_ref(&ep->com.qp->ibqp);
+ clear_bit(QP_REFERENCED, &ep->com.flags);
+ set_bit(QP_DEREFED, &ep->com.history);
+}
+
+static void ref_qp(struct c4iw_ep *ep)
+{
+ set_bit(QP_REFERENCED, &ep->com.flags);
+ set_bit(QP_REFED, &ep->com.history);
+ c4iw_qp_add_ref(&ep->com.qp->ibqp);
+}
+
static void
process_req(struct work_struct *ctx)
{
@@ -304,9 +332,7 @@ process_peer_close(struct c4iw_ep *ep)
disconnect = 0;
STOP_EP_TIMER(ep);
close_socket(&ep->com, 0);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
release = 1;
break;
@@ -490,6 +516,7 @@ process_close_complete(struct c4iw_ep *ep)
/* The cm_id may be null if we failed to connect */
mutex_lock(&ep->com.mutex);
+ set_bit(CLOSE_CON_RPL, &ep->com.history);
switch (ep->com.state) {
@@ -580,13 +607,14 @@ static void
process_data(struct c4iw_ep *ep)
{
struct sockaddr_in *local, *remote;
+ int disconnect = 0;
CTR5(KTR_IW_CXGBE, "%s: so %p, ep %p, state %s, sbused %d", __func__,
ep->com.so, ep, states[ep->com.state], sbused(&ep->com.so->so_rcv));
switch (state_read(&ep->com)) {
case MPA_REQ_SENT:
- process_mpa_reply(ep);
+ disconnect = process_mpa_reply(ep);
break;
case MPA_REQ_WAIT:
in_getsockaddr(ep->com.so, (struct sockaddr **)&local);
@@ -595,7 +623,7 @@ process_data(struct c4iw_ep *ep)
ep->com.remote_addr = *remote;
free(local, M_SONAME);
free(remote, M_SONAME);
- process_mpa_request(ep);
+ disconnect = process_mpa_request(ep);
break;
default:
if (sbused(&ep->com.so->so_rcv))
@@ -605,6 +633,9 @@ process_data(struct c4iw_ep *ep)
ep->com.so->so_state, sbused(&ep->com.so->so_rcv));
break;
}
+ if (disconnect)
+ c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
+
}
static void
@@ -749,9 +780,9 @@ int db_delay_usecs = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, db_delay_usecs, CTLFLAG_RWTUN, &db_delay_usecs, 0,
"Usecs to delay awaiting db fifo to drain");
-static int dack_mode = 1;
+static int dack_mode = 0;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, dack_mode, CTLFLAG_RWTUN, &dack_mode, 0,
- "Delayed ack mode (default = 1)");
+ "Delayed ack mode (default = 0)");
int c4iw_max_read_depth = 8;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_max_read_depth, CTLFLAG_RWTUN, &c4iw_max_read_depth, 0,
@@ -773,9 +804,9 @@ int c4iw_debug = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, c4iw_debug, CTLFLAG_RWTUN, &c4iw_debug, 0,
"Enable debug logging (default = 0)");
-static int peer2peer;
+static int peer2peer = 1;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, peer2peer, CTLFLAG_RWTUN, &peer2peer, 0,
- "Support peer2peer ULPs (default = 0)");
+ "Support peer2peer ULPs (default = 1)");
static int p2p_type = FW_RI_INIT_P2PTYPE_READ_REQ;
SYSCTL_INT(_hw_iw_cxgbe, OID_AUTO, p2p_type, CTLFLAG_RWTUN, &p2p_type, 0,
@@ -827,14 +858,16 @@ start_ep_timer(struct c4iw_ep *ep)
add_timer(&ep->timer);
}
-static void
+static int
stop_ep_timer(struct c4iw_ep *ep)
{
del_timer_sync(&ep->timer);
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
c4iw_put_ep(&ep->com);
+ return 0;
}
+ return 1;
}
static enum
@@ -900,6 +933,8 @@ void _c4iw_free_ep(struct kref *kref)
epc = &ep->com;
KASSERT(!epc->entry.tqe_prev, ("%s epc %p still on req list",
__func__, epc));
+ if (test_bit(QP_REFERENCED, &ep->com.flags))
+ deref_qp(ep);
kfree(ep);
}
@@ -1175,20 +1210,17 @@ static void close_complete_upcall(struct c4iw_ep *ep, int status)
CTR2(KTR_IW_CXGBE, "%s:ccu1 %1", __func__, ep);
ep->com.cm_id->event_handler(ep->com.cm_id, &event);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
set_bit(CLOSE_UPCALL, &ep->com.history);
}
CTR2(KTR_IW_CXGBE, "%s:ccuE %p", __func__, ep);
}
-static int abort_connection(struct c4iw_ep *ep)
+static int send_abort(struct c4iw_ep *ep)
{
int err;
CTR2(KTR_IW_CXGBE, "%s:abB %p", __func__, ep);
- state_set(&ep->com, ABORTING);
abort_socket(ep);
err = close_socket(&ep->com, 0);
set_bit(ABORT_CONN, &ep->com.history);
@@ -1226,9 +1258,7 @@ static void peer_abort_upcall(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pau1 %p", __func__, ep);
ep->com.cm_id->event_handler(ep->com.cm_id, &event);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
set_bit(ABORT_UPCALL, &ep->com.history);
}
CTR2(KTR_IW_CXGBE, "%s:pauE %p", __func__, ep);
@@ -1282,9 +1312,7 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
if (status < 0) {
CTR3(KTR_IW_CXGBE, "%s:cru4 %p %d", __func__, ep, status);
- ep->com.cm_id->rem_ref(ep->com.cm_id);
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
+ deref_cm_id(&ep->com);
}
CTR2(KTR_IW_CXGBE, "%s:cruE %p", __func__, ep);
@@ -1353,8 +1381,19 @@ static void established_upcall(struct c4iw_ep *ep)
}
-
-static void process_mpa_reply(struct c4iw_ep *ep)
+/*
+ * process_mpa_reply - process streaming mode MPA reply
+ *
+ * Returns:
+ *
+ * 0 upon success indicating a connect request was delivered to the ULP
+ * or the mpa request is incomplete but valid so far.
+ *
+ * 1 if a failure requires the caller to close the connection.
+ *
+ * 2 if a failure requires the caller to abort the connection.
+ */
+static int process_mpa_reply(struct c4iw_ep *ep)
{
struct mpa_message *mpa;
struct mpa_v2_conn_params *mpa_v2_params;
@@ -1367,17 +1406,17 @@ static void process_mpa_reply(struct c4iw_ep *ep)
struct mbuf *top, *m;
int flags = MSG_DONTWAIT;
struct uio uio;
+ int disconnect = 0;
CTR2(KTR_IW_CXGBE, "%s:pmrB %p", __func__, ep);
/*
- * Stop mpa timer. If it expired, then the state has
- * changed and we bail since ep_timeout already aborted
- * the connection.
+ * Stop mpa timer. If it expired, then
+ * we ignore the MPA reply. process_timeout()
+ * will abort the connection.
*/
- STOP_EP_TIMER(ep);
- if (state_read(&ep->com) != MPA_REQ_SENT)
- return;
+ if (STOP_EP_TIMER(ep))
+ return 0;
uio.uio_resid = 1000000;
uio.uio_td = ep->com.thread;
@@ -1389,7 +1428,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pmr1 %p", __func__, ep);
START_EP_TIMER(ep);
- return;
+ return 0;
}
err = -err;
CTR2(KTR_IW_CXGBE, "%s:pmr2 %p", __func__, ep);
@@ -1417,7 +1456,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR3(KTR_IW_CXGBE, "%s:pmr5 %p %d", __func__, ep,
ep->mpa_pkt_len + m->m_len);
err = (-EINVAL);
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1435,8 +1474,9 @@ static void process_mpa_reply(struct c4iw_ep *ep)
/*
* if we don't even have the mpa message, then bail.
*/
- if (ep->mpa_pkt_len < sizeof(*mpa))
- return;
+ if (ep->mpa_pkt_len < sizeof(*mpa)) {
+ return 0;
+ }
mpa = (struct mpa_message *) ep->mpa_pkt;
/* Validate MPA header. */
@@ -1447,14 +1487,14 @@ static void process_mpa_reply(struct c4iw_ep *ep)
printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d, "
" Received = %d\n", __func__, mpa_rev, mpa->revision);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
if (memcmp(mpa->key, MPA_KEY_REP, sizeof(mpa->key))) {
CTR2(KTR_IW_CXGBE, "%s:pmr7 %p", __func__, ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
plen = ntohs(mpa->private_data_size);
@@ -1466,7 +1506,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
CTR2(KTR_IW_CXGBE, "%s:pmr8 %p", __func__, ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1475,8 +1515,9 @@ static void process_mpa_reply(struct c4iw_ep *ep)
if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) {
CTR2(KTR_IW_CXGBE, "%s:pmr9 %p", __func__, ep);
+ STOP_EP_TIMER(ep);
err = -EPROTO;
- goto err;
+ goto err_stop_timer;
}
ep->plen = (u8) plen;
@@ -1488,14 +1529,14 @@ static void process_mpa_reply(struct c4iw_ep *ep)
if (ep->mpa_pkt_len < (sizeof(*mpa) + plen)) {
CTR2(KTR_IW_CXGBE, "%s:pmra %p", __func__, ep);
- return;
+ return 0;
}
if (mpa->flags & MPA_REJECT) {
CTR2(KTR_IW_CXGBE, "%s:pmrb %p", __func__, ep);
err = -ECONNREFUSED;
- goto err;
+ goto err_stop_timer;
}
/*
@@ -1638,6 +1679,7 @@ static void process_mpa_reply(struct c4iw_ep *ep)
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
err = -ENOMEM;
+ disconnect = 1;
goto out;
}
@@ -1658,19 +1700,33 @@ static void process_mpa_reply(struct c4iw_ep *ep)
err = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
err = -ENOMEM;
+ disconnect = 1;
goto out;
}
goto out;
+err_stop_timer:
+ STOP_EP_TIMER(ep);
err:
- state_set(&ep->com, ABORTING);
- abort_connection(ep);
+ disconnect = 2;
out:
connect_reply_upcall(ep, err);
CTR2(KTR_IW_CXGBE, "%s:pmrE %p", __func__, ep);
- return;
+ return disconnect;
}
-static void
+/*
+ * process_mpa_request - process streaming mode MPA request
+ *
+ * Returns:
+ *
+ * 0 upon success indicating a connect request was delivered to the ULP
+ * or the mpa request is incomplete but valid so far.
+ *
+ * 1 if a failure requires the caller to close the connection.
+ *
+ * 2 if a failure requires the caller to abort the connection.
+ */
+static int
process_mpa_request(struct c4iw_ep *ep)
{
struct mpa_message *mpa;
@@ -1684,7 +1740,7 @@ process_mpa_request(struct c4iw_ep *ep)
CTR3(KTR_IW_CXGBE, "%s: ep %p, state %s", __func__, ep, states[state]);
if (state != MPA_REQ_WAIT)
- return;
+ return 0;
iov.iov_base = &ep->mpa_pkt[ep->mpa_pkt_len];
iov.iov_len = sizeof(ep->mpa_pkt) - ep->mpa_pkt_len;
@@ -1698,13 +1754,10 @@ process_mpa_request(struct c4iw_ep *ep)
rc = soreceive(ep->com.so, NULL, &uio, NULL, NULL, &flags);
if (rc == EAGAIN)
- return;
- else if (rc) {
-abort:
- STOP_EP_TIMER(ep);
- abort_connection(ep);
- return;
- }
+ return 0;
+ else if (rc)
+ goto err_stop_timer;
+
KASSERT(uio.uio_offset > 0, ("%s: sorecieve on so %p read no data",
__func__, ep->com.so));
ep->mpa_pkt_len += uio.uio_offset;
@@ -1718,7 +1771,7 @@ abort:
/* Don't even have the MPA message. Wait for more data to arrive. */
if (ep->mpa_pkt_len < sizeof(*mpa))
- return;
+ return 0;
mpa = (struct mpa_message *) ep->mpa_pkt;
/*
@@ -1727,24 +1780,24 @@ abort:
if (mpa->revision > mpa_rev) {
log(LOG_ERR, "%s: MPA version mismatch. Local = %d,"
" Received = %d\n", __func__, mpa_rev, mpa->revision);
- goto abort;
+ goto err_stop_timer;
}
if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key)))
- goto abort;
+ goto err_stop_timer;
/*
* Fail if there's too much private data.
*/
plen = ntohs(mpa->private_data_size);
if (plen > MPA_MAX_PRIVATE_DATA)
- goto abort;
+ goto err_stop_timer;
/*
* If plen does not account for pkt size
*/
if (ep->mpa_pkt_len > (sizeof(*mpa) + plen))
- goto abort;
+ goto err_stop_timer;
ep->plen = (u8) plen;
@@ -1752,7 +1805,7 @@ abort:
* If we don't have all the pdata yet, then bail.
*/
if (ep->mpa_pkt_len < (sizeof(*mpa) + plen))
- return;
+ return 0;
/*
* If we get here we have accumulated the entire mpa
@@ -1794,7 +1847,7 @@ abort:
ep->mpa_attr.p2p_type = p2p_type;
if (set_tcpinfo(ep))
- goto abort;
+ goto err_stop_timer;
CTR5(KTR_IW_CXGBE, "%s: crc_enabled = %d, recv_marker_enabled = %d, "
"xmit_marker_enabled = %d, version = %d", __func__,
@@ -1807,12 +1860,18 @@ abort:
/* drive upcall */
mutex_lock(&ep->parent_ep->com.mutex);
if (ep->parent_ep->com.state != DEAD) {
- if(connect_request_upcall(ep)) {
- abort_connection(ep);
- }
- }else
- abort_connection(ep);
+ if(connect_request_upcall(ep))
+ goto err_out;
+ }else {
+ goto err_out;
+ }
mutex_unlock(&ep->parent_ep->com.mutex);
+ return 0;
+
+err_stop_timer:
+ STOP_EP_TIMER(ep);
+err_out:
+ return 2;
}
/*
@@ -1825,6 +1884,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
int err;
struct c4iw_ep *ep = to_ep(cm_id);
CTR2(KTR_IW_CXGBE, "%s:crcB %p", __func__, ep);
+ int disconnect = 0;
if (state_read(&ep->com) == DEAD) {
@@ -1838,7 +1898,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
if (mpa_rev == 0) {
CTR2(KTR_IW_CXGBE, "%s:crc2 %p", __func__, ep);
- abort_connection(ep);
+ disconnect = 2;
}
else {
@@ -1847,6 +1907,8 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
err = soshutdown(ep->com.so, 3);
}
c4iw_put_ep(&ep->com);
+ if (disconnect)
+ err = c4iw_ep_disconnect(ep, disconnect == 2, GFP_KERNEL);
CTR2(KTR_IW_CXGBE, "%s:crc4 %p", __func__, ep);
return 0;
}
@@ -1859,6 +1921,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct c4iw_ep *ep = to_ep(cm_id);
struct c4iw_dev *h = to_c4iw_dev(cm_id->device);
struct c4iw_qp *qp = get_qhp(h, conn_param->qpn);
+ int abort = 0;
CTR2(KTR_IW_CXGBE, "%s:cacB %p", __func__, ep);
@@ -1866,7 +1929,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
CTR2(KTR_IW_CXGBE, "%s:cac1 %p", __func__, ep);
err = -ECONNRESET;
- goto err;
+ goto err_out;
}
BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
@@ -1878,9 +1941,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
(conn_param->ird > c4iw_max_read_depth)) {
CTR2(KTR_IW_CXGBE, "%s:cac2 %p", __func__, ep);
- abort_connection(ep);
err = -EINVAL;
- goto err;
+ goto err_abort;
}
if (ep->mpa_attr.version == 2 && ep->mpa_attr.enhanced_rdma_conn) {
@@ -1894,9 +1956,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->ord = conn_param->ord;
send_mpa_reject(ep, conn_param->private_data,
conn_param->private_data_len);
- abort_connection(ep);
err = -ENOMEM;
- goto err;
+ goto err_abort;
}
if (conn_param->ird > ep->ord) {
@@ -1910,9 +1971,8 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
}
else {
CTR2(KTR_IW_CXGBE, "%s:cac7 %p", __func__, ep);
- abort_connection(ep);
err = -ENOMEM;
- goto err;
+ goto err_abort;
}
}
@@ -1932,9 +1992,10 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
}
- cm_id->add_ref(cm_id);
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.qp = qp;
+ ref_qp(ep);
//ep->ofld_txq = TOEPCB(ep->com.so)->ofld_txq;
/* bind QP to EP and move to RTS */
@@ -1956,7 +2017,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err) {
CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep);
- goto err1;
+ goto err_defef_cm_id;
}
err = send_mpa_reply(ep, conn_param->private_data,
conn_param->private_data_len);
@@ -1964,7 +2025,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
if (err) {
CTR2(KTR_IW_CXGBE, "%s:caca %p", __func__, ep);
- goto err1;
+ goto err_defef_cm_id;
}
state_set(&ep->com, FPDU_MODE);
@@ -1972,11 +2033,13 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
c4iw_put_ep(&ep->com);
CTR2(KTR_IW_CXGBE, "%s:cacE %p", __func__, ep);
return 0;
-err1:
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
- cm_id->rem_ref(cm_id);
-err:
+err_defef_cm_id:
+ deref_cm_id(&ep->com);
+err_abort:
+ abort = 1;
+err_out:
+ if (abort)
+ c4iw_ep_disconnect(ep, 1, GFP_KERNEL);
c4iw_put_ep(&ep->com);
CTR2(KTR_IW_CXGBE, "%s:cacE err %p", __func__, ep);
return err;
@@ -2028,9 +2091,9 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->ord = 1;
}
- cm_id->add_ref(cm_id);
ep->com.dev = dev;
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.qp = get_qhp(dev, conn_param->qpn);
if (!ep->com.qp) {
@@ -2039,6 +2102,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
err = -EINVAL;
goto fail2;
}
+ ref_qp(ep);
ep->com.thread = curthread;
ep->com.so = cm_id->so;
@@ -2096,7 +2160,7 @@ fail3:
CTR2(KTR_IW_CXGBE, "%s:ccb %p", __func__, ep);
fib4_free_nh_ext(RT_DEFAULT_FIB, &nh4);
fail2:
- cm_id->rem_ref(cm_id);
+ deref_cm_id(&ep->com);
c4iw_put_ep(&ep->com);
out:
CTR2(KTR_IW_CXGBE, "%s:ccE %p", __func__, ep);
@@ -2124,8 +2188,8 @@ c4iw_create_listen_ep(struct iw_cm_id *cm_id, int backlog)
goto failed;
}
- cm_id->add_ref(cm_id);
ep->com.cm_id = cm_id;
+ ref_cm_id(&ep->com);
ep->com.dev = dev;
ep->backlog = backlog;
ep->com.local_addr = cm_id->local_addr;
@@ -2150,7 +2214,7 @@ c4iw_destroy_listen_ep(struct iw_cm_id *cm_id)
cm_id->so, states[ep->com.state]);
state_set(&ep->com, DEAD);
- cm_id->rem_ref(cm_id);
+ deref_cm_id(&ep->com);
c4iw_put_ep(&ep->com);
return;
@@ -2232,7 +2296,8 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
CTR2(KTR_IW_CXGBE, "%s:ced4 %p", __func__, ep);
set_bit(EP_DISC_ABORT, &ep->com.history);
- ret = abort_connection(ep);
+ close_complete_upcall(ep, -ECONNRESET);
+ ret = send_abort(ep);
} else {
CTR2(KTR_IW_CXGBE, "%s:ced5 %p", __func__, ep);
@@ -2250,8 +2315,25 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
}
if (fatal) {
+ set_bit(EP_DISC_FAIL, &ep->com.history);
+ if (!abrupt) {
+ STOP_EP_TIMER(ep);
+ close_complete_upcall(ep, -EIO);
+ }
+ if (ep->com.qp) {
+ struct c4iw_qp_attributes attrs;
+ attrs.next_state = C4IW_QP_STATE_ERROR;
+ ret = c4iw_modify_qp(ep->com.dev, ep->com.qp,
+ C4IW_QP_ATTR_NEXT_STATE,
+ &attrs, 1);
+ if (ret) {
+ CTR2(KTR_IW_CXGBE, "%s:ced7 %p", __func__, ep);
+ printf("%s - qp <- error failed!\n", __func__);
+ }
+ }
release_ep_resources(ep);
+ ep->com.state = DEAD;
CTR2(KTR_IW_CXGBE, "%s:ced6 %p", __func__, ep);
}
CTR2(KTR_IW_CXGBE, "%s:cedE %p", __func__, ep);
@@ -2290,8 +2372,13 @@ static void ep_timeout(unsigned long arg)
if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) {
- list_add_tail(&ep->entry, &timeout_list);
- kickit = 1;
+ /*
+ * Only insert if it is not already on the list.
+ */
+ if (!ep->entry.next) {
+ list_add_tail(&ep->entry, &timeout_list);
+ kickit = 1;
+ }
}
spin_unlock(&timeout_lock);
diff --git a/sys/dev/cxgbe/iw_cxgbe/cq.c b/sys/dev/cxgbe/iw_cxgbe/cq.c
index 8710e03..b40ffc7 100644
--- a/sys/dev/cxgbe/iw_cxgbe/cq.c
+++ b/sys/dev/cxgbe/iw_cxgbe/cq.c
@@ -724,7 +724,7 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
default:
printf("Unexpected cqe_status 0x%x for QPID = 0x%0x\n",
CQE_STATUS(&cqe), CQE_QPID(&cqe));
- ret = -EINVAL;
+ wc->status = IB_WC_FATAL_ERR;
}
}
out:
@@ -861,6 +861,7 @@ c4iw_create_cq(struct ib_device *ibdev, struct ib_cq_init_attr *attr,
if (!mm2)
goto err4;
+ memset(&uresp, 0, sizeof(uresp));
uresp.qid_mask = rhp->rdev.cqmask;
uresp.cqid = chp->cq.cqid;
uresp.size = chp->cq.size;
@@ -871,7 +872,8 @@ c4iw_create_cq(struct ib_device *ibdev, struct ib_cq_init_attr *attr,
uresp.gts_key = ucontext->key;
ucontext->key += PAGE_SIZE;
spin_unlock(&ucontext->mmap_lock);
- ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+ ret = ib_copy_to_udata(udata, &uresp,
+ sizeof(uresp) - sizeof(uresp.reserved));
if (ret)
goto err5;
diff --git a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
index c232f70..38a8af6 100644
--- a/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
+++ b/sys/dev/cxgbe/iw_cxgbe/iw_cxgbe.h
@@ -157,7 +157,7 @@ static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
{
- return min((int)T4_MAX_NUM_STAG, (int)(rdev->adap->vres.stag.size >> 5));
+ return (int)(rdev->adap->vres.stag.size >> 5);
}
#define C4IW_WR_TO (10*HZ)
@@ -435,6 +435,7 @@ struct c4iw_qp {
atomic_t refcnt;
wait_queue_head_t wait;
struct timer_list timer;
+ int sq_sig_all;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
@@ -712,7 +713,8 @@ enum c4iw_ep_flags {
ABORT_REQ_IN_PROGRESS = 1,
RELEASE_RESOURCES = 2,
CLOSE_SENT = 3,
- TIMEOUT = 4
+ TIMEOUT = 4,
+ QP_REFERENCED = 5
};
enum c4iw_ep_history {
@@ -737,7 +739,13 @@ enum c4iw_ep_history {
EP_DISC_ABORT = 18,
CONN_RPL_UPCALL = 19,
ACT_RETRY_NOMEM = 20,
- ACT_RETRY_INUSE = 21
+ ACT_RETRY_INUSE = 21,
+ CLOSE_CON_RPL = 22,
+ EP_DISC_FAIL = 24,
+ QP_REFED = 25,
+ QP_DEREFED = 26,
+ CM_ID_REFED = 27,
+ CM_ID_DEREFED = 28
};
struct c4iw_ep_common {
diff --git a/sys/dev/cxgbe/iw_cxgbe/mem.c b/sys/dev/cxgbe/iw_cxgbe/mem.c
index f7c460a..e42aa1a 100644
--- a/sys/dev/cxgbe/iw_cxgbe/mem.c
+++ b/sys/dev/cxgbe/iw_cxgbe/mem.c
@@ -46,6 +46,12 @@ __FBSDID("$FreeBSD$");
#define T4_ULPTX_MIN_IO 32
#define C4IW_MAX_INLINE_SIZE 96
+static int mr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
+{
+ return (is_t4(dev->rdev.adap) ||
+ is_t5(dev->rdev.adap)) &&
+ length >= 8*1024*1024*1024ULL;
+}
static int
write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
{
@@ -144,8 +150,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
- if (!stag_idx)
+ if (!stag_idx) {
+ mutex_lock(&rdev->stats.lock);
+ rdev->stats.stag.fail++;
+ mutex_unlock(&rdev->stats.lock);
return -ENOMEM;
+ }
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur += 32;
if (rdev->stats.stag.cur > rdev->stats.stag.max)
@@ -250,9 +260,9 @@ static int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
int ret;
ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, mhp->attr.pdid,
- FW_RI_STAG_NSMR, mhp->attr.perms,
+ FW_RI_STAG_NSMR, mhp->attr.len ? mhp->attr.perms : 0,
mhp->attr.mw_bind_enable, mhp->attr.zbva,
- mhp->attr.va_fbo, mhp->attr.len, shift - 12,
+ mhp->attr.va_fbo, mhp->attr.len ? mhp->attr.len : -1, shift - 12,
mhp->attr.pbl_size, mhp->attr.pbl_addr);
if (ret)
return ret;
@@ -381,7 +391,7 @@ int c4iw_reregister_phys_mem(struct ib_mr *mr, int mr_rereg_mask,
struct c4iw_dev *rhp;
__be64 *page_list = NULL;
int shift = 0;
- u64 total_size;
+ u64 total_size = 0;
int npages = 0;
int ret;
@@ -416,7 +426,10 @@ int c4iw_reregister_phys_mem(struct ib_mr *mr, int mr_rereg_mask,
if (ret)
return ret;
}
-
+ if (mr_exceeds_hw_limits(rhp, total_size)) {
+ kfree(page_list);
+ return -EINVAL;
+ }
ret = reregister_mem(rhp, php, &mh, shift, npages);
kfree(page_list);
if (ret)
@@ -477,10 +490,15 @@ struct ib_mr *c4iw_register_phys_mem(struct ib_pd *pd,
if (ret)
goto err;
+ if (mr_exceeds_hw_limits(rhp, total_size)) {
+ kfree(page_list);
+ ret = -EINVAL;
+ goto err;
+ }
ret = alloc_pbl(mhp, npages);
if (ret) {
kfree(page_list);
- goto err_pbl;
+ goto err;
}
ret = write_pbl(&mhp->rhp->rdev, page_list, mhp->attr.pbl_addr,
@@ -580,6 +598,10 @@ struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
php = to_c4iw_pd(pd);
rhp = php->rhp;
+
+ if (mr_exceeds_hw_limits(rhp, length))
+ return ERR_PTR(-EINVAL);
+
mhp = kzalloc(sizeof(*mhp), GFP_KERNEL);
if (!mhp)
return ERR_PTR(-ENOMEM);
diff --git a/sys/dev/cxgbe/iw_cxgbe/qp.c b/sys/dev/cxgbe/iw_cxgbe/qp.c
index 1c0381c..3ee16b1 100644
--- a/sys/dev/cxgbe/iw_cxgbe/qp.c
+++ b/sys/dev/cxgbe/iw_cxgbe/qp.c
@@ -615,7 +615,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
fw_flags = 0;
if (wr->send_flags & IB_SEND_SOLICITED)
fw_flags |= FW_RI_SOLICITED_EVENT_FLAG;
- if (wr->send_flags & IB_SEND_SIGNALED)
+ if (wr->send_flags & IB_SEND_SIGNALED || qhp->sq_sig_all)
fw_flags |= FW_RI_COMPLETION_FLAG;
swsqe = &qhp->wq.sq.sw_sq[qhp->wq.sq.pidx];
switch (wr->opcode) {
@@ -673,7 +673,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
swsqe->idx = qhp->wq.sq.pidx;
swsqe->complete = 0;
- swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED);
+ swsqe->signaled = (wr->send_flags & IB_SEND_SIGNALED) ||
+ qhp->sq_sig_all;
swsqe->wr_id = wr->wr_id;
init_wr_hdr(wqe, qhp->wq.sq.pidx, fw_opcode, fw_flags, len16);
@@ -952,7 +953,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&rchp->lock, flag);
- if (flushed) {
+ if (flushed && rchp->ibcq.comp_handler) {
spin_lock_irqsave(&rchp->comp_handler_lock, flag);
(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
@@ -966,7 +967,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
flushed = c4iw_flush_sq(&qhp->wq, &schp->cq, count);
spin_unlock(&qhp->lock);
spin_unlock_irqrestore(&schp->lock, flag);
- if (flushed) {
+ if (flushed && schp->ibcq.comp_handler) {
spin_lock_irqsave(&schp->comp_handler_lock, flag);
(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);
spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
@@ -1530,6 +1531,7 @@ c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
qhp->attr.enable_bind = 1;
qhp->attr.max_ord = 1;
qhp->attr.max_ird = 1;
+ qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR;
spin_lock_init(&qhp->lock);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
@@ -1702,6 +1704,12 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
memset(attr, 0, sizeof *attr);
memset(init_attr, 0, sizeof *init_attr);
attr->qp_state = to_ib_qp_state(qhp->attr.state);
+ init_attr->cap.max_send_wr = qhp->attr.sq_num_entries;
+ init_attr->cap.max_recv_wr = qhp->attr.rq_num_entries;
+ init_attr->cap.max_send_sge = qhp->attr.sq_max_sges;
+ init_attr->cap.max_recv_sge = qhp->attr.sq_max_sges;
+ init_attr->cap.max_inline_data = T4_MAX_SEND_INLINE;
+ init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
return 0;
}
#endif
diff --git a/sys/dev/cxgbe/iw_cxgbe/t4.h b/sys/dev/cxgbe/iw_cxgbe/t4.h
index 023c607..b0118f9 100644
--- a/sys/dev/cxgbe/iw_cxgbe/t4.h
+++ b/sys/dev/cxgbe/iw_cxgbe/t4.h
@@ -69,7 +69,6 @@
#define T4_MAX_SQ_SIZE (T4_MAX_EQ_SIZE - 1)
#define T4_MAX_QP_DEPTH (T4_MAX_RQ_SIZE - 1)
#define T4_MAX_CQ_DEPTH (T4_MAX_IQ_SIZE - 1)
-#define T4_MAX_NUM_STAG (1<<15)
#define T4_MAX_MR_SIZE (~0ULL - 1)
#define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
#define T4_STAG_UNSET 0xffffffff
@@ -524,7 +523,7 @@ static inline void t4_swcq_consume(struct t4_cq *cq)
static inline void t4_hwcq_consume(struct t4_cq *cq)
{
cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts;
- if (++cq->cidx_inc == (cq->size >> 4)) {
+ if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == M_CIDXINC) {
u32 val;
val = SEINTARM(0) | CIDXINC(cq->cidx_inc) | TIMERREG(7) |
diff --git a/sys/dev/cxgbe/iw_cxgbe/user.h b/sys/dev/cxgbe/iw_cxgbe/user.h
index 59a1f43..d42f659 100644
--- a/sys/dev/cxgbe/iw_cxgbe/user.h
+++ b/sys/dev/cxgbe/iw_cxgbe/user.h
@@ -50,6 +50,7 @@ struct c4iw_create_cq_resp {
__u32 cqid;
__u32 size;
__u32 qid_mask;
+ __u32 reserved; /* explicit padding (optional for i386) */
};
struct c4iw_create_qp_resp {
diff --git a/sys/dev/cxgbe/offload.h b/sys/dev/cxgbe/offload.h
index 2b5e4dc..992b4cd 100644
--- a/sys/dev/cxgbe/offload.h
+++ b/sys/dev/cxgbe/offload.h
@@ -125,7 +125,6 @@ struct t4_virt_res { /* virtualized HW resources */
struct t4_range l2t;
};
-#ifdef TCP_OFFLOAD
enum {
ULD_TOM = 0,
ULD_IWARP,
@@ -152,6 +151,7 @@ struct tom_tunables {
int tx_align;
};
+#ifdef TCP_OFFLOAD
int t4_register_uld(struct uld_info *);
int t4_unregister_uld(struct uld_info *);
int t4_activate_uld(struct adapter *, int);
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 77777f8..11d4253 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -334,7 +334,8 @@ TUNABLE_INT("hw.cxgbe.nbmcaps_allowed", &t4_nbmcaps_allowed);
static int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */
TUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed);
-static int t4_switchcaps_allowed = 0;
+static int t4_switchcaps_allowed = FW_CAPS_CONFIG_SWITCH_INGRESS |
+ FW_CAPS_CONFIG_SWITCH_EGRESS;
TUNABLE_INT("hw.cxgbe.switchcaps_allowed", &t4_switchcaps_allowed);
static int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC;
@@ -343,13 +344,13 @@ TUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed);
static int t4_toecaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed);
-static int t4_rdmacaps_allowed = 0;
+static int t4_rdmacaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed);
static int t4_tlscaps_allowed = 0;
TUNABLE_INT("hw.cxgbe.tlscaps_allowed", &t4_tlscaps_allowed);
-static int t4_iscsicaps_allowed = 0;
+static int t4_iscsicaps_allowed = -1;
TUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed);
static int t4_fcoecaps_allowed = 0;
@@ -1731,29 +1732,29 @@ cxgbe_get_counter(struct ifnet *ifp, ift_counter c)
switch (c) {
case IFCOUNTER_IPACKETS:
- return (s->rx_frames - s->rx_pause);
+ return (s->rx_frames);
case IFCOUNTER_IERRORS:
return (s->rx_jabber + s->rx_runt + s->rx_too_long +
s->rx_fcs_err + s->rx_len_err);
case IFCOUNTER_OPACKETS:
- return (s->tx_frames - s->tx_pause);
+ return (s->tx_frames);
case IFCOUNTER_OERRORS:
return (s->tx_error_frames);
case IFCOUNTER_IBYTES:
- return (s->rx_octets - s->rx_pause * 64);
+ return (s->rx_octets);
case IFCOUNTER_OBYTES:
- return (s->tx_octets - s->tx_pause * 64);
+ return (s->tx_octets);
case IFCOUNTER_IMCASTS:
- return (s->rx_mcast_frames - s->rx_pause);
+ return (s->rx_mcast_frames);
case IFCOUNTER_OMCASTS:
- return (s->tx_mcast_frames - s->tx_pause);
+ return (s->tx_mcast_frames);
case IFCOUNTER_IQDROPS:
return (s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
@@ -6287,6 +6288,9 @@ mem_region_show(struct sbuf *sb, const char *name, unsigned int from,
{
unsigned int size;
+ if (from == to)
+ return;
+
size = to - from + 1;
if (size == 0)
return;
@@ -6390,13 +6394,10 @@ sysctl_meminfo(SYSCTL_HANDLER_ARGS)
md++;
if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
- if (chip_id(sc) <= CHELSIO_T5) {
- hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
+ if (chip_id(sc) <= CHELSIO_T5)
md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
- } else {
- hi = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
+ else
md->base = t4_read_reg(sc, A_LE_DB_HASH_TBL_BASE_ADDR);
- }
md->limit = 0;
} else {
md->base = 0;
@@ -9103,9 +9104,26 @@ tweak_tunables(void)
if (t4_toecaps_allowed == -1)
t4_toecaps_allowed = FW_CAPS_CONFIG_TOE;
+
+ if (t4_rdmacaps_allowed == -1) {
+ t4_rdmacaps_allowed = FW_CAPS_CONFIG_RDMA_RDDP |
+ FW_CAPS_CONFIG_RDMA_RDMAC;
+ }
+
+ if (t4_iscsicaps_allowed == -1) {
+ t4_iscsicaps_allowed = FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU |
+ FW_CAPS_CONFIG_ISCSI_TARGET_PDU |
+ FW_CAPS_CONFIG_ISCSI_T10DIF;
+ }
#else
if (t4_toecaps_allowed == -1)
t4_toecaps_allowed = 0;
+
+ if (t4_rdmacaps_allowed == -1)
+ t4_rdmacaps_allowed = 0;
+
+ if (t4_iscsicaps_allowed == -1)
+ t4_iscsicaps_allowed = 0;
#endif
#ifdef DEV_NETMAP
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index 33d8d48..daf3b8a 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -1397,13 +1397,8 @@ process_iql:
#if defined(INET) || defined(INET6)
if (iq->flags & IQ_LRO_ENABLED) {
struct lro_ctrl *lro = &rxq->lro;
- struct lro_entry *l;
- while (!SLIST_EMPTY(&lro->lro_active)) {
- l = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, l);
- }
+ tcp_lro_flush_all(lro);
}
#endif
@@ -2343,8 +2338,8 @@ eth_tx(struct mp_ring *r, u_int cidx, u_int pidx)
} else {
total++;
remaining--;
- n = write_txpkt_wr(txq, (void *)wr, m0, available);
ETHER_BPF_MTAP(ifp, m0);
+ n = write_txpkt_wr(txq, (void *)wr, m0, available);
}
MPASS(n >= 1 && n <= available && n <= SGE_MAX_WR_NDESC);
diff --git a/sys/dev/drm2/i915/i915_gem.c b/sys/dev/drm2/i915/i915_gem.c
index 7789e36..41ce74c 100644
--- a/sys/dev/drm2/i915/i915_gem.c
+++ b/sys/dev/drm2/i915/i915_gem.c
@@ -1481,7 +1481,7 @@ i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- vm_page_t page, oldpage;
+ vm_page_t page;
int ret = 0;
#ifdef FREEBSD_WIP
bool write = (prot & VM_PROT_WRITE) != 0;
@@ -1504,13 +1504,10 @@ i915_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
* progress.
*/
if (*mres != NULL) {
- oldpage = *mres;
- vm_page_lock(oldpage);
- vm_page_remove(oldpage);
- vm_page_unlock(oldpage);
- *mres = NULL;
- } else
- oldpage = NULL;
+ vm_page_lock(*mres);
+ vm_page_remove(*mres);
+ vm_page_unlock(*mres);
+ }
VM_OBJECT_WUNLOCK(vm_obj);
retry:
ret = 0;
@@ -1590,7 +1587,6 @@ retry:
}
page->valid = VM_PAGE_BITS_ALL;
have_page:
- *mres = page;
vm_page_xbusy(page);
CTR4(KTR_DRM, "fault %p %jx %x phys %x", gem_obj, offset, prot,
@@ -1603,11 +1599,13 @@ have_page:
i915_gem_object_unpin(obj);
}
DRM_UNLOCK(dev);
- if (oldpage != NULL) {
- vm_page_lock(oldpage);
- vm_page_free(oldpage);
- vm_page_unlock(oldpage);
+ if (*mres != NULL) {
+ KASSERT(*mres != page, ("loosing %p %p", *mres, page));
+ vm_page_lock(*mres);
+ vm_page_free(*mres);
+ vm_page_unlock(*mres);
}
+ *mres = page;
vm_object_pip_wakeup(vm_obj);
return (VM_PAGER_OK);
diff --git a/sys/dev/drm2/i915/intel_pm.c b/sys/dev/drm2/i915/intel_pm.c
index ab9eee4..ddab457 100644
--- a/sys/dev/drm2/i915/intel_pm.c
+++ b/sys/dev/drm2/i915/intel_pm.c
@@ -3672,9 +3672,39 @@ static void gen6_init_clock_gating(struct drm_device *dev)
ILK_DPARBUNIT_CLOCK_GATE_ENABLE |
ILK_DPFDUNIT_CLOCK_GATE_ENABLE);
+
+#ifdef FREEBSD_WIP
+ /* NOTE Linux<->FreeBSD: Disable GEN6_MBCTL write.
+ *
+ * This arrived in Linux 3.6 in commit
+ * b4ae3f22d238617ca11610b29fde16cf8c0bc6e0 and causes significantly
+ * increased power consumption after kldloading i915kms.ko on FreeBSD
+ * on (some) Sandy Bridge laptops. A Thinkpad X220 reported about 11W
+ * after booting while idle at the vt(4) console and about double that
+ * after loading the driver.
+ *
+ * There were reports in Linux of increased consumption after a suspend
+ * and resume cycle due to that change.
+ *
+ * Linux bug reports:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=54089
+ * https://bugzilla.kernel.org/show_bug.cgi?id=58971
+ *
+ * This suspend and resume issue is reportedly fixed in Linux with
+ * commits 7dcd2677ea912573d9ed4bcd629b0023b2d11505 and
+ * 7dcd2677ea912573d9ed4bcd629b0023b2d11505 (Linux 3.11). However, I
+ * found that those changes did not help on FreeBSD, where increased
+ * power consumption is observed after loading i915kms.ko without
+ * suspending and resuming.
+ *
+ * This workaround should be removed after updating to a future Linux
+ * i915 version and verifying normal power consumption on Sandy Bridge.
+ */
+
/* WaMbcDriverBootEnable */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
+#endif /* FREEBSD_WIP */
for_each_pipe(pipe) {
I915_WRITE(DSPCNTR(pipe),
diff --git a/sys/dev/drm2/ttm/ttm_bo_vm.c b/sys/dev/drm2/ttm/ttm_bo_vm.c
index 5d72d97..96ebeca 100644
--- a/sys/dev/drm2/ttm/ttm_bo_vm.c
+++ b/sys/dev/drm2/ttm/ttm_bo_vm.c
@@ -106,21 +106,18 @@ ttm_bo_vm_fault(vm_object_t vm_obj, vm_ooffset_t offset,
struct ttm_buffer_object *bo = vm_obj->handle;
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_tt *ttm = NULL;
- vm_page_t m, m1, oldm;
+ vm_page_t m, m1;
int ret;
int retval = VM_PAGER_OK;
struct ttm_mem_type_manager *man =
&bdev->man[bo->mem.mem_type];
vm_object_pip_add(vm_obj, 1);
- oldm = *mres;
- if (oldm != NULL) {
- vm_page_lock(oldm);
- vm_page_remove(oldm);
- vm_page_unlock(oldm);
- *mres = NULL;
- } else
- oldm = NULL;
+ if (*mres != NULL) {
+ vm_page_lock(*mres);
+ vm_page_remove(*mres);
+ vm_page_unlock(*mres);
+ }
retry:
VM_OBJECT_WUNLOCK(vm_obj);
m = NULL;
@@ -261,14 +258,14 @@ reserve:
bo, m, m1, (uintmax_t)offset));
}
m->valid = VM_PAGE_BITS_ALL;
- *mres = m;
vm_page_xbusy(m);
-
- if (oldm != NULL) {
- vm_page_lock(oldm);
- vm_page_free(oldm);
- vm_page_unlock(oldm);
+ if (*mres != NULL) {
+ KASSERT(*mres != m, ("loosing %p %p", *mres, m));
+ vm_page_lock(*mres);
+ vm_page_free(*mres);
+ vm_page_unlock(*mres);
}
+ *mres = m;
out_io_unlock1:
ttm_mem_io_unlock(man);
diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c
index b1b2c4a..93b33ad 100644
--- a/sys/dev/e1000/if_igb.c
+++ b/sys/dev/e1000/if_igb.c
@@ -1184,10 +1184,27 @@ igb_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
}
}
#endif
+#if __FreeBSD_version >= 1000000
+ /* HW cannot turn these on/off separately */
+ if (mask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
+ ifp->if_capenable ^= IFCAP_RXCSUM;
+ ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
+ reinit = 1;
+ }
+ if (mask & IFCAP_TXCSUM) {
+ ifp->if_capenable ^= IFCAP_TXCSUM;
+ reinit = 1;
+ }
+ if (mask & IFCAP_TXCSUM_IPV6) {
+ ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
+ reinit = 1;
+ }
+#else
if (mask & IFCAP_HWCSUM) {
ifp->if_capenable ^= IFCAP_HWCSUM;
reinit = 1;
}
+#endif
if (mask & IFCAP_TSO4) {
ifp->if_capenable ^= IFCAP_TSO4;
reinit = 1;
@@ -1266,14 +1283,26 @@ igb_init_locked(struct adapter *adapter)
/* Set hardware offload abilities */
ifp->if_hwassist = 0;
if (ifp->if_capenable & IFCAP_TXCSUM) {
+#if __FreeBSD_version >= 1000000
+ ifp->if_hwassist |= (CSUM_IP_TCP | CSUM_IP_UDP);
+ if (adapter->hw.mac.type != e1000_82575)
+ ifp->if_hwassist |= CSUM_IP_SCTP;
+#else
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
#if __FreeBSD_version >= 800000
- if ((adapter->hw.mac.type == e1000_82576) ||
- (adapter->hw.mac.type == e1000_82580))
+ if (adapter->hw.mac.type != e1000_82575)
ifp->if_hwassist |= CSUM_SCTP;
#endif
+#endif
}
+#if __FreeBSD_version >= 1000000
+ if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) {
+ ifp->if_hwassist |= (CSUM_IP6_TCP | CSUM_IP6_UDP);
+ if (adapter->hw.mac.type != e1000_82575)
+ ifp->if_hwassist |= CSUM_IP6_SCTP;
+ }
+#endif
if (ifp->if_capenable & IFCAP_TSO)
ifp->if_hwassist |= CSUM_TSO;
@@ -3160,6 +3189,9 @@ igb_setup_interface(device_t dev, struct adapter *adapter)
ifp->if_capabilities = ifp->if_capenable = 0;
ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM;
+#if __FreeBSD_version >= 1000000
+ ifp->if_capabilities |= IFCAP_HWCSUM_IPV6;
+#endif
ifp->if_capabilities |= IFCAP_TSO;
ifp->if_capabilities |= IFCAP_JUMBO_MTU;
ifp->if_capenable = ifp->if_capabilities;
@@ -3933,17 +3965,29 @@ igb_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp,
switch (ipproto) {
case IPPROTO_TCP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_TCP | CSUM_IP6_TCP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_TCP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_TCP;
break;
case IPPROTO_UDP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_UDP | CSUM_IP6_UDP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_UDP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_UDP;
break;
#if __FreeBSD_version >= 800000
case IPPROTO_SCTP:
+#if __FreeBSD_version >= 1000000
+ if (mp->m_pkthdr.csum_flags & (CSUM_IP_SCTP | CSUM_IP6_SCTP))
+#else
if (mp->m_pkthdr.csum_flags & CSUM_SCTP)
+#endif
type_tucmd_mlhl |= E1000_ADVTXD_TUCMD_L4T_SCTP;
break;
#endif
@@ -4701,8 +4745,7 @@ igb_initialize_receive_units(struct adapter *adapter)
rxcsum |= E1000_RXCSUM_PCSD;
#if __FreeBSD_version >= 800000
/* For SCTP Offload */
- if (((hw->mac.type == e1000_82576) ||
- (hw->mac.type == e1000_82580)) &&
+ if ((hw->mac.type != e1000_82575) &&
(ifp->if_capenable & IFCAP_RXCSUM))
rxcsum |= E1000_RXCSUM_CRCOFL;
#endif
@@ -4711,8 +4754,7 @@ igb_initialize_receive_units(struct adapter *adapter)
if (ifp->if_capenable & IFCAP_RXCSUM) {
rxcsum |= E1000_RXCSUM_IPPCSE;
#if __FreeBSD_version >= 800000
- if ((adapter->hw.mac.type == e1000_82576) ||
- (adapter->hw.mac.type == e1000_82580))
+ if (adapter->hw.mac.type != e1000_82575)
rxcsum |= E1000_RXCSUM_CRCOFL;
#endif
} else
@@ -4932,7 +4974,6 @@ igb_rxeof(struct igb_queue *que, int count, int *done)
struct rx_ring *rxr = que->rxr;
struct ifnet *ifp = adapter->ifp;
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
int i, processed = 0, rxdone = 0;
u32 ptype, staterr = 0;
union e1000_adv_rx_desc *cur;
@@ -5160,10 +5201,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
if (done != NULL)
*done += rxdone;
diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h
index 98df1ec..a0c35be 100644
--- a/sys/dev/e1000/if_igb.h
+++ b/sys/dev/e1000/if_igb.h
@@ -291,7 +291,11 @@
#define ETH_ADDR_LEN 6
/* Offload bits in mbuf flag */
-#if __FreeBSD_version >= 800000
+#if __FreeBSD_version >= 1000000
+#define CSUM_OFFLOAD_IPV4 (CSUM_IP|CSUM_IP_TCP|CSUM_IP_UDP|CSUM_IP_SCTP)
+#define CSUM_OFFLOAD_IPV6 (CSUM_IP6_TCP|CSUM_IP6_UDP|CSUM_IP6_SCTP)
+#define CSUM_OFFLOAD (CSUM_OFFLOAD_IPV4|CSUM_OFFLOAD_IPV6)
+#elif __FreeBSD_version >= 800000
#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP)
#else
#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP)
diff --git a/sys/dev/ed/if_ed_3c503.c b/sys/dev/ed/if_ed_3c503.c
index 353fbbf..bcb9e44 100644
--- a/sys/dev/ed/if_ed_3c503.c
+++ b/sys/dev/ed/if_ed_3c503.c
@@ -324,7 +324,7 @@ ed_probe_3Com(device_t dev, int port_rid, int flags)
ed_asic_outb(sc, ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be 3-5,9 for 3c503\n",
+ device_printf(dev, "Invalid irq configuration (%jd) must be 3-5,9 for 3c503\n",
irq);
return (ENXIO);
}
diff --git a/sys/dev/ed/if_ed_cbus.c b/sys/dev/ed/if_ed_cbus.c
index f9672ac..7926fa8 100644
--- a/sys/dev/ed/if_ed_cbus.c
+++ b/sys/dev/ed/if_ed_cbus.c
@@ -1021,7 +1021,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
if (((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0)
|| ((rman_get_start(sc->port_res) & 0xf000) < (u_short) 0xa000)) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0x[a-f]3d0", "CNET98");
#endif
@@ -1032,7 +1032,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
/* Check window area address */
tmp_s = rman_get_start(sc->mem_res) >> 12;
if (tmp_s < 0x80) {
- device_printf(dev, "Please change window address(0x%lx)\n",
+ device_printf(dev, "Please change window address(0x%jx)\n",
rman_get_start(sc->mem_res));
return (ENXIO);
}
@@ -1040,8 +1040,8 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
tmp_s &= 0x0f;
tmp = rman_get_start(sc->port_res) >> 12;
if ((tmp_s <= tmp) && (tmp < (tmp_s + 4))) {
- device_printf(dev, "Please change iobase address(0x%lx) "
- "or window address(0x%lx)\n",
+ device_printf(dev, "Please change iobase address(0x%jx) "
+ "or window address(0x%jx)\n",
rman_get_start(sc->port_res),
rman_get_start(sc->mem_res));
return (ENXIO);
@@ -1128,7 +1128,7 @@ ed_probe_CNET98(device_t dev, int port_rid, int flags)
tmp = ED_CNET98_INT_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,9,12,13", "CNET98");
return (ENXIO);
}
@@ -1169,7 +1169,7 @@ ed_probe_CNET98EL(device_t dev, int port_rid, int flags)
/* Check I/O address. 0x[0-f]3d0 are allowed. */
if ((rman_get_start(sc->port_res) & 0x0fff) != 0x03d0) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0x?3d0", "CNET98E/L");
#endif
@@ -1223,7 +1223,7 @@ ed_probe_CNET98EL(device_t dev, int port_rid, int flags)
break;
#endif
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6", "CNET98E/L");
return (ENXIO);
}
@@ -1285,7 +1285,7 @@ ed_probe_NEC77(device_t dev, int port_rid, int flags)
tmp = ED_NEC77_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12,13", "PC-9801-77");
return (ENXIO);
}
@@ -1337,7 +1337,7 @@ ed_probe_NW98X(device_t dev, int port_rid, int flags)
tmp = ED_NW98X_IRQ13;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12,13", "EC/EP-98X");
return (ENXIO);
}
@@ -1439,7 +1439,7 @@ ed_probe_SB98(device_t dev, int port_rid, int flags)
/* Check I/O address. 00d[02468ace] are allowed. */
if ((rman_get_start(sc->port_res) & ~0x000e) != 0x00d0) {
#ifdef DIAGNOSTIC
- device_printf(dev, "Invalid i/o port configuration (0x%lx) "
+ device_printf(dev, "Invalid i/o port configuration (0x%jx) "
"must be %s for %s\n", rman_get_start(sc->port_res),
"0xd?", "SB9801");
#endif
@@ -1475,7 +1475,7 @@ ed_probe_SB98(device_t dev, int port_rid, int flags)
tmp = ED_SB98_CFG_IRQ12;
break;
default:
- device_printf(dev, "Invalid irq configuration (%ld) must be "
+ device_printf(dev, "Invalid irq configuration (%jd) must be "
"%s for %s\n", conf_irq, "3,5,6,12", "SB9801");
return (ENXIO);
}
diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c
index f1ed098..07cbd6b 100644
--- a/sys/dev/extres/clk/clk.c
+++ b/sys/dev/extres/clk/clk.c
@@ -487,10 +487,10 @@ clkdom_dump(struct clkdom * clkdom)
CLK_TOPO_SLOCK();
TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) {
rv = clknode_get_freq(clknode, &freq);
- printf("Clock: %s, parent: %s(%d), freq: %llu\n", clknode->name,
+ printf("Clock: %s, parent: %s(%d), freq: %ju\n", clknode->name,
clknode->parent == NULL ? "(NULL)" : clknode->parent->name,
clknode->parent_idx,
- ((rv == 0) ? freq: rv));
+ (uintmax_t)((rv == 0) ? freq: rv));
}
CLK_TOPO_UNLOCK();
}
@@ -818,6 +818,10 @@ clknode_set_freq(struct clknode *clknode, uint64_t freq, int flags,
/* We have exclusive topology lock, node lock is not needed. */
CLK_TOPO_XASSERT();
+ /* Check for no change */
+ if (clknode->freq == freq)
+ return (0);
+
parent_freq = 0;
/*
@@ -1258,4 +1262,75 @@ clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk)
return (rv);
return (clk_get_by_ofw_index(dev, idx, clk));
}
+
+/* --------------------------------------------------------------------------
+ *
+ * Support functions for parsing various clock related OFW things.
+ */
+
+/*
+ * Get "clock-output-names" and (optional) "clock-indices" lists.
+ * Both lists are alocated using M_OFWPROP specifier.
+ *
+ * Returns number of items or 0.
+ */
+int
+clk_parse_ofw_out_names(device_t dev, phandle_t node, const char ***out_names,
+ uint32_t **indices)
+{
+ int name_items, rv;
+
+ *out_names = NULL;
+ *indices = NULL;
+ if (!OF_hasprop(node, "clock-output-names"))
+ return (0);
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ out_names);
+ if (rv <= 0)
+ return (0);
+ name_items = rv;
+
+ if (!OF_hasprop(node, "clock-indices"))
+ return (name_items);
+ rv = OF_getencprop_alloc(node, "clock-indices", sizeof (uint32_t),
+ (void **)indices);
+ if (rv != name_items) {
+ device_printf(dev, " Size of 'clock-output-names' and "
+ "'clock-indices' differs\n");
+ free(*out_names, M_OFWPROP);
+ free(*indices, M_OFWPROP);
+ return (0);
+ }
+ return (name_items);
+}
+
+/*
+ * Get output clock name for single output clock node.
+ */
+int
+clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name)
+{
+ const char **out_names;
+ const char *tmp_name;
+ int rv;
+
+ *name = NULL;
+ if (!OF_hasprop(node, "clock-output-names")) {
+ tmp_name = ofw_bus_get_name(dev);
+ if (tmp_name == NULL)
+ return (ENXIO);
+ *name = strdup(tmp_name, M_OFWPROP);
+ return (0);
+ }
+ rv = ofw_bus_string_list_to_array(node, "clock-output-names",
+ &out_names);
+ if (rv != 1) {
+ free(out_names, M_OFWPROP);
+ device_printf(dev, "Malformed 'clock-output-names' property\n");
+ return (ENXIO);
+ }
+ *name = strdup(out_names[0], M_OFWPROP);
+ free(out_names, M_OFWPROP);
+ return (0);
+}
#endif
diff --git a/sys/dev/extres/clk/clk.h b/sys/dev/extres/clk/clk.h
index 8547bae..510f0ce 100644
--- a/sys/dev/extres/clk/clk.h
+++ b/sys/dev/extres/clk/clk.h
@@ -131,6 +131,9 @@ const char *clk_get_name(clk_t clk);
#ifdef FDT
int clk_get_by_ofw_index(device_t dev, int idx, clk_t *clk);
int clk_get_by_ofw_name(device_t dev, const char *name, clk_t *clk);
+int clk_parse_ofw_out_names(device_t dev, phandle_t node,
+ const char ***out_names, uint32_t **indices);
+int clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name);
#endif
#endif /* _DEV_EXTRES_CLK_H_ */
diff --git a/sys/dev/extres/clk/clk_bus.c b/sys/dev/extres/clk/clk_bus.c
new file mode 100644
index 0000000..e475736
--- /dev/null
+++ b/sys/dev/extres/clk/clk_bus.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+struct ofw_clkbus_softc {
+ struct simplebus_softc simplebus_sc;
+};
+
+static int
+ofw_clkbus_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+
+ if (name == NULL || strcmp(name, "clocks") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "OFW clocks bus");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static int
+ofw_clkbus_attach(device_t dev)
+{
+ struct ofw_clkbus_softc *sc;
+ phandle_t node, child;
+ device_t cdev;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ simplebus_init(dev, node);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+ if (cdev != NULL)
+ device_probe_and_attach(cdev);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t ofw_clkbus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_clkbus_probe),
+ DEVMETHOD(device_attach, ofw_clkbus_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofw_clkbus, ofw_clkbus_driver, ofw_clkbus_methods,
+ sizeof(struct ofw_clkbus_softc), simplebus_driver);
+static devclass_t ofw_clkbus_devclass;
+EARLY_DRIVER_MODULE(ofw_clkbus, simplebus, ofw_clkbus_driver,
+ ofw_clkbus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofw_clkbus, 1);
diff --git a/sys/dev/extres/clk/clk_div.c b/sys/dev/extres/clk/clk_div.c
index fcb0a57..51cc838 100644
--- a/sys/dev/extres/clk/clk_div.c
+++ b/sys/dev/extres/clk/clk_div.c
@@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_div_init(struct clknode *clk, device_t dev);
static int clknode_div_recalc(struct clknode *clk, uint64_t *req);
@@ -86,7 +90,9 @@ clknode_div_init(struct clknode *clk, device_t dev)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
if (rv != 0)
return (rv);
@@ -171,12 +177,17 @@ clknode_div_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
(*fout != (_fin / divider)))
return (ERANGE);
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset,
(sc->i_mask << sc->i_shift) | (sc->f_mask << sc->f_shift),
(i_div << sc->i_shift) | (f_div << sc->f_shift));
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
+
sc->divider = divider;
}
diff --git a/sys/dev/extres/clk/clk_fixed.c b/sys/dev/extres/clk/clk_fixed.c
index 4ddceae..02721ae 100644
--- a/sys/dev/extres/clk/clk_fixed.c
+++ b/sys/dev/extres/clk/clk_fixed.c
@@ -27,7 +27,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/bus.h>
@@ -35,20 +34,25 @@ __FBSDID("$FreeBSD$");
#include <sys/kobj.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/module.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <machine/bus.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
#include <dev/extres/clk/clk_fixed.h>
-#define DEVICE_LOCK(_sc) mtx_lock((_sc)->mtx)
-#define DEVICE_UNLOCK(_sc) mtx_unlock((_sc)->mtx)
+#define CLK_TYPE_FIXED 1
+#define CLK_TYPE_FIXED_FACTOR 2
static int clknode_fixed_init(struct clknode *clk, device_t dev);
static int clknode_fixed_recalc(struct clknode *clk, uint64_t *freq);
+static int clknode_fixed_set_freq(struct clknode *clk, uint64_t fin,
+ uint64_t *fout, int flags, int *stop);
+
struct clknode_fixed_sc {
- struct mtx *mtx;
int fixed_flags;
uint64_t freq;
uint32_t mult;
@@ -59,6 +63,7 @@ static clknode_method_t clknode_fixed_methods[] = {
/* Device interface */
CLKNODEMETHOD(clknode_init, clknode_fixed_init),
CLKNODEMETHOD(clknode_recalc_freq, clknode_fixed_recalc),
+ CLKNODEMETHOD(clknode_set_freq, clknode_fixed_set_freq),
CLKNODEMETHOD_END
};
DEFINE_CLASS_1(clknode_fixed, clknode_fixed_class, clknode_fixed_methods,
@@ -74,36 +79,52 @@ clknode_fixed_init(struct clknode *clk, device_t dev)
clknode_init_parent_idx(clk, 0);
return(0);
}
+
static int
clknode_fixed_recalc(struct clknode *clk, uint64_t *freq)
{
struct clknode_fixed_sc *sc;
sc = clknode_get_softc(clk);
- if (sc->freq != 0)
- *freq = sc->freq;
- else if ((sc->mult != 0) && (sc->div != 0))
+
+ if ((sc->mult != 0) && (sc->div != 0))
*freq = (*freq / sc->div) * sc->mult;
else
- *freq = 0;
+ *freq = sc->freq;
+ return (0);
+}
+
+static int
+clknode_fixed_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
+ int flags, int *stop)
+{
+ struct clknode_fixed_sc *sc;
+
+ sc = clknode_get_softc(clk);
+ if (sc->mult == 0 || sc->div == 0) {
+ /* Fixed frequency clock. */
+ *stop = 1;
+ if (*fout != sc->freq)
+ return (ERANGE);
+ return (0);
+ }
+ /* Fixed factor clock. */
+ *stop = 0;
+ *fout = (*fout / sc->mult) * sc->div;
return (0);
}
int
-clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
- struct mtx *dev_mtx)
+clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef)
{
struct clknode *clk;
struct clknode_fixed_sc *sc;
- if ((clkdef->freq == 0) && (clkdef->clkdef.parent_cnt == 0))
- panic("fixed clk: Frequency is not defined for clock source");
clk = clknode_create(clkdom, &clknode_fixed_class, &clkdef->clkdef);
if (clk == NULL)
return (1);
sc = clknode_get_softc(clk);
- sc->mtx = dev_mtx;
sc->fixed_flags = clkdef->fixed_flags;
sc->freq = clkdef->freq;
sc->mult = clkdef->mult;
@@ -112,3 +133,150 @@ clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
clknode_register(clkdom, clk);
return (0);
}
+
+#ifdef FDT
+
+static struct ofw_compat_data compat_data[] = {
+ {"fixed-clock", CLK_TYPE_FIXED},
+ {"fixed-factor-clock", CLK_TYPE_FIXED_FACTOR},
+ {NULL, 0},
+};
+
+struct clk_fixed_softc {
+ device_t dev;
+ struct clkdom *clkdom;
+};
+
+static int
+clk_fixed_probe(device_t dev)
+{
+ intptr_t clk_type;
+
+ clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ switch (clk_type) {
+ case CLK_TYPE_FIXED:
+ device_set_desc(dev, "Fixed clock");
+ return (BUS_PROBE_DEFAULT);
+ case CLK_TYPE_FIXED_FACTOR:
+ device_set_desc(dev, "Fixed factor clock");
+ return (BUS_PROBE_DEFAULT);
+ default:
+ return (ENXIO);
+ }
+}
+
+static int
+clk_fixed_init_fixed(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ uint32_t freq;
+ int rv;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-frequency", &freq, sizeof(freq));
+ if (rv <= 0)
+ return (ENXIO);
+ def->freq = freq;
+ return (0);
+}
+
+static int
+clk_fixed_init_fixed_factor(struct clk_fixed_softc *sc, phandle_t node,
+ struct clk_fixed_def *def)
+{
+ int rv;
+ clk_t parent;
+
+ def->clkdef.id = 1;
+ rv = OF_getencprop(node, "clock-mult", &def->mult, sizeof(def->mult));
+ if (rv <= 0)
+ return (ENXIO);
+ rv = OF_getencprop(node, "clock-div", &def->div, sizeof(def->div));
+ if (rv <= 0)
+ return (ENXIO);
+ /* Get name of parent clock */
+ rv = clk_get_by_ofw_index(sc->dev, 0, &parent);
+ if (rv != 0)
+ return (ENXIO);
+ def->clkdef.parent_names = malloc(sizeof(char *), M_OFWPROP, M_WAITOK);
+ def->clkdef.parent_names[0] = clk_get_name(parent);
+ def->clkdef.parent_cnt = 1;
+ clk_release(parent);
+ return (0);
+}
+
+static int
+clk_fixed_attach(device_t dev)
+{
+ struct clk_fixed_softc *sc;
+ intptr_t clk_type;
+ phandle_t node;
+ struct clk_fixed_def def;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ node = ofw_bus_get_node(dev);
+ clk_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
+ bzero(&def, sizeof(def));
+ if (clk_type == CLK_TYPE_FIXED)
+ rv = clk_fixed_init_fixed(sc, node, &def);
+ else if (clk_type == CLK_TYPE_FIXED_FACTOR)
+ rv = clk_fixed_init_fixed_factor(sc, node, &def);
+ else
+ rv = ENXIO;
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot FDT parameters.\n");
+ goto fail;
+ }
+ rv = clk_parse_ofw_clk_name(dev, node, &def.clkdef.name);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse clock name.\n");
+ goto fail;
+ }
+ sc->clkdom = clkdom_create(dev);
+ KASSERT(sc->clkdom != NULL, ("Clock domain is NULL"));
+
+ rv = clknode_fixed_register(sc->clkdom, &def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot register fixed clock.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+
+ rv = clkdom_finit(sc->clkdom);
+ if (rv != 0) {
+ device_printf(sc->dev, "Clk domain finit fails.\n");
+ rv = ENXIO;
+ goto fail;
+ }
+#ifdef CLK_DEBUG
+ clkdom_dump(sc->clkdom);
+#endif
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (bus_generic_attach(dev));
+
+fail:
+ free(__DECONST(char *, def.clkdef.name), M_OFWPROP);
+ free(def.clkdef.parent_names, M_OFWPROP);
+ return (rv);
+}
+
+static device_method_t clk_fixed_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, clk_fixed_probe),
+ DEVMETHOD(device_attach, clk_fixed_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(clk_fixed, clk_fixed_driver, clk_fixed_methods,
+ sizeof(struct clk_fixed_softc));
+static devclass_t clk_fixed_devclass;
+EARLY_DRIVER_MODULE(clk_fixed, simplebus, clk_fixed_driver,
+ clk_fixed_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(clk_fixed, 1);
+
+#endif
diff --git a/sys/dev/extres/clk/clk_fixed.h b/sys/dev/extres/clk/clk_fixed.h
index f57ee96..e2643ff 100644
--- a/sys/dev/extres/clk/clk_fixed.h
+++ b/sys/dev/extres/clk/clk_fixed.h
@@ -47,7 +47,6 @@ struct clk_fixed_def {
int fixed_flags;
};
-int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef,
- struct mtx *dev_mtx);
+int clknode_fixed_register(struct clkdom *clkdom, struct clk_fixed_def *clkdef);
#endif /*_DEV_EXTRES_CLK_FIXED_H_*/
diff --git a/sys/dev/extres/clk/clk_gate.c b/sys/dev/extres/clk/clk_gate.c
index 2107450..e0673fd 100644
--- a/sys/dev/extres/clk/clk_gate.c
+++ b/sys/dev/extres/clk/clk_gate.c
@@ -46,7 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
-
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_gate_init(struct clknode *clk, device_t dev);
static int clknode_gate_set_gate(struct clknode *clk, bool enable);
@@ -77,7 +80,9 @@ clknode_gate_init(struct clknode *clk, device_t dev)
int rv;
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
if (rv != 0)
return (rv);
reg = (reg >> sc->shift) & sc->mask;
@@ -95,11 +100,15 @@ clknode_gate_set_gate(struct clknode *clk, bool enable)
sc = clknode_get_softc(clk);
sc->ungated = enable;
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
(sc->ungated ? sc->on_value : sc->off_value) << sc->shift);
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
return(0);
}
diff --git a/sys/dev/extres/clk/clk_mux.c b/sys/dev/extres/clk/clk_mux.c
index 54e0653..624f587 100644
--- a/sys/dev/extres/clk/clk_mux.c
+++ b/sys/dev/extres/clk/clk_mux.c
@@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$");
CLKDEV_READ_4(clknode_get_device(_clk), off, val)
#define MD4(_clk, off, clr, set ) \
CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set)
+#define DEVICE_LOCK(_clk) \
+ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define DEVICE_UNLOCK(_clk) \
+ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
static int clknode_mux_init(struct clknode *clk, device_t dev);
static int clknode_mux_set_mux(struct clknode *clk, int idx);
@@ -76,9 +80,12 @@ clknode_mux_init(struct clknode *clk, device_t dev)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = RD4(clk, sc->offset, &reg);
- if (rv != 0)
+ DEVICE_UNLOCK(clk);
+ if (rv != 0) {
return (rv);
+ }
reg = (reg >> sc->shift) & sc->mask;
clknode_init_parent_idx(clk, reg);
return(0);
@@ -93,11 +100,16 @@ clknode_mux_set_mux(struct clknode *clk, int idx)
sc = clknode_get_softc(clk);
+ DEVICE_LOCK(clk);
rv = MD4(clk, sc->offset, sc->mask << sc->shift,
(idx & sc->mask) << sc->shift);
- if (rv != 0)
+ if (rv != 0) {
+ DEVICE_UNLOCK(clk);
return (rv);
+ }
RD4(clk, sc->offset, &reg);
+ DEVICE_UNLOCK(clk);
+
return(0);
}
diff --git a/sys/dev/extres/clk/clkdev_if.m b/sys/dev/extres/clk/clkdev_if.m
index b43d205..f9f5084 100644
--- a/sys/dev/extres/clk/clkdev_if.m
+++ b/sys/dev/extres/clk/clkdev_if.m
@@ -30,6 +30,71 @@
INTERFACE clkdev;
+CODE {
+ #include <sys/systm.h>
+ #include <sys/bus.h>
+ static int
+ clkdev_default_write_4(device_t dev, bus_addr_t addr, uint32_t val)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_WRITE_4(pdev, addr, val));
+ }
+
+ static int
+ clkdev_default_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_READ_4(pdev, addr, val));
+ }
+
+ static int
+ clkdev_default_modify_4(device_t dev, bus_addr_t addr,
+ uint32_t clear_mask, uint32_t set_mask)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ return (ENXIO);
+
+ return (CLKDEV_MODIFY_4(pdev, addr, clear_mask, set_mask));
+ }
+
+ static void
+ clkdev_default_device_lock(device_t dev)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ panic("clkdev_device_lock not implemented");
+
+ CLKDEV_DEVICE_LOCK(pdev);
+ }
+
+ static void
+ clkdev_default_device_unlock(device_t dev)
+ {
+ device_t pdev;
+
+ pdev = device_get_parent(dev);
+ if (pdev == NULL)
+ panic("clkdev_device_unlock not implemented");
+
+ CLKDEV_DEVICE_UNLOCK(pdev);
+ }
+}
+
#
# Write single register
#
@@ -37,7 +102,7 @@ METHOD int write_4 {
device_t dev;
bus_addr_t addr;
uint32_t val;
-};
+} DEFAULT clkdev_default_write_4;
#
# Read single register
@@ -46,7 +111,7 @@ METHOD int read_4 {
device_t dev;
bus_addr_t addr;
uint32_t *val;
-};
+} DEFAULT clkdev_default_read_4;
#
# Modify single register
@@ -56,4 +121,18 @@ METHOD int modify_4 {
bus_addr_t addr;
uint32_t clear_mask;
uint32_t set_mask;
-};
+} DEFAULT clkdev_default_modify_4;
+
+#
+# Get exclusive access to underlying device
+#
+METHOD void device_lock {
+ device_t dev;
+} DEFAULT clkdev_default_device_lock;
+
+#
+# Release exclusive access to underlying device
+#
+METHOD void device_unlock {
+ device_t dev;
+} DEFAULT clkdev_default_device_unlock;
diff --git a/sys/dev/extres/phy/phy.c b/sys/dev/extres/phy/phy.c
new file mode 100644
index 0000000..0e2c7e1
--- /dev/null
+++ b/sys/dev/extres/phy/phy.c
@@ -0,0 +1,235 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#include "opt_platform.h"
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+
+#include <dev/extres/phy/phy.h>
+
+#include "phy_if.h"
+
+struct phy {
+ device_t consumer_dev; /* consumer device*/
+ device_t provider_dev; /* provider device*/
+ uintptr_t phy_id; /* phy id */
+};
+
+MALLOC_DEFINE(M_PHY, "phy", "Phy framework");
+
+int
+phy_init(device_t consumer, phy_t phy)
+{
+
+ return (PHY_INIT(phy->provider_dev, phy->phy_id, true));
+}
+
+int
+phy_deinit(device_t consumer, phy_t phy)
+{
+
+ return (PHY_INIT(phy->provider_dev, phy->phy_id, false));
+}
+
+
+int
+phy_enable(device_t consumer, phy_t phy)
+{
+
+ return (PHY_ENABLE(phy->provider_dev, phy->phy_id, true));
+}
+
+int
+phy_disable(device_t consumer, phy_t phy)
+{
+
+ return (PHY_ENABLE(phy->provider_dev, phy->phy_id, false));
+}
+
+int
+phy_status(device_t consumer, phy_t phy, int *value)
+{
+
+ return (PHY_STATUS(phy->provider_dev, phy->phy_id, value));
+}
+
+int
+phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
+ phy_t *phy_out)
+{
+ phy_t phy;
+
+ /* Create handle */
+ phy = malloc(sizeof(struct phy), M_PHY,
+ M_WAITOK | M_ZERO);
+ phy->consumer_dev = consumer_dev;
+ phy->provider_dev = provider_dev;
+ phy->phy_id = id;
+ *phy_out = phy;
+ return (0);
+}
+
+void
+phy_release(phy_t phy)
+{
+ free(phy, M_PHY);
+}
+
+
+#ifdef FDT
+int phy_default_map(device_t provider, phandle_t xref, int ncells,
+ pcell_t *cells, intptr_t *id)
+{
+
+ if (ncells == 0)
+ *id = 1;
+ else if (ncells == 1)
+ *id = cells[0];
+ else
+ return (ERANGE);
+
+ return (0);
+}
+
+int
+phy_get_by_ofw_idx(device_t consumer_dev, int idx, phy_t *phy)
+{
+ phandle_t cnode, xnode;
+ pcell_t *cells;
+ device_t phydev;
+ int ncells, rv;
+ intptr_t id;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ rv = ofw_bus_parse_xref_list_alloc(cnode, "phys", "#phy-cells", idx,
+ &xnode, &ncells, &cells);
+ if (rv != 0)
+ return (rv);
+
+ /* Tranlate provider to device. */
+ phydev = OF_device_from_xref(xnode);
+ if (phydev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+ /* Map phy to number. */
+ rv = PHY_MAP(phydev, xnode, ncells, cells, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+
+ return (phy_get_by_id(consumer_dev, phydev, id, phy));
+}
+
+int
+phy_get_by_ofw_name(device_t consumer_dev, char *name, phy_t *phy)
+{
+ int rv, idx;
+ phandle_t cnode;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ rv = ofw_bus_find_string_index(cnode, "phy-names", name, &idx);
+ if (rv != 0)
+ return (rv);
+ return (phy_get_by_ofw_idx(consumer_dev, idx, phy));
+}
+
+int
+phy_get_by_ofw_property(device_t consumer_dev, char *name, phy_t *phy)
+{
+ phandle_t cnode;
+ pcell_t *cells;
+ device_t phydev;
+ int ncells, rv;
+ intptr_t id;
+
+ cnode = ofw_bus_get_node(consumer_dev);
+ if (cnode <= 0) {
+ device_printf(consumer_dev,
+ "%s called on not ofw based device\n", __func__);
+ return (ENXIO);
+ }
+ ncells = OF_getencprop_alloc(cnode, name, sizeof(pcell_t),
+ (void **)&cells);
+ if (ncells < 1)
+ return (ENXIO);
+
+ /* Tranlate provider to device. */
+ phydev = OF_device_from_xref(cells[0]);
+ if (phydev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+ /* Map phy to number. */
+ rv = PHY_MAP(phydev, cells[0], ncells - 1 , cells + 1, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+
+ return (phy_get_by_id(consumer_dev, phydev, id, phy));
+}
+
+void
+phy_register_provider(device_t provider_dev)
+{
+ phandle_t xref, node;
+
+ node = ofw_bus_get_node(provider_dev);
+ if (node <= 0)
+ panic("%s called on not ofw based device.\n", __func__);
+
+ xref = OF_xref_from_node(node);
+ OF_device_register_xref(xref, provider_dev);
+}
+
+void
+phy_unregister_provider(device_t provider_dev)
+{
+ phandle_t xref;
+
+ xref = OF_xref_from_device(provider_dev);
+ OF_device_register_xref(xref, NULL);
+}
+#endif
diff --git a/sys/dev/extres/phy/phy.h b/sys/dev/extres/phy/phy.h
new file mode 100644
index 0000000..93b4fe4
--- /dev/null
+++ b/sys/dev/extres/phy/phy.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef DEV_EXTRES_PHY_H
+#define DEV_EXTRES_PHY_H
+
+#include "opt_platform.h"
+#include <sys/types.h>
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+typedef struct phy *phy_t;
+
+/*
+ * Provider interface
+ */
+#ifdef FDT
+void phy_register_provider(device_t provider);
+void phy_unregister_provider(device_t provider);
+#endif
+
+/*
+ * Consumer interface
+ */
+int phy_get_by_id(device_t consumer_dev, device_t provider_dev, intptr_t id,
+ phy_t *phy);
+void phy_release(phy_t phy);
+int phy_get_by_ofw_name(device_t consumer, char *name, phy_t *phy);
+int phy_get_by_ofw_idx(device_t consumer, int idx, phy_t *phy);
+int phy_get_by_ofw_property(device_t consumer, char *name, phy_t *phy);
+
+int phy_init(device_t consumer, phy_t phy);
+int phy_deinit(device_t consumer, phy_t phy);
+int phy_enable(device_t consumer, phy_t phy);
+int phy_disable(device_t consumer, phy_t phy);
+int phy_status(device_t consumer, phy_t phy, int *value);
+
+#endif /* DEV_EXTRES_PHY_H */
diff --git a/sys/dev/extres/phy/phy_if.m b/sys/dev/extres/phy/phy_if.m
new file mode 100644
index 0000000..e3b4e33
--- /dev/null
+++ b/sys/dev/extres/phy/phy_if.m
@@ -0,0 +1,84 @@
+#-
+# Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 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$
+#
+
+#ifdef FDT
+#include <sys/types.h>
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+INTERFACE phy;
+
+#ifdef FDT
+HEADER {
+int phy_default_map(device_t , phandle_t, int, pcell_t *, intptr_t *);
+}
+
+#
+# map fdt property cells to phy number
+# Returns 0 on success or a standard errno value.
+#
+METHOD int map {
+ device_t provider_dev;
+ phandle_t xref;
+ int ncells;
+ pcell_t *cells;
+ intptr_t *id;
+} DEFAULT phy_default_map;
+#endif
+
+#
+# Init/deinit phy
+# Returns 0 on success or a standard errno value.
+#
+METHOD int init {
+ device_t provider_dev;
+ intptr_t id;
+ bool inti;
+};
+
+#
+# Enable/disable phy
+# Returns 0 on success or a standard errno value.
+#
+METHOD int enable {
+ device_t provider_dev;
+ intptr_t id;
+ bool enable;
+};
+
+#
+# Get phy status
+# Returns 0 on success or a standard errno value.
+#
+METHOD int status {
+ device_t provider_dev;
+ intptr_t id;
+ int *status; /* PHY_STATUS_* */
+};
+
+
diff --git a/sys/dev/extres/regulator/regdev_if.m b/sys/dev/extres/regulator/regdev_if.m
new file mode 100644
index 0000000..eecbf8b
--- /dev/null
+++ b/sys/dev/extres/regulator/regdev_if.m
@@ -0,0 +1,56 @@
+#-
+# Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 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$
+#
+
+#ifdef FDT
+#include <sys/types.h>
+#include <dev/ofw/ofw_bus.h>
+#endif
+
+#include <machine/bus.h>
+
+INTERFACE regdev;
+
+#ifdef FDT
+
+HEADER {
+int regdev_default_ofw_map(device_t , phandle_t, int, pcell_t *, intptr_t *);
+}
+
+#
+# map fdt property cells to regulator number
+# Returns 0 on success or a standard errno value.
+#
+METHOD int map {
+ device_t provider_dev;
+ phandle_t xref;
+ int ncells;
+ pcell_t *cells;
+ intptr_t *id;
+} DEFAULT regdev_default_ofw_map;
+
+#endif
diff --git a/sys/dev/extres/regulator/regnode_if.m b/sys/dev/extres/regulator/regnode_if.m
new file mode 100644
index 0000000..d92f26f
--- /dev/null
+++ b/sys/dev/extres/regulator/regnode_if.m
@@ -0,0 +1,82 @@
+#-
+# Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+INTERFACE regnode;
+HEADER {
+ struct regnode;
+}
+
+#
+# Initialize regulator
+# Returns 0 on success or a standard errno value.
+#
+METHOD int init {
+ struct regnode *regnode;
+};
+
+#
+# Enable/disable regulator
+# Returns 0 on success or a standard errno value.
+# - enable - input.
+# - delay - output, delay needed to stabilize voltage (in us)
+#
+METHOD int enable {
+ struct regnode *regnode;
+ bool enable;
+ int *udelay;
+};
+
+#
+# Get regulator status
+# Returns 0 on success or a standard errno value.
+#
+METHOD int status {
+ struct regnode *regnode;
+ int *status; /* REGULATOR_STATUS_* */
+};
+
+#
+# Set regulator voltage
+# Returns 0 on success or a standard errno value.
+# - min_uvolt, max_uvolt - input, requested voltage range (in uV)
+# - delay - output, delay needed to stabilize voltage (in us)
+METHOD int set_voltage {
+ struct regnode *regnode;
+ int min_uvolt;
+ int max_uvolt;
+ int *udelay;
+};
+
+#
+# Get regulator voltage
+# Returns 0 on success or a standard errno value.
+#
+METHOD int get_voltage {
+ struct regnode *regnode;
+ int *uvolt;
+};
diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/extres/regulator/regulator.c
new file mode 100644
index 0000000..b941aa1
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator.c
@@ -0,0 +1,984 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/kobj.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+#include <dev/extres/regulator/regulator.h>
+
+#include "regdev_if.h"
+
+MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework");
+
+/* Forward declarations. */
+struct regulator;
+struct regnode;
+
+typedef TAILQ_HEAD(regnode_list, regnode) regnode_list_t;
+typedef TAILQ_HEAD(regulator_list, regulator) regulator_list_t;
+
+/* Default regulator methods. */
+static int regnode_method_enable(struct regnode *regnode, bool enable,
+ int *udelay);
+static int regnode_method_status(struct regnode *regnode, int *status);
+static int regnode_method_set_voltage(struct regnode *regnode, int min_uvolt,
+ int max_uvolt, int *udelay);
+static int regnode_method_get_voltage(struct regnode *regnode, int *uvolt);
+
+/*
+ * Regulator controller methods.
+ */
+static regnode_method_t regnode_methods[] = {
+ REGNODEMETHOD(regnode_enable, regnode_method_enable),
+ REGNODEMETHOD(regnode_status, regnode_method_status),
+ REGNODEMETHOD(regnode_set_voltage, regnode_method_set_voltage),
+ REGNODEMETHOD(regnode_get_voltage, regnode_method_get_voltage),
+
+ REGNODEMETHOD_END
+};
+DEFINE_CLASS_0(regnode, regnode_class, regnode_methods, 0);
+
+/*
+ * Regulator node - basic element for modelling SOC and bard power supply
+ * chains. Its contains producer data.
+ */
+struct regnode {
+ KOBJ_FIELDS;
+
+ TAILQ_ENTRY(regnode) reglist_link; /* Global list entry */
+ regulator_list_t consumers_list; /* Consumers list */
+
+ /* Cache for already resolved names */
+ struct regnode *parent; /* Resolved parent */
+
+ /* Details of this device. */
+ const char *name; /* Globally unique name */
+ const char *parent_name; /* Parent name */
+
+ device_t pdev; /* Producer device_t */
+ void *softc; /* Producer softc */
+ intptr_t id; /* Per producer unique id */
+#ifdef FDT
+ phandle_t ofw_node; /* OFW node of regulator */
+#endif
+ int flags; /* REGULATOR_FLAGS_ */
+ struct sx lock; /* Lock for this regulator */
+ int ref_cnt; /* Reference counter */
+ int enable_cnt; /* Enabled counter */
+
+ struct regnode_std_param std_param; /* Standard parameters */
+};
+
+/*
+ * Per consumer data, information about how a consumer is using a regulator
+ * node.
+ * A pointer to this structure is used as a handle in the consumer interface.
+ */
+struct regulator {
+ device_t cdev; /* Consumer device */
+ struct regnode *regnode;
+ TAILQ_ENTRY(regulator) link; /* Consumers list entry */
+
+ int enable_cnt;
+ int min_uvolt; /* Requested uvolt range */
+ int max_uvolt;
+};
+
+/*
+ * Regulator names must be system wide unique.
+ */
+static regnode_list_t regnode_list = TAILQ_HEAD_INITIALIZER(regnode_list);
+
+static struct sx regnode_topo_lock;
+SX_SYSINIT(regulator_topology, &regnode_topo_lock, "Regulator topology lock");
+
+#define REG_TOPO_SLOCK() sx_slock(&regnode_topo_lock)
+#define REG_TOPO_XLOCK() sx_xlock(&regnode_topo_lock)
+#define REG_TOPO_UNLOCK() sx_unlock(&regnode_topo_lock)
+#define REG_TOPO_ASSERT() sx_assert(&regnode_topo_lock, SA_LOCKED)
+#define REG_TOPO_XASSERT() sx_assert(&regnode_topo_lock, SA_XLOCKED)
+
+#define REGNODE_SLOCK(_sc) sx_slock(&((_sc)->lock))
+#define REGNODE_XLOCK(_sc) sx_xlock(&((_sc)->lock))
+#define REGNODE_UNLOCK(_sc) sx_unlock(&((_sc)->lock))
+
+/* ----------------------------------------------------------------------------
+ *
+ * Default regulator methods for base class.
+ *
+ */
+static int
+regnode_method_enable(struct regnode *regnode, bool enable, int *udelay)
+{
+
+ if (!enable)
+ return (ENXIO);
+
+ *udelay = 0;
+ return (0);
+}
+
+static int
+regnode_method_status(struct regnode *regnode, int *status)
+{
+ *status = REGULATOR_STATUS_ENABLED;
+ return (0);
+}
+
+static int
+regnode_method_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt,
+ int *udelay)
+{
+
+ if ((min_uvolt > regnode->std_param.max_uvolt) ||
+ (max_uvolt < regnode->std_param.min_uvolt))
+ return (ERANGE);
+ *udelay = 0;
+ return (0);
+}
+
+static int
+regnode_method_get_voltage(struct regnode *regnode, int *uvolt)
+{
+
+ return (regnode->std_param.min_uvolt +
+ (regnode->std_param.max_uvolt - regnode->std_param.min_uvolt) / 2);
+}
+
+/* ----------------------------------------------------------------------------
+ *
+ * Internal functions.
+ *
+ */
+
+static struct regnode *
+regnode_find_by_name(const char *name)
+{
+ struct regnode *entry;
+
+ REG_TOPO_ASSERT();
+
+ TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
+ if (strcmp(entry->name, name) == 0)
+ return (entry);
+ }
+ return (NULL);
+}
+
+static struct regnode *
+regnode_find_by_id(device_t dev, intptr_t id)
+{
+ struct regnode *entry;
+
+ REG_TOPO_ASSERT();
+
+ TAILQ_FOREACH(entry, &regnode_list, reglist_link) {
+ if ((entry->pdev == dev) && (entry->id == id))
+ return (entry);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Create and initialize regulator object, but do not register it.
+ */
+struct regnode *
+regnode_create(device_t pdev, regnode_class_t regnode_class,
+ struct regnode_init_def *def)
+{
+ struct regnode *regnode;
+
+ KASSERT(def->name != NULL, ("regulator name is NULL"));
+ KASSERT(def->name[0] != '\0', ("regulator name is empty"));
+
+ REG_TOPO_SLOCK();
+ if (regnode_find_by_name(def->name) != NULL)
+ panic("Duplicated regulator registration: %s\n", def->name);
+ REG_TOPO_UNLOCK();
+
+ /* Create object and initialize it. */
+ regnode = malloc(sizeof(struct regnode), M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ kobj_init((kobj_t)regnode, (kobj_class_t)regnode_class);
+ sx_init(&regnode->lock, "Regulator node lock");
+
+ /* Allocate softc if required. */
+ if (regnode_class->size > 0) {
+ regnode->softc = malloc(regnode_class->size, M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ }
+
+
+ /* Copy all strings unless they're flagged as static. */
+ if (def->flags & REGULATOR_FLAGS_STATIC) {
+ regnode->name = def->name;
+ regnode->parent_name = def->parent_name;
+ } else {
+ regnode->name = strdup(def->name, M_REGULATOR);
+ if (def->parent_name != NULL)
+ regnode->parent_name = strdup(def->parent_name,
+ M_REGULATOR);
+ }
+
+ /* Rest of init. */
+ TAILQ_INIT(&regnode->consumers_list);
+ regnode->id = def->id;
+ regnode->pdev = pdev;
+ regnode->flags = def->flags;
+ regnode->parent = NULL;
+ regnode->std_param = def->std_param;
+#ifdef FDT
+ regnode->ofw_node = def->ofw_node;
+#endif
+
+ return (regnode);
+}
+
+/* Register regulator object. */
+struct regnode *
+regnode_register(struct regnode *regnode)
+{
+ int rv;
+
+#ifdef FDT
+ if (regnode->ofw_node <= 0)
+ regnode->ofw_node = ofw_bus_get_node(regnode->pdev);
+ if (regnode->ofw_node <= 0)
+ return (NULL);
+#endif
+
+ rv = REGNODE_INIT(regnode);
+ if (rv != 0) {
+ printf("REGNODE_INIT failed: %d\n", rv);
+ return (NULL);
+ }
+
+ REG_TOPO_XLOCK();
+ TAILQ_INSERT_TAIL(&regnode_list, regnode, reglist_link);
+ REG_TOPO_UNLOCK();
+#ifdef FDT
+ OF_device_register_xref(OF_xref_from_node(regnode->ofw_node),
+ regnode->pdev);
+#endif
+ return (regnode);
+}
+
+static int
+regnode_resolve_parent(struct regnode *regnode)
+{
+
+ /* All ready resolved or no parent? */
+ if ((regnode->parent != NULL) ||
+ (regnode->parent_name == NULL))
+ return (0);
+
+ regnode->parent = regnode_find_by_name(regnode->parent_name);
+ if (regnode->parent == NULL)
+ return (ENODEV);
+ return (0);
+}
+
+static void
+regnode_delay(int usec)
+{
+ int ticks;
+
+ if (usec == 0)
+ return;
+ ticks = (usec * hz + 999999) / 1000000;
+
+ if (cold || ticks < 2)
+ DELAY(usec);
+ else
+ pause("REGULATOR", ticks);
+}
+
+/* --------------------------------------------------------------------------
+ *
+ * Regulator providers interface
+ *
+ */
+
+const char *
+regnode_get_name(struct regnode *regnode)
+{
+
+ return (regnode->name);
+}
+
+const char *
+regnode_get_parent_name(struct regnode *regnode)
+{
+
+ return (regnode->parent_name);
+}
+
+int
+regnode_get_flags(struct regnode *regnode)
+{
+
+ return (regnode->flags);
+}
+
+void *
+regnode_get_softc(struct regnode *regnode)
+{
+
+ return (regnode->softc);
+}
+
+device_t
+regnode_get_device(struct regnode *regnode)
+{
+
+ return (regnode->pdev);
+}
+
+struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode)
+{
+
+ return (&regnode->std_param);
+}
+
+void regnode_topo_unlock(void)
+{
+
+ REG_TOPO_UNLOCK();
+}
+
+void regnode_topo_xlock(void)
+{
+
+ REG_TOPO_XLOCK();
+}
+
+void regnode_topo_slock(void)
+{
+
+ REG_TOPO_SLOCK();
+}
+
+
+/* --------------------------------------------------------------------------
+ *
+ * Real consumers executive
+ *
+ */
+struct regnode *
+regnode_get_parent(struct regnode *regnode)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (NULL);
+
+ return (regnode->parent);
+}
+
+/*
+ * Enable regulator.
+ */
+int
+regnode_enable(struct regnode *regnode)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ /* Enable regulator for each node in chain, starting from source. */
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL) {
+ rv = regnode_enable(regnode->parent);
+ if (rv != 0)
+ return (rv);
+ }
+
+ /* Handle this node. */
+ REGNODE_XLOCK(regnode);
+ if (regnode->enable_cnt == 0) {
+ rv = REGNODE_ENABLE(regnode, true, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ regnode->enable_cnt++;
+ REGNODE_UNLOCK(regnode);
+ return (0);
+}
+
+/*
+ * Disable regulator.
+ */
+int
+regnode_disable(struct regnode *regnode)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+ rv = 0;
+
+ REGNODE_XLOCK(regnode);
+ /* Disable regulator for each node in chain, starting from consumer. */
+ if ((regnode->enable_cnt == 1) &&
+ ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
+ rv = REGNODE_ENABLE(regnode, false, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ regnode->enable_cnt--;
+ REGNODE_UNLOCK(regnode);
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_disable(regnode->parent);
+ return (rv);
+}
+
+/*
+ * Stop regulator.
+ */
+int
+regnode_stop(struct regnode *regnode, int depth)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+ rv = 0;
+
+ REGNODE_XLOCK(regnode);
+ /* The first node must not be enabled. */
+ if ((regnode->enable_cnt != 0) && (depth == 0)) {
+ REGNODE_UNLOCK(regnode);
+ return (EBUSY);
+ }
+ /* Disable regulator for each node in chain, starting from consumer */
+ if ((regnode->enable_cnt == 0) &&
+ ((regnode->flags & REGULATOR_FLAGS_NOT_DISABLE) == 0)) {
+ rv = REGNODE_ENABLE(regnode, false, &udelay);
+ if (rv != 0) {
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+ }
+ regnode_delay(udelay);
+ }
+ REGNODE_UNLOCK(regnode);
+
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_stop(regnode->parent, depth + 1);
+ return (rv);
+}
+
+/*
+ * Get regulator status. (REGULATOR_STATUS_*)
+ */
+int
+regnode_status(struct regnode *regnode, int *status)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ rv = REGNODE_STATUS(regnode, status);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+/*
+ * Get actual regulator voltage.
+ */
+int
+regnode_get_voltage(struct regnode *regnode, int *uvolt)
+{
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ rv = REGNODE_GET_VOLTAGE(regnode, uvolt);
+ REGNODE_UNLOCK(regnode);
+
+ /* Pass call into parent, if regulator is in bypass mode. */
+ if (rv == ENOENT) {
+ rv = regnode_resolve_parent(regnode);
+ if (rv != 0)
+ return (rv);
+ if (regnode->parent != NULL)
+ rv = regnode_get_voltage(regnode->parent, uvolt);
+
+ }
+ return (rv);
+}
+
+/*
+ * Set regulator voltage.
+ */
+int
+regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt)
+{
+ int udelay;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+
+ rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
+ if (rv == 0)
+ regnode_delay(udelay);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+/*
+ * Consumer variant of regnode_set_voltage().
+ */
+static int
+regnode_set_voltage_checked(struct regnode *regnode, struct regulator *reg,
+ int min_uvolt, int max_uvolt)
+{
+ int udelay;
+ int all_max_uvolt;
+ int all_min_uvolt;
+ struct regulator *tmp;
+ int rv;
+
+ REG_TOPO_ASSERT();
+
+ REGNODE_XLOCK(regnode);
+ /* Return error if requested range is outside of regulator range. */
+ if ((min_uvolt > regnode->std_param.max_uvolt) ||
+ (max_uvolt < regnode->std_param.min_uvolt)) {
+ REGNODE_UNLOCK(regnode);
+ return (ERANGE);
+ }
+
+ /* Get actual voltage range for all consumers. */
+ all_min_uvolt = regnode->std_param.min_uvolt;
+ all_max_uvolt = regnode->std_param.max_uvolt;
+ TAILQ_FOREACH(tmp, &regnode->consumers_list, link) {
+ /* Don't take requestor in account. */
+ if (tmp == reg)
+ continue;
+ if (all_min_uvolt < tmp->min_uvolt)
+ all_min_uvolt = tmp->min_uvolt;
+ if (all_max_uvolt > tmp->max_uvolt)
+ all_max_uvolt = tmp->max_uvolt;
+ }
+
+ /* Test if request fits to actual contract. */
+ if ((min_uvolt > all_max_uvolt) ||
+ (max_uvolt < all_min_uvolt)) {
+ REGNODE_UNLOCK(regnode);
+ return (ERANGE);
+ }
+
+ /* Adjust new range.*/
+ if (min_uvolt < all_min_uvolt)
+ min_uvolt = all_min_uvolt;
+ if (max_uvolt > all_max_uvolt)
+ max_uvolt = all_max_uvolt;
+
+ rv = REGNODE_SET_VOLTAGE(regnode, min_uvolt, max_uvolt, &udelay);
+ regnode_delay(udelay);
+ REGNODE_UNLOCK(regnode);
+ return (rv);
+}
+
+#ifdef FDT
+phandle_t
+regnode_get_ofw_node(struct regnode *regnode)
+{
+
+ return (regnode->ofw_node);
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ *
+ * Regulator consumers interface.
+ *
+ */
+/* Helper function for regulator_get*() */
+static regulator_t
+regulator_create(struct regnode *regnode, device_t cdev)
+{
+ struct regulator *reg;
+
+ REG_TOPO_ASSERT();
+
+ reg = malloc(sizeof(struct regulator), M_REGULATOR,
+ M_WAITOK | M_ZERO);
+ reg->cdev = cdev;
+ reg->regnode = regnode;
+ reg->enable_cnt = 0;
+
+ REGNODE_XLOCK(regnode);
+ regnode->ref_cnt++;
+ TAILQ_INSERT_TAIL(&regnode->consumers_list, reg, link);
+ reg ->min_uvolt = regnode->std_param.min_uvolt;
+ reg ->max_uvolt = regnode->std_param.max_uvolt;
+ REGNODE_UNLOCK(regnode);
+
+ return (reg);
+}
+
+int
+regulator_enable(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ REG_TOPO_SLOCK();
+ rv = regnode_enable(regnode);
+ if (rv == 0)
+ reg->enable_cnt++;
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_disable(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ KASSERT(reg->enable_cnt > 0,
+ ("Attempt to disable already disabled regulator: %s\n",
+ regnode->name));
+ REG_TOPO_SLOCK();
+ rv = regnode_disable(regnode);
+ if (rv == 0)
+ reg->enable_cnt--;
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_stop(regulator_t reg)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ KASSERT(reg->enable_cnt == 0,
+ ("Attempt to stop already enabled regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_stop(regnode, 0);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_status(regulator_t reg, int *status)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_status(regnode, status);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_get_voltage(regulator_t reg, int *uvolt)
+{
+ int rv;
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+ rv = regnode_get_voltage(regnode, uvolt);
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+int
+regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt)
+{
+ struct regnode *regnode;
+ int rv;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+
+ REG_TOPO_SLOCK();
+
+ rv = regnode_set_voltage_checked(regnode, reg, min_uvolt, max_uvolt);
+ if (rv == 0) {
+ reg->min_uvolt = min_uvolt;
+ reg->max_uvolt = max_uvolt;
+ }
+ REG_TOPO_UNLOCK();
+ return (rv);
+}
+
+const char *
+regulator_get_name(regulator_t reg)
+{
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ return (regnode->name);
+}
+
+int
+regulator_get_by_name(device_t cdev, const char *name, regulator_t *reg)
+{
+ struct regnode *regnode;
+
+ REG_TOPO_SLOCK();
+ regnode = regnode_find_by_name(name);
+ if (regnode == NULL) {
+ REG_TOPO_UNLOCK();
+ return (ENODEV);
+ }
+ *reg = regulator_create(regnode, cdev);
+ REG_TOPO_UNLOCK();
+ return (0);
+}
+
+int
+regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id, regulator_t *reg)
+{
+ struct regnode *regnode;
+
+ REG_TOPO_SLOCK();
+
+ regnode = regnode_find_by_id(pdev, id);
+ if (regnode == NULL) {
+ REG_TOPO_UNLOCK();
+ return (ENODEV);
+ }
+ *reg = regulator_create(regnode, cdev);
+ REG_TOPO_UNLOCK();
+
+ return (0);
+}
+
+int
+regulator_release(regulator_t reg)
+{
+ struct regnode *regnode;
+
+ regnode = reg->regnode;
+ KASSERT(regnode->ref_cnt > 0,
+ ("Attempt to access unreferenced regulator: %s\n", regnode->name));
+ REG_TOPO_SLOCK();
+ while (reg->enable_cnt > 0) {
+ regnode_disable(regnode);
+ reg->enable_cnt--;
+ }
+ REGNODE_XLOCK(regnode);
+ TAILQ_REMOVE(&regnode->consumers_list, reg, link);
+ regnode->ref_cnt--;
+ REGNODE_UNLOCK(regnode);
+ REG_TOPO_UNLOCK();
+
+ free(reg, M_REGULATOR);
+ return (0);
+}
+
+#ifdef FDT
+/* Default DT mapper. */
+int
+regdev_default_ofw_map(device_t dev, phandle_t xref, int ncells,
+ pcell_t *cells, intptr_t *id)
+{
+ if (ncells == 0)
+ *id = 1;
+ else if (ncells == 1)
+ *id = cells[0];
+ else
+ return (ERANGE);
+
+ return (0);
+}
+
+int
+regulator_parse_ofw_stdparam(device_t pdev, phandle_t node,
+ struct regnode_init_def *def)
+{
+ phandle_t supply_xref;
+ struct regnode_std_param *par;
+ int rv;
+
+ par = &def->std_param;
+ rv = OF_getprop_alloc(node, "regulator-name", 1,
+ (void **)&def->name);
+ if (rv <= 0) {
+ device_printf(pdev, "%s: Missing regulator name\n",
+ __func__);
+ return (ENXIO);
+ }
+
+ rv = OF_getencprop(node, "regulator-min-microvolt", &par->min_uvolt,
+ sizeof(par->min_uvolt));
+ if (rv <= 0)
+ par->min_uvolt = 0;
+
+ rv = OF_getencprop(node, "regulator-max-microvolt", &par->max_uvolt,
+ sizeof(par->max_uvolt));
+ if (rv <= 0)
+ par->max_uvolt = 0;
+
+ rv = OF_getencprop(node, "regulator-min-microamp", &par->min_uamp,
+ sizeof(par->min_uamp));
+ if (rv <= 0)
+ par->min_uamp = 0;
+
+ rv = OF_getencprop(node, "regulator-max-microamp", &par->max_uamp,
+ sizeof(par->max_uamp));
+ if (rv <= 0)
+ par->max_uamp = 0;
+
+ rv = OF_getencprop(node, "regulator-ramp-delay", &par->ramp_delay,
+ sizeof(par->ramp_delay));
+ if (rv <= 0)
+ par->ramp_delay = 0;
+
+ rv = OF_getencprop(node, "regulator-enable-ramp-delay",
+ &par->enable_delay, sizeof(par->enable_delay));
+ if (rv <= 0)
+ par->enable_delay = 0;
+
+ if (OF_hasprop(node, "regulator-boot-on"))
+ par->boot_on = 1;
+
+ if (OF_hasprop(node, "regulator-always-on"))
+ par->always_on = 1;
+
+ if (OF_hasprop(node, "enable-active-high"))
+ par->enable_active_high = 1;
+
+ rv = OF_getencprop(node, "vin-supply", &supply_xref,
+ sizeof(supply_xref));
+ if (rv >= 0) {
+ rv = OF_getprop_alloc(supply_xref, "regulator-name", 1,
+ (void **)&def->parent_name);
+ if (rv <= 0)
+ def->parent_name = NULL;
+ }
+ return (0);
+}
+
+int
+regulator_get_by_ofw_property(device_t cdev, char *name, regulator_t *reg)
+{
+ phandle_t cnode, *cells;
+ device_t regdev;
+ int ncells, rv;
+ intptr_t id;
+
+ *reg = NULL;
+
+ cnode = ofw_bus_get_node(cdev);
+ if (cnode <= 0) {
+ device_printf(cdev, "%s called on not ofw based device\n",
+ __func__);
+ return (ENXIO);
+ }
+
+ cells = NULL;
+ ncells = OF_getencprop_alloc(cnode, name, sizeof(*cells),
+ (void **)&cells);
+ if (ncells <= 0)
+ return (ENXIO);
+
+ /* Translate xref to device */
+ regdev = OF_device_from_xref(cells[0]);
+ if (regdev == NULL) {
+ free(cells, M_OFWPROP);
+ return (ENODEV);
+ }
+
+ /* Map regulator to number */
+ rv = REGDEV_MAP(regdev, cells[0], ncells - 1, cells + 1, &id);
+ free(cells, M_OFWPROP);
+ if (rv != 0)
+ return (rv);
+ return (regulator_get_by_id(cdev, regdev, id, reg));
+}
+#endif
diff --git a/sys/dev/extres/regulator/regulator.h b/sys/dev/extres/regulator/regulator.h
new file mode 100644
index 0000000..380bad6
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator.h
@@ -0,0 +1,127 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_EXTRES_REGULATOR_H_
+#define _DEV_EXTRES_REGULATOR_H_
+#include "opt_platform.h"
+
+#include <sys/kobj.h>
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#endif
+#include "regnode_if.h"
+
+#define REGULATOR_FLAGS_STATIC 0x00000001 /* Static strings */
+#define REGULATOR_FLAGS_NOT_DISABLE 0x00000002 /* Cannot be disabled */
+
+#define REGULATOR_STATUS_ENABLED 0x00000001
+#define REGULATOR_STATUS_OVERCURRENT 0x00000002
+
+typedef struct regulator *regulator_t;
+
+/* Standard regulator parameters. */
+struct regnode_std_param {
+ int min_uvolt; /* In uV */
+ int max_uvolt; /* In uV */
+ int min_uamp; /* In uA */
+ int max_uamp; /* In uA */
+ int ramp_delay; /* In uV/usec */
+ int enable_delay; /* In usec */
+ bool boot_on; /* Is enabled on boot */
+ bool always_on; /* Must be enabled */
+ int enable_active_high;
+};
+
+/* Initialization parameters. */
+struct regnode_init_def {
+ char *name; /* Regulator name */
+ char *parent_name; /* Name of parent regulator */
+ struct regnode_std_param std_param; /* Standard parameters */
+ intptr_t id; /* Regulator ID */
+ int flags; /* Flags */
+#ifdef FDT
+ phandle_t ofw_node; /* OFW node of regulator */
+#endif
+
+};
+
+/*
+ * Shorthands for constructing method tables.
+ */
+#define REGNODEMETHOD KOBJMETHOD
+#define REGNODEMETHOD_END KOBJMETHOD_END
+#define regnode_method_t kobj_method_t
+#define regnode_class_t kobj_class_t
+DECLARE_CLASS(regnode_class);
+
+/* Providers interface. */
+struct regnode *regnode_create(device_t pdev, regnode_class_t regnode_class,
+ struct regnode_init_def *def);
+struct regnode *regnode_register(struct regnode *regnode);
+const char *regnode_get_name(struct regnode *regnode);
+const char *regnode_get_parent_name(struct regnode *regnode);
+struct regnode *regnode_get_parent(struct regnode *regnode);
+int regnode_get_flags(struct regnode *regnode);
+void *regnode_get_softc(struct regnode *regnode);
+device_t regnode_get_device(struct regnode *regnode);
+struct regnode_std_param *regnode_get_stdparam(struct regnode *regnode);
+void regnode_topo_unlock(void);
+void regnode_topo_xlock(void);
+void regnode_topo_slock(void);
+
+int regnode_enable(struct regnode *regnode);
+int regnode_disable(struct regnode *regnode);
+int regnode_stop(struct regnode *regnode, int depth);
+int regnode_status(struct regnode *regnode, int *status);
+int regnode_get_voltage(struct regnode *regnode, int *uvolt);
+int regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt);
+#ifdef FDT
+phandle_t regnode_get_ofw_node(struct regnode *regnode);
+#endif
+
+/* Consumers interface. */
+int regulator_get_by_name(device_t cdev, const char *name,
+ regulator_t *regulator);
+int regulator_get_by_id(device_t cdev, device_t pdev, intptr_t id,
+ regulator_t *regulator);
+int regulator_release(regulator_t regulator);
+const char *regulator_get_name(regulator_t regulator);
+int regulator_enable(regulator_t reg);
+int regulator_disable(regulator_t reg);
+int regulator_stop(regulator_t reg);
+int regulator_status(regulator_t reg, int *status);
+int regulator_get_voltage(regulator_t reg, int *uvolt);
+int regulator_set_voltage(regulator_t reg, int min_uvolt, int max_uvolt);
+
+#ifdef FDT
+int regulator_get_by_ofw_property(device_t dev, char *name, regulator_t *reg);
+int regulator_parse_ofw_stdparam(device_t dev, phandle_t node,
+ struct regnode_init_def *def);
+#endif
+
+#endif /* _DEV_EXTRES_REGULATOR_H_ */
diff --git a/sys/dev/extres/regulator/regulator_bus.c b/sys/dev/extres/regulator/regulator_bus.c
new file mode 100644
index 0000000..5e7f4c9
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator_bus.c
@@ -0,0 +1,89 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+struct ofw_regulator_bus_softc {
+ struct simplebus_softc simplebus_sc;
+};
+
+static int
+ofw_regulator_bus_probe(device_t dev)
+{
+ const char *name;
+
+ name = ofw_bus_get_name(dev);
+ if (name == NULL || strcmp(name, "regulators") != 0)
+ return (ENXIO);
+ device_set_desc(dev, "OFW regulators bus");
+
+ return (0);
+}
+
+static int
+ofw_regulator_bus_attach(device_t dev)
+{
+ struct ofw_regulator_bus_softc *sc;
+ phandle_t node, child;
+
+ sc = device_get_softc(dev);
+ node = ofw_bus_get_node(dev);
+ simplebus_init(dev, node);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ simplebus_add_device(dev, child, 0, NULL, -1, NULL);
+ }
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t ofw_regulator_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ofw_regulator_bus_probe),
+ DEVMETHOD(device_attach, ofw_regulator_bus_attach),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(ofw_regulator_bus, ofw_regulator_bus_driver,
+ ofw_regulator_bus_methods, sizeof(struct ofw_regulator_bus_softc),
+ simplebus_driver);
+static devclass_t ofw_regulator_bus_devclass;
+EARLY_DRIVER_MODULE(ofw_regulator_bus, simplebus, ofw_regulator_bus_driver,
+ ofw_regulator_bus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
+MODULE_VERSION(ofw_regulator_bus, 1);
diff --git a/sys/dev/extres/regulator/regulator_fixed.c b/sys/dev/extres/regulator/regulator_fixed.c
new file mode 100644
index 0000000..5a44a72
--- /dev/null
+++ b/sys/dev/extres/regulator/regulator_fixed.c
@@ -0,0 +1,456 @@
+/*-
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#endif
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/extres/regulator/regulator_fixed.h>
+
+#include "regdev_if.h"
+
+MALLOC_DEFINE(M_FIXEDREGULATOR, "fixedregulator", "Fixed regulator");
+
+/* GPIO list for shared pins. */
+typedef TAILQ_HEAD(gpio_list, gpio_entry) gpio_list_t;
+struct gpio_entry {
+ TAILQ_ENTRY(gpio_entry) link;
+ struct gpiobus_pin gpio_pin;
+ int use_cnt;
+ int enable_cnt;
+};
+static gpio_list_t gpio_list = TAILQ_HEAD_INITIALIZER(gpio_list);
+static struct mtx gpio_list_mtx;
+MTX_SYSINIT(gpio_list_lock, &gpio_list_mtx, "Regulator GPIO lock", MTX_DEF);
+
+struct regnode_fixed_sc {
+ struct regnode_std_param *param;
+ bool gpio_open_drain;
+ struct gpio_entry *gpio_entry;
+};
+
+static int regnode_fixed_init(struct regnode *regnode);
+static int regnode_fixed_enable(struct regnode *regnode, bool enable,
+ int *udelay);
+static int regnode_fixed_status(struct regnode *regnode, int *status);
+
+static regnode_method_t regnode_fixed_methods[] = {
+ /* Regulator interface */
+ REGNODEMETHOD(regnode_init, regnode_fixed_init),
+ REGNODEMETHOD(regnode_enable, regnode_fixed_enable),
+ REGNODEMETHOD(regnode_status, regnode_fixed_status),
+ REGNODEMETHOD_END
+};
+DEFINE_CLASS_1(regnode_fixed, regnode_fixed_class, regnode_fixed_methods,
+ sizeof(struct regnode_fixed_sc), regnode_class);
+
+/*
+ * GPIO list functions.
+ * Two or more regulators can share single GPIO pins, so we must track all
+ * GPIOs in gpio_list.
+ * The GPIO pin is registerd and reseved for first consumer, all others share
+ * gpio_entry with it.
+ */
+static struct gpio_entry *
+regnode_get_gpio_entry(struct gpiobus_pin *gpio_pin)
+{
+ struct gpio_entry *entry, *tmp;
+ device_t busdev;
+ int rv;
+
+ busdev = GPIO_GET_BUS(gpio_pin->dev);
+ if (busdev == NULL)
+ return (NULL);
+ entry = malloc(sizeof(struct gpio_entry), M_FIXEDREGULATOR,
+ M_WAITOK | M_ZERO);
+
+ mtx_lock(&gpio_list_mtx);
+
+ TAILQ_FOREACH(tmp, &gpio_list, link) {
+ if (tmp->gpio_pin.dev == gpio_pin->dev &&
+ tmp->gpio_pin.pin == gpio_pin->pin) {
+ tmp->use_cnt++;
+ mtx_unlock(&gpio_list_mtx);
+ free(entry, M_FIXEDREGULATOR);
+ return (tmp);
+ }
+ }
+
+ /* Reserve pin. */
+ /* XXX Can we call gpiobus_map_pin() with gpio_list_mtx mutex held? */
+ rv = gpiobus_map_pin(busdev, gpio_pin->pin);
+ if (rv != 0) {
+ mtx_unlock(&gpio_list_mtx);
+ free(entry, M_FIXEDREGULATOR);
+ return (NULL);
+ }
+ /* Everything is OK, build new entry and insert it to list. */
+ entry->gpio_pin = *gpio_pin;
+ entry->use_cnt = 1;
+ TAILQ_INSERT_TAIL(&gpio_list, entry, link);
+
+ mtx_unlock(&gpio_list_mtx);
+ return (entry);
+}
+
+
+/*
+ * Regulator class implementation.
+ */
+static int
+regnode_fixed_init(struct regnode *regnode)
+{
+ device_t dev;
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ uint32_t flags;
+ bool enable;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+ dev = regnode_get_device(regnode);
+ sc->param = regnode_get_stdparam(regnode);
+ if (sc->gpio_entry == NULL)
+ return (0);
+ pin = &sc->gpio_entry->gpio_pin;
+
+ flags = GPIO_PIN_OUTPUT;
+ if (sc->gpio_open_drain)
+ flags |= GPIO_PIN_OPENDRAIN;
+ enable = sc->param->boot_on || sc->param->always_on;
+ if (!sc->param->enable_active_high)
+ enable = !enable;
+ rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+ rv = GPIO_PIN_SETFLAGS(pin->dev, pin->pin, flags);
+ if (rv != 0) {
+ device_printf(dev, "Cannot configure GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+
+ return (0);
+}
+
+/*
+ * Enable/disable regulator.
+ * Take shared GPIO pins in account
+ */
+static int
+regnode_fixed_enable(struct regnode *regnode, bool enable, int *udelay)
+{
+ device_t dev;
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+ dev = regnode_get_device(regnode);
+
+ *udelay = 0;
+ if (sc->param->always_on && !enable)
+ return (0);
+ if (sc->gpio_entry == NULL)
+ return (0);
+ pin = &sc->gpio_entry->gpio_pin;
+ if (enable) {
+ sc->gpio_entry->enable_cnt++;
+ if (sc->gpio_entry->enable_cnt > 1)
+ return (0);
+ } else {
+ KASSERT(sc->gpio_entry->enable_cnt > 0,
+ ("Invalid enable count"));
+ sc->gpio_entry->enable_cnt--;
+ if (sc->gpio_entry->enable_cnt >= 1)
+ return (0);
+ }
+ if (!sc->param->enable_active_high)
+ enable = !enable;
+ rv = GPIO_PIN_SET(pin->dev, pin->pin, enable);
+ if (rv != 0) {
+ device_printf(dev, "Cannot set GPIO pin: %d\n", pin->pin);
+ return (rv);
+ }
+ *udelay = sc->param->enable_delay;
+ return (0);
+}
+
+static int
+regnode_fixed_status(struct regnode *regnode, int *status)
+{
+ struct regnode_fixed_sc *sc;
+ struct gpiobus_pin *pin;
+ uint32_t val;
+ int rv;
+
+ sc = regnode_get_softc(regnode);
+
+ *status = 0;
+ if (sc->gpio_entry == NULL) {
+ *status = REGULATOR_STATUS_ENABLED;
+ return (0);
+ }
+ pin = &sc->gpio_entry->gpio_pin;
+
+ rv = GPIO_PIN_GET(pin->dev, pin->pin, &val);
+ if (rv == 0) {
+ if (!sc->param->enable_active_high ^ (val != 0))
+ *status = REGULATOR_STATUS_ENABLED;
+ }
+ return (rv);
+}
+
+int
+regnode_fixed_register(device_t dev, struct regnode_fixed_init_def *init_def)
+{
+ struct regnode *regnode;
+ struct regnode_fixed_sc *sc;
+
+ regnode = regnode_create(dev, &regnode_fixed_class,
+ &init_def->reg_init_def);
+ if (regnode == NULL) {
+ device_printf(dev, "Cannot create regulator.\n");
+ return(ENXIO);
+ }
+ sc = regnode_get_softc(regnode);
+ sc->gpio_open_drain = init_def->gpio_open_drain;
+ if (init_def->gpio_pin != NULL) {
+ sc->gpio_entry = regnode_get_gpio_entry(init_def->gpio_pin);
+ if (sc->gpio_entry == NULL)
+ return(ENXIO);
+ }
+ regnode = regnode_register(regnode);
+ if (regnode == NULL) {
+ device_printf(dev, "Cannot register regulator.\n");
+ return(ENXIO);
+ }
+ return (0);
+}
+
+/*
+ * OFW Driver implementation.
+ */
+#ifdef FDT
+
+struct regfix_softc
+{
+ device_t dev;
+ bool attach_done;
+ struct regnode_fixed_init_def init_def;
+ phandle_t gpio_prodxref;
+ pcell_t *gpio_cells;
+ int gpio_ncells;
+ struct gpiobus_pin gpio_pin;
+};
+
+static struct ofw_compat_data compat_data[] = {
+ {"regulator-fixed", 1},
+ {NULL, 0},
+};
+
+static int
+regfix_get_gpio(struct regfix_softc * sc)
+{
+ device_t busdev;
+ phandle_t node;
+
+ int rv;
+
+ if (sc->gpio_prodxref == 0)
+ return (0);
+
+ node = ofw_bus_get_node(sc->dev);
+
+ /* Test if controller exist. */
+ sc->gpio_pin.dev = OF_device_from_xref(sc->gpio_prodxref);
+ if (sc->gpio_pin.dev == NULL)
+ return (ENODEV);
+
+ /* Test if GPIO bus already exist. */
+ busdev = GPIO_GET_BUS(sc->gpio_pin.dev);
+ if (busdev == NULL)
+ return (ENODEV);
+
+ rv = gpio_map_gpios(sc->gpio_pin.dev, node,
+ OF_node_from_xref(sc->gpio_prodxref), sc->gpio_ncells,
+ sc->gpio_cells, &(sc->gpio_pin.pin), &(sc->gpio_pin.flags));
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot map the gpio property.\n");
+ return (ENXIO);
+ }
+ sc->init_def.gpio_pin = &sc->gpio_pin;
+ return (0);
+}
+
+static int
+regfix_parse_fdt(struct regfix_softc * sc)
+{
+ phandle_t node;
+ int rv;
+ struct regnode_init_def *init_def;
+
+ node = ofw_bus_get_node(sc->dev);
+ init_def = &sc->init_def.reg_init_def;
+
+ rv = regulator_parse_ofw_stdparam(sc->dev, node, init_def);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot parse standard parameters.\n");
+ return(rv);
+ }
+
+ /* Fixed regulator uses 'startup-delay-us' property for enable_delay */
+ rv = OF_getencprop(node, "startup-delay-us",
+ &init_def->std_param.enable_delay,
+ sizeof(init_def->std_param.enable_delay));
+ if (rv <= 0)
+ init_def->std_param.enable_delay = 0;
+ /* GPIO pin */
+ if (OF_hasprop(node, "gpio-open-drain"))
+ sc->init_def.gpio_open_drain = true;
+
+ if (!OF_hasprop(node, "gpio"))
+ return (0);
+ rv = ofw_bus_parse_xref_list_alloc(node, "gpio", "#gpio-cells", 0,
+ &sc->gpio_prodxref, &sc->gpio_ncells, &sc->gpio_cells);
+ if (rv != 0) {
+ sc->gpio_prodxref = 0;
+ device_printf(sc->dev, "Malformed gpio property\n");
+ return (ENXIO);
+ }
+ return (0);
+}
+
+static void
+regfix_new_pass(device_t dev)
+{
+ struct regfix_softc * sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ bus_generic_new_pass(dev);
+
+ if (sc->attach_done)
+ return;
+
+ /* Try to get and configure GPIO. */
+ rv = regfix_get_gpio(sc);
+ if (rv != 0)
+ return;
+
+ /* Register regulator. */
+ regnode_fixed_register(sc->dev, &sc->init_def);
+ sc->attach_done = true;
+}
+
+static int
+regfix_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ return (ENXIO);
+
+ device_set_desc(dev, "Fixed Regulator");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+regfix_detach(device_t dev)
+{
+
+ /* This device is always present. */
+ return (EBUSY);
+}
+
+static int
+regfix_attach(device_t dev)
+{
+ struct regfix_softc * sc;
+ int rv;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ /* Parse FDT data. */
+ rv = regfix_parse_fdt(sc);
+ if (rv != 0)
+ return(ENXIO);
+
+ /* Fill reset of init. */
+ sc->init_def.reg_init_def.id = 1;
+ sc->init_def.reg_init_def.flags = REGULATOR_FLAGS_STATIC;
+
+ /* Try to get and configure GPIO. */
+ rv = regfix_get_gpio(sc);
+ if (rv != 0)
+ return (bus_generic_attach(dev));
+
+ /* Register regulator. */
+ regnode_fixed_register(sc->dev, &sc->init_def);
+ sc->attach_done = true;
+
+ return (bus_generic_attach(dev));
+}
+
+static device_method_t regfix_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, regfix_probe),
+ DEVMETHOD(device_attach, regfix_attach),
+ DEVMETHOD(device_detach, regfix_detach),
+ /* Bus interface */
+ DEVMETHOD(bus_new_pass, regfix_new_pass),
+ /* Regdev interface */
+ DEVMETHOD(regdev_map, regdev_default_ofw_map),
+
+ DEVMETHOD_END
+};
+
+static devclass_t regfix_devclass;
+DEFINE_CLASS_0(regfix, regfix_driver, regfix_methods,
+ sizeof(struct regfix_softc));
+EARLY_DRIVER_MODULE(regfix, simplebus, regfix_driver,
+ regfix_devclass, 0, 0, BUS_PASS_BUS);
+
+#endif /* FDT */
diff --git a/sys/dev/filemon/filemon_lock.c b/sys/dev/extres/regulator/regulator_fixed.h
index 5cac47c..5cc0751 100644
--- a/sys/dev/filemon/filemon_lock.c
+++ b/sys/dev/extres/regulator/regulator_fixed.h
@@ -1,6 +1,5 @@
/*-
- * Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright 2016 Michal Meloun <mmel@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -12,10 +11,10 @@
* 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 JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND
+ * 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 JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE
+ * 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)
@@ -23,35 +22,23 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
+ * $FreeBSD$
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-static __inline void
-filemon_lock_read(void)
-{
-
- sx_slock(&access_lock);
-}
-
-static __inline void
-filemon_unlock_read(void)
-{
-
- sx_sunlock(&access_lock);
-}
+#ifndef _DEV_EXTRES_REGULATOR_FIXED_H_
+#define _DEV_EXTRES_REGULATOR_FIXED_H_
-static __inline void
-filemon_lock_write(void)
-{
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/extres/regulator/regulator.h>
- sx_xlock(&access_lock);
-}
+struct regnode_fixed_init_def {
+ struct regnode_init_def reg_init_def;
+ bool gpio_open_drain;
+ struct gpiobus_pin *gpio_pin;
+};
-static __inline void
-filemon_unlock_write(void)
-{
+int regnode_fixed_register(device_t dev,
+ struct regnode_fixed_init_def *init_def);
- sx_xunlock(&access_lock);
-}
+#endif /*_DEV_EXTRES_REGULATOR_FIXED_H_*/
diff --git a/sys/dev/fdt/fdt_common.c b/sys/dev/fdt/fdt_common.c
index 6211aca..73f7ada 100644
--- a/sys/dev/fdt/fdt_common.c
+++ b/sys/dev/fdt/fdt_common.c
@@ -722,3 +722,16 @@ fdt_get_unit(device_t dev)
return (strtol(name,NULL,0));
}
+
+int
+fdt_get_chosen_bootargs(char *bootargs, size_t max_size)
+{
+ phandle_t chosen;
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return (ENXIO);
+ if (OF_getprop(chosen, "bootargs", bootargs, max_size) == -1)
+ return (ENXIO);
+ return (0);
+} \ No newline at end of file
diff --git a/sys/dev/fdt/fdt_common.h b/sys/dev/fdt/fdt_common.h
index db27b43..17af344 100644
--- a/sys/dev/fdt/fdt_common.h
+++ b/sys/dev/fdt/fdt_common.h
@@ -100,5 +100,6 @@ int fdt_parent_addr_cells(phandle_t);
int fdt_reg_to_rl(phandle_t, struct resource_list *);
int fdt_pm(phandle_t);
int fdt_get_unit(device_t);
+int fdt_get_chosen_bootargs(char *bootargs, size_t max_size);
#endif /* _FDT_COMMON_H_ */
diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c
index 36c278f..8d43a70 100644
--- a/sys/dev/fdt/simplebus.c
+++ b/sys/dev/fdt/simplebus.c
@@ -369,7 +369,7 @@ simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
if (j == sc->nranges && sc->nranges != 0) {
if (bootverbose)
device_printf(bus, "Could not map resource "
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
@@ -387,8 +387,8 @@ simplebus_print_res(struct simplebus_devinfo *di)
if (di == NULL)
return (0);
rv = 0;
- rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx");
- rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld");
+ rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx");
+ rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/dev/filemon/filemon.c b/sys/dev/filemon/filemon.c
index cd40c5a..10f27ad 100644
--- a/sys/dev/filemon/filemon.c
+++ b/sys/dev/filemon/filemon.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/poll.h>
#include <sys/proc.h>
-#include <sys/queue.h>
#include <sys/sx.h>
#include <sys/syscall.h>
#include <sys/sysent.h>
@@ -80,23 +79,112 @@ static struct cdevsw filemon_cdevsw = {
MALLOC_DECLARE(M_FILEMON);
MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor");
+/*
+ * The filemon->lock protects several things currently:
+ * - fname1/fname2/msgbufr are pre-allocated and used per syscall
+ * for logging and copyins rather than stack variables.
+ * - Serializing the filemon's log output.
+ * - Preventing inheritance or removal of the filemon into proc.p_filemon.
+ */
struct filemon {
- TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */
- struct sx lock; /* Lock mutex for this filemon. */
+ struct sx lock; /* Lock for this filemon. */
struct file *fp; /* Output file pointer. */
- struct proc *p; /* The process being monitored. */
char fname1[MAXPATHLEN]; /* Temporary filename buffer. */
char fname2[MAXPATHLEN]; /* Temporary filename buffer. */
char msgbufr[1024]; /* Output message buffer. */
+ int error; /* Log write error, returned on close(2). */
+ u_int refcnt; /* Pointer reference count. */
+ u_int proccnt; /* Process count. */
};
-static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse);
-static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free);
-static struct sx access_lock;
-
static struct cdev *filemon_dev;
+static void filemon_output(struct filemon *filemon, char *msg, size_t len);
+
+static __inline struct filemon *
+filemon_acquire(struct filemon *filemon)
+{
+
+ if (filemon != NULL)
+ refcount_acquire(&filemon->refcnt);
+ return (filemon);
+}
+
+/*
+ * Release a reference and free on the last one.
+ */
+static void
+filemon_release(struct filemon *filemon)
+{
+
+ if (refcount_release(&filemon->refcnt) == 0)
+ return;
+ /*
+ * There are valid cases of releasing while locked, such as in
+ * filemon_untrack_processes, but none which are done where there
+ * is not at least 1 reference remaining.
+ */
+ sx_assert(&filemon->lock, SA_UNLOCKED);
+
+ sx_destroy(&filemon->lock);
+ free(filemon, M_FILEMON);
+}
+
+/*
+ * Acquire the proc's p_filemon reference and lock the filemon.
+ * The proc's p_filemon may not match this filemon on return.
+ */
+static struct filemon *
+filemon_proc_get(struct proc *p)
+{
+ struct filemon *filemon;
+
+ PROC_LOCK(p);
+ filemon = filemon_acquire(p->p_filemon);
+ PROC_UNLOCK(p);
+
+ if (filemon == NULL)
+ return (NULL);
+ /*
+ * The p->p_filemon may have changed by now. That case is handled
+ * by the exit and fork hooks and filemon_attach_proc specially.
+ */
+ sx_xlock(&filemon->lock);
+ return (filemon);
+}
+
+/* Remove and release the filemon on the given process. */
+static void
+filemon_proc_drop(struct proc *p)
+{
+ struct filemon *filemon;
+
+ KASSERT(p->p_filemon != NULL, ("%s: proc %p NULL p_filemon",
+ __func__, p));
+ sx_assert(&p->p_filemon->lock, SA_XLOCKED);
+ PROC_LOCK(p);
+ filemon = p->p_filemon;
+ p->p_filemon = NULL;
+ --filemon->proccnt;
+ PROC_UNLOCK(p);
+ /*
+ * This should not be the last reference yet. filemon_release()
+ * cannot be called with filemon locked, which the caller expects
+ * will stay locked.
+ */
+ KASSERT(filemon->refcnt > 1, ("%s: proc %p dropping filemon %p "
+ "with last reference", __func__, p, filemon));
+ filemon_release(filemon);
+}
+
+/* Unlock and release the filemon. */
+static __inline void
+filemon_drop(struct filemon *filemon)
+{
+
+ sx_xunlock(&filemon->lock);
+ filemon_release(filemon);
+}
-#include "filemon_lock.c"
#include "filemon_wrapper.c"
static void
@@ -115,35 +203,151 @@ filemon_comment(struct filemon *filemon)
filemon_output(filemon, filemon->msgbufr, len);
}
+/*
+ * Invalidate the passed filemon in all processes.
+ */
static void
-filemon_dtr(void *data)
+filemon_untrack_processes(struct filemon *filemon)
{
- struct filemon *filemon = data;
+ struct proc *p;
- if (filemon != NULL) {
- struct file *fp;
+ sx_assert(&filemon->lock, SA_XLOCKED);
- /* Follow same locking order as filemon_pid_check. */
- filemon_lock_write();
- sx_xlock(&filemon->lock);
+ /* Avoid allproc loop if there is no need. */
+ if (filemon->proccnt == 0)
+ return;
+
+ /*
+ * Processes in this list won't go away while here since
+ * filemon_event_process_exit() will lock on filemon->lock
+ * which we hold.
+ */
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ /*
+ * No PROC_LOCK is needed to compare here since it is
+ * guaranteed to not change since we have its filemon
+ * locked. Everything that changes this p_filemon will
+ * be locked on it.
+ */
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+ }
+ sx_sunlock(&allproc_lock);
+
+ /*
+ * It's possible some references were acquired but will be
+ * dropped shortly as they are restricted from being
+ * inherited. There is at least the reference in cdevpriv remaining.
+ */
+ KASSERT(filemon->refcnt > 0, ("%s: filemon %p should have "
+ "references still.", __func__, filemon));
+ KASSERT(filemon->proccnt == 0, ("%s: filemon %p should not have "
+ "attached procs still.", __func__, filemon));
+}
- /* Remove from the in-use list. */
- TAILQ_REMOVE(&filemons_inuse, filemon, link);
+/*
+ * Close out the log.
+ */
+static void
+filemon_close_log(struct filemon *filemon)
+{
+ struct file *fp;
+ struct timeval now;
+ size_t len;
- fp = filemon->fp;
- filemon->fp = NULL;
- filemon->p = NULL;
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ if (filemon->fp == NULL)
+ return;
- /* Add to the free list. */
- TAILQ_INSERT_TAIL(&filemons_free, filemon, link);
+ getmicrotime(&now);
- /* Give up write access. */
- sx_xunlock(&filemon->lock);
- filemon_unlock_write();
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr),
+ "# Stop %ju.%06ju\n# Bye bye\n",
+ (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
+
+ filemon_output(filemon, filemon->msgbufr, len);
+ fp = filemon->fp;
+ filemon->fp = NULL;
+
+ sx_xunlock(&filemon->lock);
+ fdrop(fp, curthread);
+ sx_xlock(&filemon->lock);
+}
+
+/*
+ * The devfs file is being closed. Untrace all processes. It is possible
+ * filemon_close/close(2) was not called.
+ */
+static void
+filemon_dtr(void *data)
+{
+ struct filemon *filemon = data;
- if (fp != NULL)
- fdrop(fp, curthread);
+ if (filemon == NULL)
+ return;
+
+ sx_xlock(&filemon->lock);
+ /*
+ * Detach the filemon. It cannot be inherited after this.
+ */
+ filemon_untrack_processes(filemon);
+ filemon_close_log(filemon);
+ filemon_drop(filemon);
+}
+
+/* Attach the filemon to the process. */
+static int
+filemon_attach_proc(struct filemon *filemon, struct proc *p)
+{
+ struct filemon *filemon2;
+
+ sx_assert(&filemon->lock, SA_XLOCKED);
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ KASSERT((p->p_flag & P_WEXIT) == 0,
+ ("%s: filemon %p attaching to exiting process %p",
+ __func__, filemon, p));
+
+ if (p->p_filemon == filemon)
+ return (0);
+ /*
+ * Don't allow truncating other process traces. It is
+ * not really intended to trace procs other than curproc
+ * anyhow.
+ */
+ if (p->p_filemon != NULL && p != curproc)
+ return (EBUSY);
+ /*
+ * Historic behavior of filemon has been to let a child initiate
+ * tracing on itself and cease existing tracing. Bmake
+ * .META + .MAKE relies on this. It is only relevant for attaching to
+ * curproc.
+ */
+ while (p->p_filemon != NULL) {
+ PROC_UNLOCK(p);
+ sx_xunlock(&filemon->lock);
+ while ((filemon2 = filemon_proc_get(p)) != NULL) {
+ /* It may have changed. */
+ if (p->p_filemon == filemon2)
+ filemon_proc_drop(p);
+ filemon_drop(filemon2);
+ }
+ sx_xlock(&filemon->lock);
+ PROC_LOCK(p);
+ /*
+ * It may have been attached to, though unlikely.
+ * Try again if needed.
+ */
}
+
+ KASSERT(p->p_filemon == NULL,
+ ("%s: proc %p didn't detach filemon %p", __func__, p,
+ p->p_filemon));
+ p->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+
+ return (0);
}
static int
@@ -178,10 +382,16 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
/* Set the monitored process ID. */
case FILEMON_SET_PID:
+ /* Invalidate any existing processes already set. */
+ filemon_untrack_processes(filemon);
+
error = pget(*((pid_t *)data), PGET_CANDEBUG | PGET_NOTWEXIT,
&p);
if (error == 0) {
- filemon->p = p;
+ KASSERT(p->p_filemon != filemon,
+ ("%s: proc %p didn't untrack filemon %p",
+ __func__, p, filemon));
+ error = filemon_attach_proc(filemon, p);
PROC_UNLOCK(p);
}
break;
@@ -199,49 +409,48 @@ static int
filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused,
struct thread *td __unused)
{
+ int error;
struct filemon *filemon;
- /* Get exclusive write access. */
- filemon_lock_write();
-
- if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL)
- TAILQ_REMOVE(&filemons_free, filemon, link);
-
- /* Give up write access. */
- filemon_unlock_write();
-
- if (filemon == NULL) {
- filemon = malloc(sizeof(struct filemon), M_FILEMON,
- M_WAITOK | M_ZERO);
- sx_init(&filemon->lock, "filemon");
- }
-
- devfs_set_cdevpriv(filemon, filemon_dtr);
-
- /* Get exclusive write access. */
- filemon_lock_write();
+ filemon = malloc(sizeof(*filemon), M_FILEMON,
+ M_WAITOK | M_ZERO);
+ sx_init(&filemon->lock, "filemon");
+ refcount_init(&filemon->refcnt, 1);
- /* Add to the in-use list. */
- TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link);
+ error = devfs_set_cdevpriv(filemon, filemon_dtr);
+ if (error != 0)
+ filemon_release(filemon);
- /* Give up write access. */
- filemon_unlock_write();
-
- return (0);
+ return (error);
}
+/* Called on close of last devfs file handle, before filemon_dtr(). */
static int
filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused,
struct thread *td __unused)
{
+ struct filemon *filemon;
+ int error;
- return (0);
+ if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0)
+ return (error);
+
+ sx_xlock(&filemon->lock);
+ filemon_close_log(filemon);
+ error = filemon->error;
+ sx_xunlock(&filemon->lock);
+ /*
+ * Processes are still being traced but won't log anything
+ * now. After this call returns filemon_dtr() is called which
+ * will detach processes.
+ */
+
+ return (error);
}
static void
filemon_load(void *dummy __unused)
{
- sx_init(&access_lock, "filemons_inuse");
/* Install the syscall wrappers. */
filemon_wrapper_install();
@@ -253,38 +462,11 @@ filemon_load(void *dummy __unused)
static int
filemon_unload(void)
{
- struct filemon *filemon;
- int error = 0;
-
- /* Get exclusive write access. */
- filemon_lock_write();
-
- if (TAILQ_FIRST(&filemons_inuse) != NULL)
- error = EBUSY;
- else {
- destroy_dev(filemon_dev);
-
- /* Deinstall the syscall wrappers. */
- filemon_wrapper_deinstall();
- }
- /* Give up write access. */
- filemon_unlock_write();
+ destroy_dev(filemon_dev);
+ filemon_wrapper_deinstall();
- if (error == 0) {
- /* free() filemon structs free list. */
- filemon_lock_write();
- while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) {
- TAILQ_REMOVE(&filemons_free, filemon, link);
- sx_destroy(&filemon->lock);
- free(filemon, M_FILEMON);
- }
- filemon_unlock_write();
-
- sx_destroy(&access_lock);
- }
-
- return (error);
+ return (0);
}
static int
diff --git a/sys/dev/filemon/filemon_wrapper.c b/sys/dev/filemon/filemon_wrapper.c
index 6911dc5..87c9392 100644
--- a/sys/dev/filemon/filemon_wrapper.c
+++ b/sys/dev/filemon/filemon_wrapper.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2011, David E. O'Brien.
* Copyright (c) 2009-2011, Juniper Networks, Inc.
- * Copyright (c) 2015, EMC Corp.
+ * Copyright (c) 2015-2016, EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,9 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/imgact.h>
#include <sys/eventhandler.h>
+#include <sys/filedesc.h>
+#include <sys/imgact.h>
#include <sys/sx.h>
#include <sys/vnode.h>
@@ -45,6 +46,7 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
{
struct uio auio;
struct iovec aiov;
+ int error;
if (filemon->fp == NULL)
return;
@@ -62,56 +64,33 @@ filemon_output(struct filemon *filemon, char *msg, size_t len)
if (filemon->fp->f_type == DTYPE_VNODE)
bwillwrite();
- fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
-}
-
-static struct filemon *
-filemon_pid_check(struct proc *p)
-{
- struct filemon *filemon;
-
- filemon_lock_read();
- if (TAILQ_EMPTY(&filemons_inuse)) {
- filemon_unlock_read();
- return (NULL);
- }
- sx_slock(&proctree_lock);
- while (p->p_pid != 0) {
- TAILQ_FOREACH(filemon, &filemons_inuse, link) {
- if (p == filemon->p) {
- sx_sunlock(&proctree_lock);
- sx_xlock(&filemon->lock);
- filemon_unlock_read();
- return (filemon);
- }
- }
- p = proc_realparent(p);
- }
- sx_sunlock(&proctree_lock);
- filemon_unlock_read();
- return (NULL);
+ error = fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread);
+ if (error != 0)
+ filemon->error = error;
}
static int
filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_chdir(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "C %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -126,12 +105,11 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
char *fullpath, *freepath;
size_t len;
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
fullpath = "<unknown>";
freepath = NULL;
- vn_fullpath(FIRST_THREAD_IN_PROC(p), imgp->vp, &fullpath,
- &freepath);
+ vn_fullpath(curthread, imgp->vp, &fullpath, &freepath);
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "E %d %s\n",
@@ -139,321 +117,244 @@ filemon_event_process_exec(void *arg __unused, struct proc *p,
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ filemon_drop(filemon);
free(freepath, M_TEMP);
}
}
-static int
-filemon_wrapper_open(struct thread *td, struct open_args *uap)
+static void
+_filemon_wrapper_openat(struct thread *td, char *upath, int flags, int fd)
{
- int ret;
- size_t done;
+ int error;
size_t len;
+ struct file *fp;
struct filemon *filemon;
+ char *atpath, *freepath;
+ cap_rights_t rights;
- if ((ret = sys_open(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- if (uap->flags & O_RDWR) {
- /*
- * We'll get the W record below, but need
- * to also output an R to distingish from
- * O_WRONLY.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "R %d %s\n",
- curproc->p_pid, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ atpath = "";
+ freepath = NULL;
+ fp = NULL;
+ if ((error = copyinstr(upath, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
+ if (filemon->fname1[0] != '/' && fd != AT_FDCWD) {
+ /*
+ * rats - we cannot do too much about this.
+ * the trace should show a dir we read
+ * recently.. output an A record as a clue
+ * until we can do better.
+ * XXX: This may be able to come out with
+ * the namecache lookup now.
+ */
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "%c %d %s\n",
- (uap->flags & O_ACCMODE) ? 'W':'R',
+ sizeof(filemon->msgbufr), "A %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+ /*
+ * Try to resolve the path from the vnode using the
+ * namecache. It may be inaccurate, but better
+ * than nothing.
+ */
+ if (getvnode(td, fd,
+ cap_rights_init(&rights, CAP_LOOKUP), &fp) == 0) {
+ vn_fullpath(td, fp->f_vnode, &atpath,
+ &freepath);
+ }
+ }
+ if (flags & O_RDWR) {
+ /*
+ * We'll get the W record below, but need
+ * to also output an R to distinguish from
+ * O_WRONLY.
+ */
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "R %d %s%s%s\n",
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
}
- }
- return (ret);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "%c %d %s%s%s\n",
+ (flags & O_ACCMODE) ? 'W':'R',
+ curproc->p_pid, atpath,
+ atpath[0] != '\0' ? "/" : "", filemon->fname1);
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
+ if (fp != NULL)
+ fdrop(fp, td);
+ free(freepath, M_TEMP);
+ }
}
static int
-filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
+filemon_wrapper_open(struct thread *td, struct open_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_openat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- filemon->fname2[0] = '\0';
- if (filemon->fname1[0] != '/' && uap->fd != AT_FDCWD) {
- /*
- * rats - we cannot do too much about this.
- * the trace should show a dir we read
- * recently.. output an A record as a clue
- * until we can do better.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "A %d %s\n",
- curproc->p_pid, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
- if (uap->flag & O_RDWR) {
- /*
- * We'll get the W record below, but need
- * to also output an R to distingish from
- * O_WRONLY.
- */
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "R %d %s%s\n",
- curproc->p_pid, filemon->fname2, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
- }
-
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "%c %d %s%s\n",
- (uap->flag & O_ACCMODE) ? 'W':'R',
- curproc->p_pid, filemon->fname2, filemon->fname1);
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_open(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flags, AT_FDCWD);
return (ret);
}
static int
-filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
+filemon_wrapper_openat(struct thread *td, struct openat_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_rename(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->from, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->to, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
-
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_openat(td, uap)) == 0)
+ _filemon_wrapper_openat(td, uap->path, uap->flag, uap->fd);
return (ret);
}
static int
-filemon_wrapper_link(struct thread *td, struct link_args *uap)
+filemon_wrapper_rename(struct thread *td, struct rename_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
- if ((ret = sys_link(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->link, filemon->fname2,
- sizeof(filemon->fname2), &done);
+ if ((ret = sys_rename(td, uap)) == 0) {
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(uap->from, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(uap->to, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ sizeof(filemon->msgbufr), "M %d '%s' '%s'\n",
curproc->p_pid, filemon->fname1, filemon->fname2);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
return (ret);
}
-static int
-filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
+static void
+_filemon_wrapper_link(struct thread *td, char *upath1, char *upath2)
{
- int ret;
- size_t done;
- size_t len;
struct filemon *filemon;
+ size_t len;
+ int error;
+
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if (((error = copyinstr(upath1, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) ||
+ ((error = copyinstr(upath2, filemon->fname2,
+ sizeof(filemon->fname2), NULL)) != 0)) {
+ filemon->error = error;
+ goto copyfail;
+ }
- if ((ret = sys_symlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->link, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
-
- filemon_output(filemon, filemon->msgbufr, len);
+ len = snprintf(filemon->msgbufr,
+ sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
+ curproc->p_pid, filemon->fname1, filemon->fname2);
- sx_xunlock(&filemon->lock);
- }
+ filemon_output(filemon, filemon->msgbufr, len);
+copyfail:
+ filemon_drop(filemon);
}
-
- return (ret);
}
static int
-filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
+filemon_wrapper_link(struct thread *td, struct link_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
-
- if ((ret = sys_linkat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path1, filemon->fname1,
- sizeof(filemon->fname1), &done);
- copyinstr(uap->path2, filemon->fname2,
- sizeof(filemon->fname2), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "L %d '%s' '%s'\n",
- curproc->p_pid, filemon->fname1, filemon->fname2);
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_link(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
return (ret);
}
static int
-filemon_wrapper_stat(struct thread *td, struct stat_args *uap)
+filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
- if ((ret = sys_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "S %d %s\n",
- curproc->p_pid, filemon->fname1);
-
- filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_symlink(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path, uap->link);
return (ret);
}
-#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
static int
-filemon_wrapper_freebsd32_stat(struct thread *td,
- struct freebsd32_stat_args *uap)
+filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap)
{
int ret;
- size_t done;
- size_t len;
- struct filemon *filemon;
-
- if ((ret = freebsd32_stat(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
-
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr), "S %d %s\n",
- curproc->p_pid, filemon->fname1);
-
- filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
- }
- }
+ if ((ret = sys_linkat(td, uap)) == 0)
+ _filemon_wrapper_link(td, uap->path1, uap->path2);
return (ret);
}
-#endif
static void
filemon_event_process_exit(void *arg __unused, struct proc *p)
{
size_t len;
struct filemon *filemon;
- struct timeval now;
- /* Get timestamp before locking. */
- getmicrotime(&now);
-
- if ((filemon = filemon_pid_check(p)) != NULL) {
+ if ((filemon = filemon_proc_get(p)) != NULL) {
len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr),
"X %d %d %d\n", p->p_pid, p->p_xexit, p->p_xsig);
filemon_output(filemon, filemon->msgbufr, len);
- /* Check if the monitored process is about to exit. */
- if (filemon->p == p) {
- len = snprintf(filemon->msgbufr,
- sizeof(filemon->msgbufr),
- "# Stop %ju.%06ju\n# Bye bye\n",
- (uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
-
- filemon_output(filemon, filemon->msgbufr, len);
- filemon->p = NULL;
- }
-
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() may have dropped this p_filemon
+ * already while in filemon_proc_get() before acquiring the
+ * filemon lock.
+ */
+ KASSERT(p->p_filemon == NULL || p->p_filemon == filemon,
+ ("%s: p %p was attached while exiting, expected "
+ "filemon %p or NULL", __func__, p, filemon));
+ if (p->p_filemon == filemon)
+ filemon_proc_drop(p);
+
+ filemon_drop(filemon);
}
}
static int
filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
{
- int ret;
- size_t done;
+ int error, ret;
size_t len;
struct filemon *filemon;
if ((ret = sys_unlink(td, uap)) == 0) {
- if ((filemon = filemon_pid_check(curproc)) != NULL) {
- copyinstr(uap->path, filemon->fname1,
- sizeof(filemon->fname1), &done);
+ if ((filemon = filemon_proc_get(curproc)) != NULL) {
+ if ((error = copyinstr(uap->path, filemon->fname1,
+ sizeof(filemon->fname1), NULL)) != 0) {
+ filemon->error = error;
+ goto copyfail;
+ }
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "D %d %s\n",
curproc->p_pid, filemon->fname1);
filemon_output(filemon, filemon->msgbufr, len);
-
- sx_xunlock(&filemon->lock);
+copyfail:
+ filemon_drop(filemon);
}
}
@@ -467,14 +368,34 @@ filemon_event_process_fork(void *arg __unused, struct proc *p1,
size_t len;
struct filemon *filemon;
- if ((filemon = filemon_pid_check(p1)) != NULL) {
+ if ((filemon = filemon_proc_get(p1)) != NULL) {
len = snprintf(filemon->msgbufr,
sizeof(filemon->msgbufr), "F %d %d\n",
p1->p_pid, p2->p_pid);
filemon_output(filemon, filemon->msgbufr, len);
- sx_xunlock(&filemon->lock);
+ /*
+ * filemon_untrack_processes() or
+ * filemon_ioctl(FILEMON_SET_PID) may have changed the parent's
+ * p_filemon while in filemon_proc_get() before acquiring the
+ * filemon lock. Only inherit if the parent is still traced by
+ * this filemon.
+ */
+ if (p1->p_filemon == filemon) {
+ PROC_LOCK(p2);
+ /*
+ * It may have been attached to already by a new
+ * filemon.
+ */
+ if (p2->p_filemon == NULL) {
+ p2->p_filemon = filemon_acquire(filemon);
+ ++filemon->proccnt;
+ }
+ PROC_UNLOCK(p2);
+ }
+
+ filemon_drop(filemon);
}
}
@@ -491,7 +412,6 @@ filemon_wrapper_install(void)
sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
- sv_table[SYS_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -504,7 +424,6 @@ filemon_wrapper_install(void)
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *) filemon_wrapper_openat;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
- sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
@@ -532,7 +451,6 @@ filemon_wrapper_deinstall(void)
sv_table[SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[SYS_openat].sy_call = (sy_call_t *)sys_openat;
sv_table[SYS_rename].sy_call = (sy_call_t *)sys_rename;
- sv_table[SYS_stat].sy_call = (sy_call_t *)sys_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
@@ -545,7 +463,6 @@ filemon_wrapper_deinstall(void)
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[FREEBSD32_SYS_openat].sy_call = (sy_call_t *)sys_openat;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
- sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
diff --git a/sys/dev/flash/mx25l.c b/sys/dev/flash/mx25l.c
index c4dad4b..6b71340 100644
--- a/sys/dev/flash/mx25l.c
+++ b/sys/dev/flash/mx25l.c
@@ -26,6 +26,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
@@ -40,6 +42,12 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <geom/geom_disk.h>
+#ifdef FDT
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
#include <dev/spibus/spi.h>
#include "spibus_if.h"
@@ -48,6 +56,8 @@ __FBSDID("$FreeBSD$");
#define FL_NONE 0x00
#define FL_ERASE_4K 0x01
#define FL_ERASE_32K 0x02
+#define FL_ENABLE_4B_ADDR 0x04
+#define FL_DISABLE_4B_ADDR 0x08
/*
* Define the sectorsize to be a smaller size rather than the flash
@@ -105,6 +115,7 @@ struct mx25l_flash_ident flash_devices[] = {
{ "mx25ll32", 0xc2, 0x2016, 64 * 1024, 64, FL_NONE },
{ "mx25ll64", 0xc2, 0x2017, 64 * 1024, 128, FL_NONE },
{ "mx25ll128", 0xc2, 0x2018, 64 * 1024, 256, FL_ERASE_4K | FL_ERASE_32K },
+ { "mx25ll256", 0xc2, 0x2019, 64 * 1024, 512, FL_ERASE_4K | FL_ERASE_32K | FL_ENABLE_4B_ADDR },
{ "s25fl032", 0x01, 0x0215, 64 * 1024, 64, FL_NONE },
{ "s25fl064", 0x01, 0x0216, 64 * 1024, 128, FL_NONE },
{ "s25fl128", 0x01, 0x2018, 64 * 1024, 256, FL_NONE },
@@ -211,10 +222,13 @@ mx25l_set_writable(device_t dev, int writable)
static void
mx25l_erase_cmd(device_t dev, off_t sector, uint8_t ecmd)
{
- uint8_t txBuf[4], rxBuf[4];
+ struct mx25l_softc *sc;
+ uint8_t txBuf[5], rxBuf[5];
struct spi_command cmd;
int err;
+ sc = device_get_softc(dev);
+
mx25l_wait_for_device_ready(dev);
mx25l_set_writable(dev, 1);
@@ -225,11 +239,20 @@ mx25l_erase_cmd(device_t dev, off_t sector, uint8_t ecmd)
txBuf[0] = ecmd;
cmd.tx_cmd = txBuf;
cmd.rx_cmd = rxBuf;
- cmd.rx_cmd_sz = 4;
- cmd.tx_cmd_sz = 4;
- txBuf[1] = ((sector >> 16) & 0xff);
- txBuf[2] = ((sector >> 8) & 0xff);
- txBuf[3] = (sector & 0xff);
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.rx_cmd_sz = 5;
+ cmd.tx_cmd_sz = 5;
+ txBuf[1] = ((sector >> 24) & 0xff);
+ txBuf[2] = ((sector >> 16) & 0xff);
+ txBuf[3] = ((sector >> 8) & 0xff);
+ txBuf[4] = (sector & 0xff);
+ } else {
+ cmd.rx_cmd_sz = 4;
+ cmd.tx_cmd_sz = 4;
+ txBuf[1] = ((sector >> 16) & 0xff);
+ txBuf[2] = ((sector >> 8) & 0xff);
+ txBuf[3] = (sector & 0xff);
+ }
err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd);
}
@@ -247,8 +270,13 @@ mx25l_write(device_t dev, off_t offset, caddr_t data, off_t count)
pdev = device_get_parent(dev);
sc = device_get_softc(dev);
- cmd.tx_cmd_sz = 4;
- cmd.rx_cmd_sz = 4;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.tx_cmd_sz = 5;
+ cmd.rx_cmd_sz = 5;
+ } else {
+ cmd.tx_cmd_sz = 4;
+ cmd.rx_cmd_sz = 4;
+ }
bytes_writen = 0;
write_offset = offset;
@@ -282,9 +310,16 @@ mx25l_write(device_t dev, off_t offset, caddr_t data, off_t count)
mx25l_erase_cmd(dev, offset + bytes_writen, CMD_SECTOR_ERASE);
txBuf[0] = CMD_PAGE_PROGRAM;
- txBuf[1] = ((write_offset >> 16) & 0xff);
- txBuf[2] = ((write_offset >> 8) & 0xff);
- txBuf[3] = (write_offset & 0xff);
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ txBuf[1] = ((write_offset >> 24) & 0xff);
+ txBuf[2] = ((write_offset >> 16) & 0xff);
+ txBuf[3] = ((write_offset >> 8) & 0xff);
+ txBuf[4] = (write_offset & 0xff);
+ } else {
+ txBuf[1] = ((write_offset >> 16) & 0xff);
+ txBuf[2] = ((write_offset >> 8) & 0xff);
+ txBuf[3] = (write_offset & 0xff);
+ }
bytes_to_write = MIN(FLASH_PAGE_SIZE,
count - bytes_writen);
@@ -336,14 +371,26 @@ mx25l_read(device_t dev, off_t offset, caddr_t data, off_t count)
return (EIO);
txBuf[0] = CMD_FAST_READ;
- cmd.tx_cmd_sz = 5;
- cmd.rx_cmd_sz = 5;
-
- txBuf[1] = ((offset >> 16) & 0xff);
- txBuf[2] = ((offset >> 8) & 0xff);
- txBuf[3] = (offset & 0xff);
- /* Dummy byte */
- txBuf[4] = 0;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR) {
+ cmd.tx_cmd_sz = 6;
+ cmd.rx_cmd_sz = 6;
+
+ txBuf[1] = ((offset >> 24) & 0xff);
+ txBuf[2] = ((offset >> 16) & 0xff);
+ txBuf[3] = ((offset >> 8) & 0xff);
+ txBuf[4] = (offset & 0xff);
+ /* Dummy byte */
+ txBuf[5] = 0;
+ } else {
+ cmd.tx_cmd_sz = 5;
+ cmd.rx_cmd_sz = 5;
+
+ txBuf[1] = ((offset >> 16) & 0xff);
+ txBuf[2] = ((offset >> 8) & 0xff);
+ txBuf[3] = (offset & 0xff);
+ /* Dummy byte */
+ txBuf[4] = 0;
+ }
cmd.tx_cmd = txBuf;
cmd.rx_cmd = rxBuf;
@@ -358,9 +405,45 @@ mx25l_read(device_t dev, off_t offset, caddr_t data, off_t count)
}
static int
+mx25l_set_4b_mode(device_t dev, uint8_t command)
+{
+ uint8_t txBuf[1], rxBuf[1];
+ struct spi_command cmd;
+ device_t pdev;
+ int err;
+
+ memset(&cmd, 0, sizeof(cmd));
+ memset(txBuf, 0, sizeof(txBuf));
+ memset(rxBuf, 0, sizeof(rxBuf));
+
+ pdev = device_get_parent(dev);
+
+ cmd.tx_cmd_sz = cmd.rx_cmd_sz = 1;
+
+ cmd.tx_cmd = txBuf;
+ cmd.rx_cmd = rxBuf;
+
+ txBuf[0] = command;
+
+ err = SPIBUS_TRANSFER(pdev, dev, &cmd);
+
+ mx25l_wait_for_device_ready(dev);
+
+ return (err);
+}
+
+static int
mx25l_probe(device_t dev)
{
+
+#ifdef FDT
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+ if (!ofw_bus_is_compatible(dev, "st,m25p"))
+ return (ENXIO);
+#endif
device_set_desc(dev, "M25Pxx Flash Family");
+
return (0);
}
@@ -397,6 +480,12 @@ mx25l_attach(device_t dev)
sc->sc_sectorsize = ident->sectorsize;
sc->sc_flags = ident->flags;
+ if (sc->sc_flags & FL_ENABLE_4B_ADDR)
+ mx25l_set_4b_mode(dev, CMD_ENTER_4B_MODE);
+
+ if (sc->sc_flags & FL_DISABLE_4B_ADDR)
+ mx25l_set_4b_mode(dev, CMD_EXIT_4B_MODE);
+
/* NB: use stripesize to hold the erase/region size for RedBoot */
sc->sc_disk->d_stripesize = ident->sectorsize;
diff --git a/sys/dev/flash/mx25lreg.h b/sys/dev/flash/mx25lreg.h
index 7253dba..5e303e1 100644
--- a/sys/dev/flash/mx25lreg.h
+++ b/sys/dev/flash/mx25lreg.h
@@ -45,6 +45,8 @@
#define CMD_BULK_ERASE 0xC7
#define CMD_BLOCK_4K_ERASE 0x20
#define CMD_BLOCK_32K_ERASE 0x52
+#define CMD_ENTER_4B_MODE 0xB7
+#define CMD_EXIT_4B_MODE 0xE9
/*
* Status register flags
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index 44ab581..553d574 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -390,7 +390,7 @@ gpiobus_probe_nomatch(device_t dev, device_t child)
device_printf(dev, "<unknown device> at pins %s", pins);
else
device_printf(dev, "<unknown device> at pin %s", pins);
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
printf("\n");
}
@@ -412,7 +412,7 @@ gpiobus_print_child(device_t dev, device_t child)
gpiobus_print_pins(devi, pins, sizeof(pins));
retval += printf("%s", pins);
}
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
return (retval);
diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c
index be5a747..f6d2115 100644
--- a/sys/dev/gpio/ofw_gpiobus.c
+++ b/sys/dev/gpio/ofw_gpiobus.c
@@ -575,6 +575,7 @@ static devclass_t ofwgpiobus_devclass;
DEFINE_CLASS_1(gpiobus, ofw_gpiobus_driver, ofw_gpiobus_methods,
sizeof(struct gpiobus_softc), gpiobus_driver);
-DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0);
+EARLY_DRIVER_MODULE(ofw_gpiobus, gpio, ofw_gpiobus_driver, ofwgpiobus_devclass,
+ 0, 0, BUS_PASS_BUS);
MODULE_VERSION(ofw_gpiobus, 1);
MODULE_DEPEND(ofw_gpiobus, gpiobus, 1, 1, 1);
diff --git a/sys/dev/hyperv/include/hyperv.h b/sys/dev/hyperv/include/hyperv.h
index 0a057c8..26a2bfc 100644
--- a/sys/dev/hyperv/include/hyperv.h
+++ b/sys/dev/hyperv/include/hyperv.h
@@ -124,6 +124,8 @@ typedef struct hv_guid {
unsigned char data[16];
} __packed hv_guid;
+int snprintf_hv_guid(char *, size_t, const hv_guid *);
+
#define HV_NIC_GUID \
.data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, \
0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E}
diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
index 0cec9a7..acc49b4 100644
--- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
+++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
@@ -181,6 +181,7 @@ struct hn_txdesc {
#define HN_CSUM_ASSIST_WIN8 (CSUM_IP | CSUM_TCP)
#define HN_CSUM_ASSIST (CSUM_IP | CSUM_UDP | CSUM_TCP)
+#define HN_LRO_LENLIM_MULTIRX_DEF (12 * ETHERMTU)
#define HN_LRO_LENLIM_DEF (25 * ETHERMTU)
/* YYY 2*MTU is a bit rough, but should be good enough. */
#define HN_LRO_LENLIM_MIN(ifp) (2 * (ifp)->if_mtu)
@@ -333,6 +334,17 @@ static void hn_xmit_txeof(struct hn_tx_ring *);
static void hn_xmit_taskfunc(void *, int);
static void hn_xmit_txeof_taskfunc(void *, int);
+#if __FreeBSD_version >= 1100099
+static void
+hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
+{
+ int i;
+
+ for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
+ sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
+}
+#endif
+
static int
hn_ifmedia_upd(struct ifnet *ifp __unused)
{
@@ -530,6 +542,16 @@ netvsc_attach(device_t dev)
device_printf(dev, "%d TX ring, %d RX ring\n",
sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
+#if __FreeBSD_version >= 1100099
+ if (sc->hn_rx_ring_inuse > 1) {
+ /*
+ * Reduce TCP segment aggregation limit for multiple
+ * RX rings to increase ACK timeliness.
+ */
+ hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MULTIRX_DEF);
+ }
+#endif
+
if (device_info.link_state == 0) {
sc->hn_carrier = 1;
}
@@ -756,13 +778,8 @@ netvsc_channel_rollup(struct hv_vmbus_channel *chan)
struct hn_tx_ring *txr = chan->hv_chan_txr;
#if defined(INET) || defined(INET6)
struct hn_rx_ring *rxr = chan->hv_chan_rxr;
- struct lro_ctrl *lro = &rxr->hn_lro;
- struct lro_entry *queued;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(&rxr->hn_lro);
#endif
/*
@@ -1238,8 +1255,10 @@ netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
return (0);
} else if (packet->tot_data_buf_len <= MHLEN) {
m_new = m_gethdr(M_NOWAIT, MT_DATA);
- if (m_new == NULL)
+ if (m_new == NULL) {
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
return (0);
+ }
memcpy(mtod(m_new, void *), packet->data,
packet->tot_data_buf_len);
m_new->m_pkthdr.len = m_new->m_len = packet->tot_data_buf_len;
@@ -1259,7 +1278,7 @@ netvsc_recv(struct hv_vmbus_channel *chan, netvsc_packet *packet,
m_new = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size);
if (m_new == NULL) {
- if_printf(ifp, "alloc mbuf failed.\n");
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
return (0);
}
@@ -1449,14 +1468,8 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
*/
NV_LOCK(sc);
if (sc->hn_rx_ring[0].hn_lro.lro_length_lim <
- HN_LRO_LENLIM_MIN(ifp)) {
- int i;
-
- for (i = 0; i < sc->hn_rx_ring_inuse; ++i) {
- sc->hn_rx_ring[i].hn_lro.lro_length_lim =
- HN_LRO_LENLIM_MIN(ifp);
- }
- }
+ HN_LRO_LENLIM_MIN(ifp))
+ hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
NV_UNLOCK(sc);
#endif
@@ -1789,7 +1802,7 @@ hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
{
struct hn_softc *sc = arg1;
unsigned int lenlim;
- int error, i;
+ int error;
lenlim = sc->hn_rx_ring[0].hn_lro.lro_length_lim;
error = sysctl_handle_int(oidp, &lenlim, 0, req);
@@ -1801,8 +1814,7 @@ hn_lro_lenlim_sysctl(SYSCTL_HANDLER_ARGS)
return EINVAL;
NV_LOCK(sc);
- for (i = 0; i < sc->hn_rx_ring_inuse; ++i)
- sc->hn_rx_ring[i].hn_lro.lro_length_lim = lenlim;
+ hn_set_lro_lenlim(sc, lenlim);
NV_UNLOCK(sc);
return 0;
}
diff --git a/sys/dev/hyperv/utilities/hv_heartbeat.c b/sys/dev/hyperv/utilities/hv_heartbeat.c
index c1b6da5..09bd28b 100644
--- a/sys/dev/hyperv/utilities/hv_heartbeat.c
+++ b/sys/dev/hyperv/utilities/hv_heartbeat.c
@@ -94,6 +94,10 @@ static int
hv_heartbeat_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvheartbeat", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Heartbeat Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_kvp.c b/sys/dev/hyperv/utilities/hv_kvp.c
index 8517918..d71310b 100644
--- a/sys/dev/hyperv/utilities/hv_kvp.c
+++ b/sys/dev/hyperv/utilities/hv_kvp.c
@@ -304,28 +304,11 @@ hv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg,
{
int err_ip, err_subnet, err_gway, err_dns, err_adap;
int UNUSED_FLAG = 1;
- int guid_index;
struct hv_device *hv_dev; /* GUID Data Structure */
hn_softc_t *sc; /* hn softc structure */
char if_name[4];
- unsigned char guid_instance[40];
- char *guid_data = NULL;
char buf[39];
- struct guid_extract {
- char a1[2];
- char a2[2];
- char a3[2];
- char a4[2];
- char b1[2];
- char b2[2];
- char c1[2];
- char c2[2];
- char d[4];
- char e[12];
- };
-
- struct guid_extract *id;
device_t *devs;
int devcnt;
@@ -352,17 +335,7 @@ hv_kvp_convert_utf16_ipinfo_to_utf8(struct hv_kvp_ip_msg *host_ip_msg,
/* Trying to find GUID of Network Device */
hv_dev = sc->hn_dev_obj;
- for (guid_index = 0; guid_index < 16; guid_index++) {
- sprintf(&guid_instance[guid_index * 2], "%02x",
- hv_dev->device_id.data[guid_index]);
- }
-
- guid_data = (char *)guid_instance;
- id = (struct guid_extract *)guid_data;
- snprintf(buf, sizeof(buf), "{%.2s%.2s%.2s%.2s-%.2s%.2s-%.2s%.2s-%.4s-%s}",
- id->a4, id->a3, id->a2, id->a1,
- id->b2, id->b1, id->c2, id->c1, id->d, id->e);
- guid_data = NULL;
+ snprintf_hv_guid(buf, sizeof(buf), &hv_dev->device_id);
sprintf(if_name, "%s%d", "hn", device_get_unit(devs[devcnt]));
if (strncmp(buf, (char *)umsg->body.kvp_ip_val.adapter_id, 39) == 0) {
@@ -890,6 +863,10 @@ static int
hv_kvp_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvkvp", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V KVP Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_shutdown.c b/sys/dev/hyperv/utilities/hv_shutdown.c
index 20bc65e..0beed5a 100644
--- a/sys/dev/hyperv/utilities/hv_shutdown.c
+++ b/sys/dev/hyperv/utilities/hv_shutdown.c
@@ -116,6 +116,10 @@ static int
hv_shutdown_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvshutdown", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Shutdown Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/utilities/hv_timesync.c b/sys/dev/hyperv/utilities/hv_timesync.c
index d1ea904..06580d7 100644
--- a/sys/dev/hyperv/utilities/hv_timesync.c
+++ b/sys/dev/hyperv/utilities/hv_timesync.c
@@ -171,6 +171,10 @@ static int
hv_timesync_probe(device_t dev)
{
const char *p = vmbus_get_type(dev);
+
+ if (resource_disabled("hvtimesync", 0))
+ return ENXIO;
+
if (!memcmp(p, &service_guid, sizeof(hv_guid))) {
device_set_desc(dev, "Hyper-V Time Synch Service");
return BUS_PROBE_DEFAULT;
diff --git a/sys/dev/hyperv/vmbus/hv_connection.c b/sys/dev/hyperv/vmbus/hv_connection.c
index aa1e59e..e170298 100644
--- a/sys/dev/hyperv/vmbus/hv_connection.c
+++ b/sys/dev/hyperv/vmbus/hv_connection.c
@@ -364,31 +364,35 @@ hv_vmbus_on_events(int cpu)
/**
* Send a msg on the vmbus's message connection
*/
-int hv_vmbus_post_message(void *buffer, size_t bufferLen) {
- int ret = 0;
+int hv_vmbus_post_message(void *buffer, size_t bufferLen)
+{
hv_vmbus_connection_id connId;
- unsigned retries = 0;
+ sbintime_t time = SBT_1MS;
+ int retries;
+ int ret;
- /* NetScaler delays from previous code were consolidated here */
- static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000};
+ connId.as_uint32_t = 0;
+ connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- /* for(each entry in delayAmount) try to post message,
- * delay a little bit before retrying
+ /*
+ * We retry to cope with transient failures caused by host side's
+ * insufficient resources. 20 times should suffice in practice.
*/
- for (retries = 0;
- retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) {
- connId.as_uint32_t = 0;
- connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID;
- ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen);
- if (ret != HV_STATUS_INSUFFICIENT_BUFFERS)
- break;
- /* TODO: KYS We should use a blocking wait call */
- DELAY(delayAmount[retries]);
+ for (retries = 0; retries < 20; retries++) {
+ ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer,
+ bufferLen);
+ if (ret == HV_STATUS_SUCCESS)
+ return (0);
+
+ pause_sbt("pstmsg", time, 0, C_HARDCLOCK);
+ if (time < SBT_1S * 2)
+ time *= 2;
}
- KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n"));
+ KASSERT(ret == HV_STATUS_SUCCESS,
+ ("Error VMBUS: Message Post Failed, ret=%d\n", ret));
- return (ret);
+ return (EAGAIN);
}
/**
diff --git a/sys/dev/hyperv/vmbus/hv_et.c b/sys/dev/hyperv/vmbus/hv_et.c
index d961486..9fb6e23 100644
--- a/sys/dev/hyperv/vmbus/hv_et.c
+++ b/sys/dev/hyperv/vmbus/hv_et.c
@@ -60,7 +60,7 @@ hv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime)
timer_cfg.as_uint64 = 0;
timer_cfg.auto_enable = 1;
- timer_cfg.sintx = HV_VMBUS_MESSAGE_SINT;
+ timer_cfg.sintx = HV_VMBUS_TIMER_SINT;
periodticks[curcpu] = sbintime2tick(periodtime);
if (firsttime == 0)
diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c
index 6afc2b8..a87b5ce 100644
--- a/sys/dev/hyperv/vmbus/hv_hv.c
+++ b/sys/dev/hyperv/vmbus/hv_hv.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/pcpu.h>
#include <sys/timetc.h>
+#include <sys/kernel.h>
#include <machine/bus.h>
#include <machine/md_var.h>
#include <vm/vm.h>
@@ -207,8 +208,6 @@ hv_vmbus_init(void)
hv_vmbus_g_context.hypercall_page = virt_addr;
- tc_init(&hv_timecounter); /* register virtual timecount */
-
hv_et_init();
return (0);
@@ -368,6 +367,9 @@ hv_vmbus_synic_init(void *arg)
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
+ wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
+ shared_sint.as_uint64_t);
+
/* Enable the global synic bit */
sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL);
sctrl.u.enable = 1;
@@ -404,12 +406,23 @@ void hv_vmbus_synic_cleanup(void *arg)
shared_sint.u.masked = 1;
/*
- * Disable the interrupt
+ * Disable the interrupt 0
*/
wrmsr(
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT,
shared_sint.as_uint64_t);
+ shared_sint.as_uint64_t = rdmsr(
+ HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT);
+
+ shared_sint.u.masked = 1;
+
+ /*
+ * Disable the interrupt 1
+ */
+ wrmsr(
+ HV_X64_MSR_SINT0 + HV_VMBUS_TIMER_SINT,
+ shared_sint.as_uint64_t);
simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP);
simp.u.simp_enabled = 0;
simp.u.base_simp_gpa = 0;
@@ -423,3 +436,14 @@ void hv_vmbus_synic_cleanup(void *arg)
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
}
+static void
+hv_tc_init(void)
+{
+ if (vm_guest != VM_GUEST_HV)
+ return;
+
+ /* register virtual timecounter */
+ tc_init(&hv_timecounter);
+}
+
+SYSINIT(hv_tc_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hv_tc_init, NULL);
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
index 4895f71..669a532 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/pcpu.h>
#include <x86/apicvar.h>
+#include <dev/hyperv/include/hyperv.h>
#include "hv_vmbus_priv.h"
#include <contrib/dev/acpica/include/acpi.h>
@@ -75,7 +76,7 @@ static char *vmbus_ids[] = { "VMBUS", NULL };
* the hypervisor.
*/
static void
-vmbus_msg_swintr(void *arg)
+vmbus_msg_swintr(void *arg, int pending __unused)
{
int cpu;
void* page_addr;
@@ -174,12 +175,15 @@ hv_vmbus_isr(struct trapframe *frame)
/* Check if there are actual msgs to be process */
page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
- msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
+ msg = (hv_vmbus_message*) page_addr + HV_VMBUS_TIMER_SINT;
/* we call eventtimer process the message */
if (msg->header.message_type == HV_MESSAGE_TIMER_EXPIRED) {
msg->header.message_type = HV_MESSAGE_TYPE_NONE;
+ /* call intrrupt handler of event timer */
+ hv_et_intr(frame);
+
/*
* Make sure the write to message_type (ie set to
* HV_MESSAGE_TYPE_NONE) happens before we read the
@@ -196,12 +200,12 @@ hv_vmbus_isr(struct trapframe *frame)
*/
wrmsr(HV_X64_MSR_EOM, 0);
}
- hv_et_intr(frame);
- return (FILTER_HANDLED);
}
+ msg = (hv_vmbus_message*) page_addr + HV_VMBUS_MESSAGE_SINT;
if (msg->header.message_type != HV_MESSAGE_TYPE_NONE) {
- swi_sched(hv_vmbus_g_context.msg_swintr[cpu], 0);
+ taskqueue_enqueue(hv_vmbus_g_context.hv_msg_tq[cpu],
+ &hv_vmbus_g_context.hv_msg_task[cpu]);
}
return (FILTER_HANDLED);
@@ -279,6 +283,23 @@ vmbus_write_ivar(
return (ENOENT);
}
+static int
+vmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen)
+{
+ char guidbuf[40];
+ struct hv_device *dev_ctx = device_get_ivars(child);
+
+ strlcat(buf, "classid=", buflen);
+ snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->class_id);
+ strlcat(buf, guidbuf, buflen);
+
+ strlcat(buf, " deviceid=", buflen);
+ snprintf_hv_guid(guidbuf, sizeof(guidbuf), &dev_ctx->device_id);
+ strlcat(buf, guidbuf, buflen);
+
+ return (0);
+}
+
struct hv_device*
hv_vmbus_child_device_create(
hv_guid type,
@@ -300,15 +321,17 @@ hv_vmbus_child_device_create(
return (child_dev);
}
-static void
-print_dev_guid(struct hv_device *dev)
+int
+snprintf_hv_guid(char *buf, size_t sz, const hv_guid *guid)
{
- int i;
- unsigned char guid_name[100];
- for (i = 0; i < 32; i += 2)
- sprintf(&guid_name[i], "%02x", dev->class_id.data[i / 2]);
- if(bootverbose)
- printf("VMBUS: Class ID: %s\n", guid_name);
+ int cnt;
+ const unsigned char *d = guid->data;
+
+ cnt = snprintf(buf, sz,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
+ d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+ return (cnt);
}
int
@@ -317,8 +340,11 @@ hv_vmbus_child_device_register(struct hv_device *child_dev)
device_t child;
int ret = 0;
- print_dev_guid(child_dev);
-
+ if (bootverbose) {
+ char name[40];
+ snprintf_hv_guid(name, sizeof(name), &child_dev->class_id);
+ printf("VMBUS: Class ID: %s\n", name);
+ }
child = device_add_child(vmbus_devp, NULL, -1);
child_dev->device = child;
@@ -485,9 +511,6 @@ vmbus_bus_init(void)
setup_args.vector = hv_vmbus_g_context.hv_cb_vector;
CPU_FOREACH(j) {
- hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
- hv_vmbus_g_context.msg_swintr[j] = NULL;
-
snprintf(buf, sizeof(buf), "cpu%d:hyperv", j);
intrcnt_add(buf, &hv_vmbus_intr_cpu[j]);
@@ -504,39 +527,21 @@ vmbus_bus_init(void)
*/
hv_vmbus_g_context.hv_event_queue[j] = taskqueue_create_fast("hyperv event", M_WAITOK,
taskqueue_thread_enqueue, &hv_vmbus_g_context.hv_event_queue[j]);
- if (hv_vmbus_g_context.hv_event_queue[j] == NULL) {
- if (bootverbose)
- printf("VMBUS: failed to setup taskqueue\n");
- goto cleanup1;
- }
CPU_SETOF(j, &cpu_mask);
taskqueue_start_threads_cpuset(&hv_vmbus_g_context.hv_event_queue[j], 1, PI_NET, &cpu_mask,
"hvevent%d", j);
/*
- * Setup software interrupt thread and handler for msg handling.
- */
- ret = swi_add(&hv_vmbus_g_context.hv_msg_intr_event[j],
- "hv_msg", vmbus_msg_swintr, (void *)(long)j, SWI_CLOCK, 0,
- &hv_vmbus_g_context.msg_swintr[j]);
- if (ret) {
- if(bootverbose)
- printf("VMBUS: failed to setup msg swi for "
- "cpu %d\n", j);
- goto cleanup1;
- }
-
- /*
- * Bind the swi thread to the cpu.
+ * Setup per-cpu tasks and taskqueues to handle msg.
*/
- ret = intr_event_bind(hv_vmbus_g_context.hv_msg_intr_event[j],
- j);
- if (ret) {
- if(bootverbose)
- printf("VMBUS: failed to bind msg swi thread "
- "to cpu %d\n", j);
- goto cleanup1;
- }
+ hv_vmbus_g_context.hv_msg_tq[j] = taskqueue_create_fast(
+ "hyperv msg", M_WAITOK, taskqueue_thread_enqueue,
+ &hv_vmbus_g_context.hv_msg_tq[j]);
+ CPU_SETOF(j, &cpu_mask);
+ taskqueue_start_threads_cpuset(&hv_vmbus_g_context.hv_msg_tq[j],
+ 1, PI_NET, &cpu_mask, "hvmsg%d", j);
+ TASK_INIT(&hv_vmbus_g_context.hv_msg_task[j], 0,
+ vmbus_msg_swintr, (void *)(long)j);
/*
* Prepare the per cpu msg and event pages to be called on each cpu.
@@ -576,11 +581,10 @@ vmbus_bus_init(void)
* remove swi and vmbus callback vector;
*/
CPU_FOREACH(j) {
- if (hv_vmbus_g_context.hv_event_queue[j] != NULL)
+ if (hv_vmbus_g_context.hv_event_queue[j] != NULL) {
taskqueue_free(hv_vmbus_g_context.hv_event_queue[j]);
- if (hv_vmbus_g_context.msg_swintr[j] != NULL)
- swi_remove(hv_vmbus_g_context.msg_swintr[j]);
- hv_vmbus_g_context.hv_msg_intr_event[j] = NULL;
+ hv_vmbus_g_context.hv_event_queue[j] = NULL;
+ }
}
vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
@@ -645,11 +649,10 @@ vmbus_bus_exit(void)
/* remove swi */
CPU_FOREACH(i) {
- if (hv_vmbus_g_context.hv_event_queue[i] != NULL)
+ if (hv_vmbus_g_context.hv_event_queue[i] != NULL) {
taskqueue_free(hv_vmbus_g_context.hv_event_queue[i]);
- if (hv_vmbus_g_context.msg_swintr[i] != NULL)
- swi_remove(hv_vmbus_g_context.msg_swintr[i]);
- hv_vmbus_g_context.hv_msg_intr_event[i] = NULL;
+ hv_vmbus_g_context.hv_event_queue[i] = NULL;
+ }
}
vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector);
@@ -714,6 +717,7 @@ static device_method_t vmbus_methods[] = {
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_read_ivar, vmbus_read_ivar),
DEVMETHOD(bus_write_ivar, vmbus_write_ivar),
+ DEVMETHOD(bus_child_pnpinfo_str, vmbus_child_pnpinfo_str),
{ 0, 0 } };
diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
index 62fa22a..1a0ed04 100644
--- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
+++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
@@ -70,6 +70,7 @@ typedef uint16_t hv_vmbus_status;
* You did not supply enough message buffers to send a message.
*/
+#define HV_STATUS_SUCCESS ((uint16_t)0)
#define HV_STATUS_INSUFFICIENT_BUFFERS ((uint16_t)0x0013)
typedef void (*hv_vmbus_channel_callback)(void *context);
@@ -180,7 +181,8 @@ enum {
HV_VMBUS_EVENT_PORT_ID = 2,
HV_VMBUS_MONITOR_CONNECTION_ID = 3,
HV_VMBUS_MONITOR_PORT_ID = 3,
- HV_VMBUS_MESSAGE_SINT = 2
+ HV_VMBUS_MESSAGE_SINT = 2,
+ HV_VMBUS_TIMER_SINT = 4,
};
#define HV_PRESENT_BIT 0x80000000
@@ -203,8 +205,8 @@ typedef struct {
* event and msg handling.
*/
struct taskqueue *hv_event_queue[MAXCPU];
- struct intr_event *hv_msg_intr_event[MAXCPU];
- void *msg_swintr[MAXCPU];
+ struct taskqueue *hv_msg_tq[MAXCPU];
+ struct task hv_msg_task[MAXCPU];
/*
* Host use this vector to intrrupt guest for vmbus channel
* event and msg.
diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c
index ec84f8f..75c41b7 100644
--- a/sys/dev/ichwd/ichwd.c
+++ b/sys/dev/ichwd/ichwd.c
@@ -540,9 +540,6 @@ ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p)
if (ich == NULL)
return (NULL);
- ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n",
- id->ich_version, id->desc);
-
if (id_p)
*id_p = id;
@@ -573,8 +570,6 @@ ichwd_identify(driver_t *driver, device_t parent)
if (dev == NULL)
return;
- device_set_desc_copy(dev, id_p->desc);
-
switch (id_p->tco_version) {
case 1:
break;
@@ -611,10 +606,16 @@ ichwd_identify(driver_t *driver, device_t parent)
static int
ichwd_probe(device_t dev)
{
+ struct ichwd_device *id_p;
/* Do not claim some ISA PnP device by accident. */
if (isa_get_logicalid(dev) != 0)
return (ENXIO);
+
+ if (ichwd_find_ich_lpc_bridge(&id_p) == NULL)
+ return (ENXIO);
+
+ device_set_desc_copy(dev, id_p->desc);
return (0);
}
@@ -677,9 +678,6 @@ ichwd_attach(device_t dev)
if (ichwd_clear_noreboot(sc) != 0)
goto fail;
- ichwd_verbose_printf(dev, "%s (ICH%d or equivalent)\n",
- id_p->desc, sc->ich_version);
-
/*
* Determine if we are coming up after a watchdog-induced reset. Some
* BIOSes may clear this bit at bootup, preventing us from reporting
diff --git a/sys/dev/iicbus/iicbus.c b/sys/dev/iicbus/iicbus.c
index df29b09..a090bb9 100644
--- a/sys/dev/iicbus/iicbus.c
+++ b/sys/dev/iicbus/iicbus.c
@@ -149,7 +149,7 @@ iicbus_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
if (devi->addr != 0)
retval += printf(" at addr %#x", devi->addr);
- resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%ld");
+ resource_list_print_type(&devi->rl, "irq", SYS_RES_IRQ, "%jd");
retval += bus_print_child_footer(dev, child);
return (retval);
diff --git a/sys/dev/iir/iir.c b/sys/dev/iir/iir.c
index bf5cec5..e74698e 100644
--- a/sys/dev/iir/iir.c
+++ b/sys/dev/iir/iir.c
@@ -744,9 +744,9 @@ gdt_next(struct gdt_softc *gdt)
ccb->ccb_h.flags));
csio = &ccb->csio;
ccbh = &ccb->ccb_h;
- cmd = csio->cdb_io.cdb_bytes[0];
- /* Max CDB length is 12 bytes */
- if (csio->cdb_len > 12) {
+ cmd = scsiio_cdb_ptr(csio)[0];
+ /* Max CDB length is 12 bytes, can't be phys addr */
+ if (csio->cdb_len > 12 || (ccbh->flags & CAM_CDB_PHYS)) {
ccbh->status = CAM_REQ_INVALID;
--gdt_stat.io_count_act;
xpt_done(ccb);
diff --git a/sys/dev/iir/iir_pci.c b/sys/dev/iir/iir_pci.c
index 261f5a6..5db66b1 100644
--- a/sys/dev/iir/iir_pci.c
+++ b/sys/dev/iir/iir_pci.c
@@ -228,7 +228,7 @@ iir_pci_attach(device_t dev)
/* check and reset interface area */
bus_write_4(gdt->sc_dpmem, GDT_MPR_IC, htole32(GDT_MPR_MAGIC));
if (bus_read_4(gdt->sc_dpmem, GDT_MPR_IC) != htole32(GDT_MPR_MAGIC)) {
- device_printf(dev, "cannot access DPMEM at 0x%lx (shadowed?)\n",
+ device_printf(dev, "cannot access DPMEM at 0x%jx (shadowed?)\n",
rman_get_start(gdt->sc_dpmem));
error = ENXIO;
goto err;
diff --git a/sys/dev/ipmi/ipmi.c b/sys/dev/ipmi/ipmi.c
index 8101717..314d4d6 100644
--- a/sys/dev/ipmi/ipmi.c
+++ b/sys/dev/ipmi/ipmi.c
@@ -603,6 +603,20 @@ ipmi_polled_enqueue_request(struct ipmi_softc *sc, struct ipmi_request *req)
*/
static int
+ipmi_reset_watchdog(struct ipmi_softc *sc)
+{
+ struct ipmi_request *req;
+ int error;
+
+ IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
+ IPMI_RESET_WDOG, 0, 0);
+ error = ipmi_submit_driver_request(sc, req, 0);
+ if (error)
+ device_printf(sc->ipmi_dev, "Failed to reset watchdog\n");
+ return (error);
+}
+
+static int
ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
{
struct ipmi_request *req;
@@ -613,7 +627,6 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
IPMI_ALLOC_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
IPMI_SET_WDOG, 6, 0);
-
if (sec) {
req->ir_request[0] = IPMI_SET_WD_TIMER_DONT_STOP
| IPMI_SET_WD_TIMER_SMS_OS;
@@ -630,24 +643,10 @@ ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
req->ir_request[4] = 0;
req->ir_request[5] = 0;
}
-
error = ipmi_submit_driver_request(sc, req, 0);
if (error)
device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
- else if (sec) {
- IPMI_INIT_DRIVER_REQUEST(req, IPMI_ADDR(IPMI_APP_REQUEST, 0),
- IPMI_RESET_WDOG, 0, 0);
-
- error = ipmi_submit_driver_request(sc, req, 0);
- if (error)
- device_printf(sc->ipmi_dev,
- "Failed to reset watchdog\n");
- }
-
return (error);
- /*
- dump_watchdog(sc);
- */
}
static void
@@ -665,12 +664,24 @@ ipmi_wd_event(void *arg, unsigned int cmd, int *error)
timeout = ((uint64_t)1 << cmd) / 1000000000;
if (timeout == 0)
timeout = 1;
- e = ipmi_set_watchdog(sc, timeout);
- if (e == 0) {
- *error = 0;
- sc->ipmi_watchdog_active = 1;
- } else
- (void)ipmi_set_watchdog(sc, 0);
+ if (timeout != sc->ipmi_watchdog_active) {
+ e = ipmi_set_watchdog(sc, timeout);
+ if (e == 0) {
+ sc->ipmi_watchdog_active = timeout;
+ } else {
+ (void)ipmi_set_watchdog(sc, 0);
+ sc->ipmi_watchdog_active = 0;
+ }
+ }
+ if (sc->ipmi_watchdog_active != 0) {
+ e = ipmi_reset_watchdog(sc);
+ if (e == 0) {
+ *error = 0;
+ } else {
+ (void)ipmi_set_watchdog(sc, 0);
+ sc->ipmi_watchdog_active = 0;
+ }
+ }
} else if (atomic_readandclear_int(&sc->ipmi_watchdog_active) != 0) {
e = ipmi_set_watchdog(sc, 0);
if (e != 0 && cmd == 0)
diff --git a/sys/dev/isci/isci_controller.c b/sys/dev/isci/isci_controller.c
index b0f4285..d3ec045 100644
--- a/sys/dev/isci/isci_controller.c
+++ b/sys/dev/isci/isci_controller.c
@@ -740,6 +740,11 @@ void isci_action(struct cam_sim *sim, union ccb *ccb)
}
break;
case XPT_SCSI_IO:
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
isci_io_request_execute_scsi_io(ccb, controller);
break;
#if __FreeBSD_version >= 900026
@@ -802,6 +807,7 @@ isci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
{
struct ISCI_REMOTE_DEVICE *dev;
struct ccb_hdr *ccb_h;
+ uint8_t *ptr;
int dev_idx;
KASSERT(mtx_owned(&controller->lock), ("controller lock not owned"));
@@ -821,8 +827,8 @@ isci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
if (ccb_h == NULL)
continue;
- isci_log_message(1, "ISCI", "release %p %x\n", ccb_h,
- ((union ccb *)ccb_h)->csio.cdb_io.cdb_bytes[0]);
+ ptr = scsiio_cdb_ptr(&((union ccb *)ccb_h)->csio);
+ isci_log_message(1, "ISCI", "release %p %x\n", ccb_h, *ptr);
dev->queued_ccb_in_progress = (union ccb *)ccb_h;
isci_io_request_execute_scsi_io(
diff --git a/sys/dev/isci/isci_io_request.c b/sys/dev/isci/isci_io_request.c
index e6b68fd..f86c126 100644
--- a/sys/dev/isci/isci_io_request.c
+++ b/sys/dev/isci/isci_io_request.c
@@ -86,6 +86,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
struct ISCI_REMOTE_DEVICE *isci_remote_device;
union ccb *ccb;
BOOL complete_ccb;
+ struct ccb_scsiio *csio;
complete_ccb = TRUE;
isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller);
@@ -93,7 +94,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
(struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device);
ccb = isci_request->ccb;
-
+ csio = &ccb->csio;
ccb->ccb_h.status &= ~CAM_STATUS_MASK;
switch (completion_status) {
@@ -124,7 +125,6 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
SCI_SSP_RESPONSE_IU_T * response_buffer;
uint32_t sense_length;
int error_code, sense_key, asc, ascq;
- struct ccb_scsiio *csio = &ccb->csio;
response_buffer = (SCI_SSP_RESPONSE_IU_T *)
scif_io_request_get_response_iu_address(
@@ -146,7 +146,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(1, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0],
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio),
csio->scsi_status, sense_key, asc, ascq);
break;
}
@@ -157,7 +157,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(0, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x remote device reset required\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio));
break;
case SCI_IO_FAILURE_TERMINATED:
@@ -165,7 +165,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(0, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio));
break;
case SCI_IO_FAILURE_INVALID_STATE:
@@ -208,7 +208,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
isci_log_message(1, "ISCI",
"isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n",
ccb->ccb_h.path_id, ccb->ccb_h.target_id,
- ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0],
+ ccb->ccb_h.target_lun, scsiio_cdb_ptr(csio),
completion_status);
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
break;
@@ -285,13 +285,13 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
* get a ready notification for this device.
*/
isci_log_message(1, "ISCI", "already queued %p %x\n",
- ccb, ccb->csio.cdb_io.cdb_bytes[0]);
+ ccb, scsiio_cdb_ptr(csio));
isci_remote_device->queued_ccb_in_progress = NULL;
} else {
isci_log_message(1, "ISCI", "queue %p %x\n", ccb,
- ccb->csio.cdb_io.cdb_bytes[0]);
+ scsiio_cdb_ptr(csio));
ccb->ccb_h.status |= CAM_SIM_QUEUED;
TAILQ_INSERT_TAIL(&isci_remote_device->queued_ccbs,
@@ -373,7 +373,7 @@ scif_cb_io_request_get_cdb_address(void * scif_user_io_request)
struct ISCI_IO_REQUEST *isci_request =
(struct ISCI_IO_REQUEST *)scif_user_io_request;
- return (isci_request->ccb->csio.cdb_io.cdb_bytes);
+ return (scsiio_cdb_ptr(&isci_request->ccb->csio));
}
/**
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index a9bdaf7..7172ec0 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -288,6 +288,8 @@ iscsi_session_terminate_task(struct iscsi_session *is,
struct iscsi_outstanding *io, bool requeue)
{
+ ISCSI_SESSION_LOCK_ASSERT(is);
+
if (io->io_ccb != NULL) {
io->io_ccb->ccb_h.status &= ~(CAM_SIM_QUEUED | CAM_STATUS_MASK);
if (requeue)
@@ -2220,6 +2222,7 @@ iscsi_action_scsiio(struct iscsi_session *is, union ccb *ccb)
error = icl_pdu_append_data(request, csio->data_ptr, len, M_NOWAIT);
if (error != 0) {
+ iscsi_outstanding_remove(is, io);
icl_pdu_free(request);
if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
xpt_freeze_devq(ccb->ccb_h.path, 1);
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index 28b7b7f..bffa8de 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -2554,7 +2554,8 @@ iwn_find_eeprom_channel(struct iwn_softc *sc, struct ieee80211_channel *c)
} else {
for (j = 0; j < 5; j++) {
for (i = 0; i < iwn_bands[j].nchan; i++) {
- if (iwn_bands[j].chan[i] == c->ic_ieee)
+ if (iwn_bands[j].chan[i] == c->ic_ieee &&
+ ((j == 0) ^ IEEE80211_IS_CHAN_A(c)) == 1)
return &sc->eeprom_channels[j][i];
}
}
@@ -8700,7 +8701,9 @@ iwn_panicked(void *arg0, int pending)
struct iwn_softc *sc = arg0;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+#if 0
int error;
+#endif
if (vap == NULL) {
printf("%s: null vap\n", __func__);
@@ -8708,8 +8711,18 @@ iwn_panicked(void *arg0, int pending)
}
device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; "
- "resetting...\n", __func__, vap->iv_state);
+ "restarting\n", __func__, vap->iv_state);
+ /*
+ * This is not enough work. We need to also reinitialise
+ * the correct transmit state for aggregation enabled queues,
+ * which has a very specific requirement of
+ * ring index = 802.11 seqno % 256. If we don't do this (which
+ * we definitely don't!) then the firmware will just panic again.
+ */
+#if 1
+ ieee80211_restart_all(ic);
+#else
IWN_LOCK(sc);
iwn_stop_locked(sc);
@@ -8726,6 +8739,7 @@ iwn_panicked(void *arg0, int pending)
}
IWN_UNLOCK(sc);
+#endif
}
static void
diff --git a/sys/dev/ixgbe/if_ix.c b/sys/dev/ixgbe/if_ix.c
index f0e218f..5e16fbd 100644
--- a/sys/dev/ixgbe/if_ix.c
+++ b/sys/dev/ixgbe/if_ix.c
@@ -4749,10 +4749,6 @@ ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS)
if ((error) || (req->newptr == NULL))
return (error);
- /* Checks to validate new value */
- if (adapter->advertise == advertise) /* no change */
- return (0);
-
return ixgbe_set_advertise(adapter, advertise);
}
@@ -4763,6 +4759,10 @@ ixgbe_set_advertise(struct adapter *adapter, int advertise)
struct ixgbe_hw *hw;
ixgbe_link_speed speed;
+ /* Checks to validate new value */
+ if (adapter->advertise == advertise) /* no change */
+ return (0);
+
hw = &adapter->hw;
dev = adapter->dev;
diff --git a/sys/dev/ixgbe/ix_txrx.c b/sys/dev/ixgbe/ix_txrx.c
index 00e5dc8..66bcb25 100644
--- a/sys/dev/ixgbe/ix_txrx.c
+++ b/sys/dev/ixgbe/ix_txrx.c
@@ -1753,7 +1753,6 @@ ixgbe_rxeof(struct ix_queue *que)
struct rx_ring *rxr = que->rxr;
struct ifnet *ifp = adapter->ifp;
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
int i, nextp, processed = 0;
u32 staterr = 0;
u32 count = adapter->rx_process_limit;
@@ -2003,10 +2002,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
IXGBE_RX_UNLOCK(rxr);
diff --git a/sys/dev/ixl/ixl_txrx.c b/sys/dev/ixl/ixl_txrx.c
index 0ae7433..ca6e252 100644
--- a/sys/dev/ixl/ixl_txrx.c
+++ b/sys/dev/ixl/ixl_txrx.c
@@ -1511,7 +1511,6 @@ ixl_rxeof(struct ixl_queue *que, int count)
struct ifnet *ifp = vsi->ifp;
#if defined(INET6) || defined(INET)
struct lro_ctrl *lro = &rxr->lro;
- struct lro_entry *queued;
#endif
int i, nextp, processed = 0;
union i40e_rx_desc *cur;
@@ -1735,10 +1734,7 @@ next_desc:
/*
* Flush any outstanding LRO work
*/
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
#endif
IXL_RX_UNLOCK(rxr);
diff --git a/sys/dev/le/lebuffer_sbus.c b/sys/dev/le/lebuffer_sbus.c
index 1254fc3..f2c7c5f 100644
--- a/sys/dev/le/lebuffer_sbus.c
+++ b/sys/dev/le/lebuffer_sbus.c
@@ -297,7 +297,7 @@ lebuffer_print_res(struct lebuffer_devinfo *ldi)
rv = 0;
rv += resource_list_print_type(&ldi->ldi_rl, "mem", SYS_RES_MEMORY,
- "%#lx");
- rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%ld");
+ "%#jx");
+ rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%jd");
return (rv);
}
diff --git a/sys/dev/mca/mca_bus.c b/sys/dev/mca/mca_bus.c
index 55ac9ed..2de61da 100644
--- a/sys/dev/mca/mca_bus.c
+++ b/sys/dev/mca/mca_bus.c
@@ -365,11 +365,11 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IOPORT, rid++))) {
if (rle->count == 1) {
- snprintf(buf, sizeof(buf), "%s%lx",
+ snprintf(buf, sizeof(buf), "%s%jx",
((rid == 1) ? "io 0x" : "0x"),
rle->start);
} else {
- snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
+ snprintf(buf, sizeof(buf), "%s%jx-0x%jx",
((rid == 1) ? "io 0x" : "0x"),
rle->start,
(rle->start + rle->count));
@@ -381,11 +381,11 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_MEMORY, rid++))) {
if (rle->count == 1) {
- snprintf(buf, sizeof(buf), "%s%lx",
+ snprintf(buf, sizeof(buf), "%s%jx",
((rid == 1) ? "mem 0x" : "0x"),
rle->start);
} else {
- snprintf(buf, sizeof(buf), "%s%lx-0x%lx",
+ snprintf(buf, sizeof(buf), "%s%jx-0x%jx",
((rid == 1) ? "mem 0x" : "0x"),
rle->start,
(rle->start + rle->count));
@@ -396,14 +396,14 @@ mca_print_child (device_t dev, device_t child)
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_IRQ, rid++))) {
- snprintf(buf, sizeof(buf), "irq %ld", rle->start);
+ snprintf(buf, sizeof(buf), "irq %jd", rle->start);
mca_reg_print(child, buf,
((rid == 1) ? &separator : NULL), &column);
}
rid = 0;
while ((rle = resource_list_find(&(m_dev->rl), SYS_RES_DRQ, rid++))) {
- snprintf(buf, sizeof(buf), "drq %lx", rle->start);
+ snprintf(buf, sizeof(buf), "drq %jx", rle->start);
mca_reg_print(child, buf,
((rid == 1) ? &separator : NULL), &column);
}
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index ddcc853..c224186 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -2141,7 +2141,7 @@ mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
pass = &cm->cm_frame->pass;
bzero(pass->cdb, 16);
pass->header.cmd = MFI_CMD_PD_SCSI_IO;
- switch (bio->bio_cmd & 0x03) {
+ switch (bio->bio_cmd) {
case BIO_READ:
flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
readop = 1;
@@ -2200,7 +2200,7 @@ mfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
bzero(cm->cm_frame, sizeof(union mfi_frame));
cm->cm_frame->header.context = context;
io = &cm->cm_frame->io;
- switch (bio->bio_cmd & 0x03) {
+ switch (bio->bio_cmd) {
case BIO_READ:
io->header.cmd = MFI_CMD_LD_READ;
flags = MFI_CMD_DATAIN | MFI_CMD_BIO;
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
index 48339be..230dfcc 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -322,9 +322,6 @@ mlx5e_decompress_cqes(struct mlx5e_cq *cq)
static int
mlx5e_poll_rx_cq(struct mlx5e_rq *rq, int budget)
{
-#ifndef HAVE_TURBO_LRO
- struct lro_entry *queued;
-#endif
int i;
for (i = 0; i < budget; i++) {
@@ -399,10 +396,7 @@ wq_ll_pop:
/* ensure cq space is freed before enabling more cqes */
wmb();
#ifndef HAVE_TURBO_LRO
- while ((queued = SLIST_FIRST(&rq->lro.lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&rq->lro.lro_active, next);
- tcp_lro_flush(&rq->lro, queued);
- }
+ tcp_lro_flush_all(&rq->lro);
#endif
return (i);
}
diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c
index 5dc0626..5b24a6d 100644
--- a/sys/dev/mmc/host/dwmmc.c
+++ b/sys/dev/mmc/host/dwmmc.c
@@ -1178,3 +1178,4 @@ static devclass_t dwmmc_devclass;
DRIVER_MODULE(dwmmc, simplebus, dwmmc_driver, dwmmc_devclass, 0, 0);
DRIVER_MODULE(dwmmc, ofwbus, dwmmc_driver, dwmmc_devclass, 0, 0);
DRIVER_MODULE(mmc, dwmmc, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(dwmmc, mmc, 1, 1, 1);
diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c
index a65ff41..9f88079 100644
--- a/sys/dev/mmc/mmc.c
+++ b/sys/dev/mmc/mmc.c
@@ -1811,3 +1811,5 @@ driver_t mmc_driver = {
sizeof(struct mmc_softc),
};
devclass_t mmc_devclass;
+
+MODULE_VERSION(mmc, 1);
diff --git a/sys/dev/mmc/mmcreg.h b/sys/dev/mmc/mmcreg.h
index f454ddb..b169d26 100644
--- a/sys/dev/mmc/mmcreg.h
+++ b/sys/dev/mmc/mmcreg.h
@@ -85,8 +85,11 @@ struct mmc_command {
#define MMC_RSP_R1B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
#define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
#define MMC_RSP_R3 (MMC_RSP_PRESENT)
-#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC)
-#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC)
+#define MMC_RSP_R4 (MMC_RSP_PRESENT)
+#define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R5B (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
#define MMC_RSP(x) ((x) & MMC_RSP_MASK)
uint32_t retries;
uint32_t error;
diff --git a/sys/dev/mvs/mvs_pci.c b/sys/dev/mvs/mvs_pci.c
index 316ac00..b3262f8 100644
--- a/sys/dev/mvs/mvs_pci.c
+++ b/sys/dev/mvs/mvs_pci.c
@@ -396,7 +396,7 @@ mvs_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct mvs_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = HC_BASE(unit >> 2) + PORT_BASE(unit & 0x03);
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/mvs/mvs_soc.c b/sys/dev/mvs/mvs_soc.c
index d4ecd8f..b34df30 100644
--- a/sys/dev/mvs/mvs_soc.c
+++ b/sys/dev/mvs/mvs_soc.c
@@ -342,7 +342,7 @@ mvs_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct mvs_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = PORT_BASE(unit & 0x03);
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/mxge/if_mxge.c b/sys/dev/mxge/if_mxge.c
index 928917f..f78b34b 100644
--- a/sys/dev/mxge/if_mxge.c
+++ b/sys/dev/mxge/if_mxge.c
@@ -2819,11 +2819,7 @@ mxge_clean_rx_done(struct mxge_slice_state *ss)
break;
}
#if defined(INET) || defined (INET6)
- while (!SLIST_EMPTY(&ss->lc.lro_active)) {
- struct lro_entry *lro = SLIST_FIRST(&ss->lc.lro_active);
- SLIST_REMOVE_HEAD(&ss->lc.lro_active, next);
- tcp_lro_flush(&ss->lc, lro);
- }
+ tcp_lro_flush_all(&ss->lc);
#endif
}
@@ -4612,7 +4608,7 @@ mxge_add_msix_irqs(mxge_softc_t *sc)
device_printf(sc->dev, "using %d msix IRQs:",
sc->num_slices);
for (i = 0; i < sc->num_slices; i++)
- printf(" %ld", rman_get_start(sc->msix_irq_res[i]));
+ printf(" %jd", rman_get_start(sc->msix_irq_res[i]));
printf("\n");
}
return (0);
@@ -4668,7 +4664,7 @@ mxge_add_single_irq(mxge_softc_t *sc)
return ENXIO;
}
if (mxge_verbose)
- device_printf(sc->dev, "using %s irq %ld\n",
+ device_printf(sc->dev, "using %s irq %jd\n",
sc->legacy_irq ? "INTx" : "MSI",
rman_get_start(sc->irq_res));
err = bus_setup_intr(sc->dev, sc->irq_res,
@@ -4823,7 +4819,7 @@ mxge_attach(device_t dev)
sc->sram = rman_get_virtual(sc->mem_res);
sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100;
if (sc->sram_size > rman_get_size(sc->mem_res)) {
- device_printf(dev, "impossible memory region size %ld\n",
+ device_printf(dev, "impossible memory region size %jd\n",
rman_get_size(sc->mem_res));
err = ENXIO;
goto abort_with_mem_res;
diff --git a/sys/dev/ncr/ncr.c b/sys/dev/ncr/ncr.c
index 6c941e1..111cd69 100644
--- a/sys/dev/ncr/ncr.c
+++ b/sys/dev/ncr/ncr.c
@@ -3860,6 +3860,16 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
csio = &ccb->csio;
/*
+ * Make sure we support this request. We can't do
+ * PHYS pointers.
+ */
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
+ }
+
+ /*
* Last time we need to check if this CCB needs to
* be aborted.
*/
@@ -4070,8 +4080,7 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
/*
** command
*/
- /* XXX JGibbs - Support other command types */
- cp->phys.cmd.addr = vtophys (csio->cdb_io.cdb_bytes);
+ cp->phys.cmd.addr = vtophys (scsiio_cdb_ptr(csio));
cp->phys.cmd.size = csio->cdb_len;
/*
** sense command
@@ -4083,7 +4092,6 @@ ncr_action (struct cam_sim *sim, union ccb *ccb)
*/
cp->sensecmd[0] = 0x03;
cp->sensecmd[1] = ccb->ccb_h.target_lun << 5;
- cp->sensecmd[4] = sizeof(struct scsi_sense_data);
cp->sensecmd[4] = csio->sense_len;
/*
** sense data
diff --git a/sys/dev/nctgpio/nctgpio.c b/sys/dev/nctgpio/nctgpio.c
new file mode 100644
index 0000000..ab547c0
--- /dev/null
+++ b/sys/dev/nctgpio/nctgpio.c
@@ -0,0 +1,802 @@
+/*-
+ * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ */
+
+/*
+ * Nuvoton GPIO driver.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/eventhandler.h>
+#include <sys/lock.h>
+
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/gpio.h>
+
+#include <isa/isavar.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#include "gpio_if.h"
+
+/*
+ * Global configuration registers (CR).
+ */
+#define NCT_CR_LDN 0x07 /* Logical Device Number */
+#define NCT_CR_CHIP_ID 0x20 /* Chip ID */
+#define NCT_CR_CHIP_ID_H 0x20 /* Chip ID (high byte) */
+#define NCT_CR_CHIP_ID_L 0x21 /* Chip ID (low byte) */
+#define NCT_CR_OPT_1 0x26 /* Global Options (1) */
+
+/* Logical Device Numbers. */
+#define NCT_LDN_GPIO 0x07
+#define NCT_LDN_GPIO_CFG 0x08
+#define NCT_LDN_GPIO_MODE 0x0f
+
+/* Logical Device 7 */
+#define NCT_LD7_GPIO_ENABLE 0x30
+#define NCT_LD7_GPIO0_IOR 0xe0
+#define NCT_LD7_GPIO0_DAT 0xe1
+#define NCT_LD7_GPIO0_INV 0xe2
+#define NCT_LD7_GPIO0_DST 0xe3
+#define NCT_LD7_GPIO1_IOR 0xe4
+#define NCT_LD7_GPIO1_DAT 0xe5
+#define NCT_LD7_GPIO1_INV 0xe6
+#define NCT_LD7_GPIO1_DST 0xe7
+
+/* Logical Device F */
+#define NCT_LDF_GPIO0_OUTCFG 0xe0
+#define NCT_LDF_GPIO1_OUTCFG 0xe1
+
+#define NCT_EXTFUNC_ENTER 0x87
+#define NCT_EXTFUNC_EXIT 0xaa
+
+#define NCT_MAX_PIN 15
+#define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN)
+
+#define NCT_PIN_BIT(_p) (1 << ((_p) % 8))
+
+#define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \
+ GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \
+ GPIO_PIN_INVIN | GPIO_PIN_INVOUT)
+
+struct nct_softc {
+ device_t dev;
+ device_t busdev;
+ struct mtx mtx;
+ struct resource *portres;
+ int rid;
+ struct gpio_pin pins[NCT_MAX_PIN];
+};
+
+#define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \
+ device_get_nameunit(dev), NULL, MTX_DEF)
+#define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx)
+#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx)
+#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx)
+#define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED)
+#define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED)
+
+#define NCT_BARRIER_WRITE(_sc) \
+ bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE)
+
+#define NCT_BARRIER_READ_WRITE(_sc) \
+ bus_barrier((_sc)->portres, 0, 2, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+static void ext_cfg_enter(struct nct_softc *);
+static void ext_cfg_exit(struct nct_softc *);
+
+/*
+ * Potential Extended Function Enable Register addresses.
+ * Same address as EFIR.
+ */
+uint8_t probe_addrs[] = {0x2e, 0x4e};
+
+struct nuvoton_vendor_device_id {
+ uint16_t chip_id;
+ const char * descr;
+} nct_devs[] = {
+ {
+ .chip_id = 0x1061,
+ .descr = "Nuvoton NCT5104D",
+ },
+ {
+ .chip_id = 0xc452,
+ .descr = "Nuvoton NCT5104D (PC-Engines APU)",
+ },
+};
+
+static void
+write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, reg);
+ NCT_BARRIER_WRITE(sc);
+ bus_write_1(sc->portres, 1, value);
+ NCT_BARRIER_WRITE(sc);
+}
+
+static uint8_t
+read_cfg_reg_1(struct nct_softc *sc, uint8_t reg)
+{
+ uint8_t value;
+
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, reg);
+ NCT_BARRIER_READ_WRITE(sc);
+ value = bus_read_1(sc->portres, 1);
+ NCT_BARRIER_READ_WRITE(sc);
+
+ return (value);
+}
+
+static uint16_t
+read_cfg_reg_2(struct nct_softc *sc, uint8_t reg)
+{
+ uint16_t value;
+
+ value = read_cfg_reg_1(sc, reg) << 8;
+ value |= read_cfg_reg_1(sc, reg + 1);
+
+ return (value);
+}
+
+/*
+ * Enable extended function mode.
+ *
+ */
+static void
+ext_cfg_enter(struct nct_softc *sc)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
+ NCT_BARRIER_WRITE(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
+ NCT_BARRIER_WRITE(sc);
+}
+
+/*
+ * Disable extended function mode.
+ *
+ */
+static void
+ext_cfg_exit(struct nct_softc *sc)
+{
+ GPIO_ASSERT_LOCKED(sc);
+ bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT);
+ NCT_BARRIER_WRITE(sc);
+}
+
+/*
+ * Select a Logical Device.
+ */
+static void
+select_ldn(struct nct_softc *sc, uint8_t ldn)
+{
+ write_cfg_reg_1(sc, NCT_CR_LDN, ldn);
+}
+
+/*
+ * Get the GPIO Input/Output register address
+ * for a pin.
+ */
+static uint8_t
+nct_ior_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_IOR;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_IOR;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Data register address for a pin.
+ */
+static uint8_t
+nct_dat_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_DAT;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_DAT;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Inversion register address
+ * for a pin.
+ */
+static uint8_t
+nct_inv_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LD7_GPIO0_INV;
+ if (pin_num > 7)
+ addr = NCT_LD7_GPIO1_INV;
+
+ return (addr);
+}
+
+/*
+ * Get the GPIO Output Configuration/Mode
+ * register address for a pin.
+ */
+static uint8_t
+nct_outcfg_addr(uint32_t pin_num)
+{
+ uint8_t addr;
+
+ addr = NCT_LDF_GPIO0_OUTCFG;
+ if (pin_num > 7)
+ addr = NCT_LDF_GPIO1_OUTCFG;
+
+ return (addr);
+}
+
+/*
+ * Set a pin to output mode.
+ */
+static void
+nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+ ior &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, ior);
+}
+
+/*
+ * Set a pin to input mode.
+ */
+static void
+nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+ ior |= NCT_PIN_BIT(pin_num);
+ write_cfg_reg_1(sc, reg, ior);
+}
+
+/*
+ * Check whether a pin is configured as an input.
+ */
+static bool
+nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t ior;
+
+ reg = nct_ior_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ ior = read_cfg_reg_1(sc, reg);
+
+ return (ior & NCT_PIN_BIT(pin_num));
+}
+
+/*
+ * Write a value to an output pin.
+ */
+static void
+nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data)
+{
+ uint8_t reg;
+ uint8_t value;
+
+ reg = nct_dat_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ value = read_cfg_reg_1(sc, reg);
+ if (data)
+ value |= NCT_PIN_BIT(pin_num);
+ else
+ value &= ~(NCT_PIN_BIT(pin_num));
+
+ write_cfg_reg_1(sc, reg, value);
+}
+
+static bool
+nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+
+ reg = nct_dat_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+
+ return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+ inv |= (NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, inv);
+}
+
+static void
+nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+ inv &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, inv);
+}
+
+static bool
+nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t inv;
+
+ reg = nct_inv_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO);
+ inv = read_cfg_reg_1(sc, reg);
+
+ return (inv & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+ outcfg |= (NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, outcfg);
+}
+
+static void
+nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+ outcfg &= ~(NCT_PIN_BIT(pin_num));
+ write_cfg_reg_1(sc, reg, outcfg);
+}
+
+static bool
+nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
+{
+ uint8_t reg;
+ uint8_t outcfg;
+
+ reg = nct_outcfg_addr(pin_num);
+ select_ldn(sc, NCT_LDN_GPIO_MODE);
+ outcfg = read_cfg_reg_1(sc, reg);
+
+ return (outcfg & NCT_PIN_BIT(pin_num));
+}
+
+static void
+nct_identify(driver_t *driver, device_t parent)
+{
+ if (device_find_child(parent, driver->name, 0) != NULL)
+ return;
+
+ BUS_ADD_CHILD(parent, 0, driver->name, 0);
+}
+
+static int
+nct_probe(device_t dev)
+{
+ int i, j;
+ int rc;
+ struct nct_softc *sc;
+ uint16_t chipid;
+
+ /* Make sure we do not claim some ISA PNP device. */
+ if (isa_get_logicalid(dev) != 0)
+ return (ENXIO);
+
+ sc = device_get_softc(dev);
+
+ for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) {
+ sc->rid = 0;
+ sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
+ probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE);
+ if (sc->portres == NULL)
+ continue;
+
+ GPIO_LOCK_INIT(sc);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_enter(sc);
+ chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+
+ GPIO_LOCK_DESTROY(sc);
+
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+ bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid);
+
+ for (j = 0; j < sizeof(nct_devs) / sizeof(*nct_devs); j++) {
+ if (chipid == nct_devs[j].chip_id) {
+ rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2);
+ if (rc != 0) {
+ device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]);
+ continue;
+ }
+ device_set_desc(dev, nct_devs[j].descr);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+ }
+ return (ENXIO);
+}
+
+static int
+nct_attach(device_t dev)
+{
+ struct nct_softc *sc;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ sc->rid = 0;
+ sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
+ 0ul, ~0ul, 2, RF_ACTIVE);
+ if (sc->portres == NULL) {
+ device_printf(dev, "cannot allocate ioport\n");
+ return (ENXIO);
+ }
+
+ GPIO_LOCK_INIT(sc);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_enter(sc);
+ select_ldn(sc, NCT_LDN_GPIO);
+ /* Enable gpio0 and gpio1. */
+ write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE,
+ read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03);
+
+ for (i = 0; i <= NCT_MAX_PIN; i++) {
+ struct gpio_pin *pin;
+
+ pin = &sc->pins[i];
+ pin->gp_pin = i;
+ pin->gp_caps = NCT_GPIO_CAPS;
+ pin->gp_flags = 0;
+
+ snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i);
+ pin->gp_name[GPIOMAXNAME - 1] = '\0';
+
+ if (nct_pin_is_input(sc, i))
+ pin->gp_flags |= GPIO_PIN_INPUT;
+ else
+ pin->gp_flags |= GPIO_PIN_OUTPUT;
+
+ if (nct_pin_is_opendrain(sc, i))
+ pin->gp_flags |= GPIO_PIN_OPENDRAIN;
+ else
+ pin->gp_flags |= GPIO_PIN_PUSHPULL;
+
+ if (nct_pin_is_inverted(sc, i))
+ pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
+ }
+ GPIO_UNLOCK(sc);
+
+ sc->busdev = gpiobus_attach_bus(dev);
+ if (sc->busdev == NULL) {
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+ GPIO_LOCK_DESTROY(sc);
+
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+nct_detach(device_t dev)
+{
+ struct nct_softc *sc;
+
+ sc = device_get_softc(dev);
+ gpiobus_detach_bus(dev);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ ext_cfg_exit(sc);
+ GPIO_UNLOCK(sc);
+
+ /* Cleanup resources. */
+ bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
+
+ GPIO_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_t
+nct_gpio_get_bus(device_t dev)
+{
+ struct nct_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sc->busdev);
+}
+
+static int
+nct_gpio_pin_max(device_t dev, int *npins)
+{
+ *npins = NCT_MAX_PIN;
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ nct_write_pin(sc, pin_num, pin_value);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *pin_value = nct_read_pin(sc, pin_num);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ if (nct_read_pin(sc, pin_num))
+ nct_write_pin(sc, pin_num, 0);
+ else
+ nct_write_pin(sc, pin_num, 1);
+
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *caps = sc->pins[pin_num].gp_caps;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ *flags = sc->pins[pin_num].gp_flags;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
+{
+ struct nct_softc *sc;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
+{
+ struct nct_softc *sc;
+ struct gpio_pin *pin;
+
+ if (!NCT_IS_VALID_PIN(pin_num))
+ return (EINVAL);
+
+ sc = device_get_softc(dev);
+ pin = &sc->pins[pin_num];
+ if ((flags & pin->gp_caps) != flags)
+ return (EINVAL);
+
+ GPIO_ASSERT_UNLOCKED(sc);
+ GPIO_LOCK(sc);
+ if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
+ (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_INPUT)
+ nct_set_pin_is_input(sc, pin_num);
+ else
+ nct_set_pin_is_output(sc, pin_num);
+ }
+
+ if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
+ if (flags & GPIO_PIN_INPUT) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
+ (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_OPENDRAIN)
+ nct_set_pin_opendrain(sc, pin_num);
+ else
+ nct_set_pin_pushpull(sc, pin_num);
+ }
+
+ if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
+ if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) !=
+ (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
+ GPIO_UNLOCK(sc);
+ return (EINVAL);
+ }
+
+ if (flags & GPIO_PIN_INVIN)
+ nct_set_pin_is_inverted(sc, pin_num);
+ else
+ nct_set_pin_not_inverted(sc, pin_num);
+ }
+
+ pin->gp_flags = flags;
+ GPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static device_method_t nct_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, nct_identify),
+ DEVMETHOD(device_probe, nct_probe),
+ DEVMETHOD(device_attach, nct_attach),
+ DEVMETHOD(device_detach, nct_detach),
+
+ /* GPIO */
+ DEVMETHOD(gpio_get_bus, nct_gpio_get_bus),
+ DEVMETHOD(gpio_pin_max, nct_gpio_pin_max),
+ DEVMETHOD(gpio_pin_get, nct_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, nct_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle),
+ DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags),
+
+ DEVMETHOD_END
+};
+
+static driver_t nct_isa_driver = {
+ "gpio",
+ nct_methods,
+ sizeof(struct nct_softc)
+};
+
+static devclass_t nct_devclass;
+
+DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL);
+MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c
index bc5b452..9129960 100644
--- a/sys/dev/netmap/netmap_generic.c
+++ b/sys/dev/netmap/netmap_generic.c
@@ -129,8 +129,9 @@ static inline struct mbuf *
netmap_get_mbuf(int len)
{
struct mbuf *m;
- m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR | M_NOFREE);
+ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (m) {
+ m->m_flags |= M_NOFREE; /* XXXNP: Almost certainly incorrect. */
m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save
m->m_ext.ext_free = (void *)netmap_default_mbuf_destructor;
m->m_ext.ext_type = EXT_EXTREF;
diff --git a/sys/dev/oce/oce_if.c b/sys/dev/oce/oce_if.c
index f0cce5f..3704612 100644
--- a/sys/dev/oce/oce_if.c
+++ b/sys/dev/oce/oce_if.c
@@ -1497,16 +1497,12 @@ static void
oce_rx_flush_lro(struct oce_rq *rq)
{
struct lro_ctrl *lro = &rq->lro;
- struct lro_entry *queued;
POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
if (!IF_LRO_ENABLED(sc))
return;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
rq->lro_pkts_queued = 0;
return;
diff --git a/sys/dev/ofw/ofw_iicbus.c b/sys/dev/ofw/ofw_iicbus.c
index c0fa054..73cad7c 100644
--- a/sys/dev/ofw/ofw_iicbus.c
+++ b/sys/dev/ofw/ofw_iicbus.c
@@ -80,8 +80,10 @@ static devclass_t ofwiicbus_devclass;
DEFINE_CLASS_1(iicbus, ofw_iicbus_driver, ofw_iicbus_methods,
sizeof(struct iicbus_softc), iicbus_driver);
-DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0);
-DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass, 0, 0);
+EARLY_DRIVER_MODULE(ofw_iicbus, iicbb, ofw_iicbus_driver, ofwiicbus_devclass,
+ 0, 0, BUS_PASS_BUS);
+EARLY_DRIVER_MODULE(ofw_iicbus, iichb, ofw_iicbus_driver, ofwiicbus_devclass,
+ 0, 0, BUS_PASS_BUS);
MODULE_VERSION(ofw_iicbus, 1);
MODULE_DEPEND(ofw_iicbus, iicbus, 1, 1, 1);
diff --git a/sys/dev/ofw/ofwbus.c b/sys/dev/ofw/ofwbus.c
index 8eb5dd5..fc43410 100644
--- a/sys/dev/ofw/ofwbus.c
+++ b/sys/dev/ofw/ofwbus.c
@@ -200,8 +200,8 @@ ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
start = rle->start;
- count = ulmax(count, rle->count);
- end = ulmax(rle->end, start + count - 1);
+ count = ummax(count, rle->count);
+ end = ummax(rle->end, start + count - 1);
}
switch (type) {
diff --git a/sys/dev/ofw/ofwpci.c b/sys/dev/ofw/ofwpci.c
new file mode 100644
index 0000000..2872fe1
--- /dev/null
+++ b/sys/dev/ofw/ofwpci.c
@@ -0,0 +1,628 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_pci.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/ofwpci.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include "pcib_if.h"
+
+/*
+ * If it is necessary to set another value of this for
+ * some platforms it should be set at fdt.h file
+ */
+#ifndef PCI_MAP_INTR
+#define PCI_MAP_INTR 4
+#endif
+
+#define PCI_INTR_PINS 4
+
+/*
+ * bus interface.
+ */
+static struct resource * ofw_pci_alloc_resource(device_t, device_t,
+ int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
+static int ofw_pci_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static int ofw_pci_adjust_resource(device_t, device_t, int,
+ struct resource *, rman_res_t, rman_res_t);
+
+#ifdef __powerpc__
+static bus_space_tag_t ofw_pci_bus_get_bus_tag(device_t, device_t);
+#endif
+
+/*
+ * pcib interface
+ */
+static int ofw_pci_maxslots(device_t);
+
+/*
+ * ofw_bus interface
+ */
+static phandle_t ofw_pci_get_node(device_t, device_t);
+
+/*
+ * local methods
+ */
+static int ofw_pci_fill_ranges(phandle_t, struct ofw_pci_range *);
+
+/*
+ * Driver methods.
+ */
+static device_method_t ofw_pci_methods[] = {
+
+ /* Device interface */
+ DEVMETHOD(device_attach, ofw_pci_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar),
+ DEVMETHOD(bus_write_ivar, ofw_pci_write_ivar),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, ofw_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, ofw_pci_release_resource),
+ DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, ofw_pci_deactivate_resource),
+ DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource),
+#ifdef __powerpc__
+ DEVMETHOD(bus_get_bus_tag, ofw_pci_bus_get_bus_tag),
+#endif
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, ofw_pci_maxslots),
+ DEVMETHOD(pcib_route_interrupt, ofw_pci_route_interrupt),
+
+ /* ofw_bus interface */
+ DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(ofw_pci, ofw_pci_driver, ofw_pci_methods, 0);
+
+int
+ofw_pci_init(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ phandle_t node;
+ u_int32_t busrange[2];
+ struct ofw_pci_range *rp;
+ int error;
+ struct ofw_pci_cell_info *cell_info;
+
+ node = ofw_bus_get_node(dev);
+ sc = device_get_softc(dev);
+ sc->sc_initialized = 1;
+ sc->sc_range = NULL;
+
+ cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ sc->sc_cell_info = cell_info;
+
+ if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
+ busrange[0] = 0;
+
+ sc->sc_dev = dev;
+ sc->sc_node = node;
+ sc->sc_bus = busrange[0];
+
+ if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
+ phandle_t c;
+ int n, i;
+
+ sc->sc_nrange = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_nranges(c, cell_info);
+ if (n > 0)
+ sc->sc_nrange += n;
+ }
+ if (sc->sc_nrange == 0) {
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ i = 0;
+ for (c = OF_child(node); c != 0; c = OF_peer(c)) {
+ n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
+ if (n > 0)
+ i += n;
+ }
+ KASSERT(i == sc->sc_nrange, ("range count mismatch"));
+ } else {
+ sc->sc_nrange = ofw_pci_nranges(node, cell_info);
+ if (sc->sc_nrange <= 0) {
+ device_printf(dev, "could not getranges\n");
+ error = ENXIO;
+ goto out;
+ }
+ sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
+ M_DEVBUF, M_WAITOK);
+ ofw_pci_fill_ranges(node, sc->sc_range);
+ }
+
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "PCI I/O Ports";
+ error = rman_init(&sc->sc_io_rman);
+ if (error) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "PCI Memory";
+ error = rman_init(&sc->sc_mem_rman);
+ if (error) {
+ device_printf(dev, "rman_init() failed. error = %d\n", error);
+ goto out;
+ }
+
+ for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
+ rp->pci_hi != 0; rp++) {
+ error = 0;
+
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_CONFIG:
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ error = rman_manage_region(&sc->sc_io_rman, rp->pci,
+ rp->pci + rp->size - 1);
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ error = rman_manage_region(&sc->sc_mem_rman, rp->pci,
+ rp->pci + rp->size - 1);
+ break;
+ }
+
+ if (error) {
+ device_printf(dev,
+ "rman_manage_region(%x, %#jx, %#jx) failed. "
+ "error = %d\n", rp->pci_hi &
+ OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
+ rp->pci + rp->size - 1, error);
+ goto out;
+ }
+ }
+
+ ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
+ return (0);
+
+out:
+ free(cell_info, M_DEVBUF);
+ free(sc->sc_range, M_DEVBUF);
+ rman_fini(&sc->sc_io_rman);
+ rman_fini(&sc->sc_mem_rman);
+
+ return (error);
+}
+
+int
+ofw_pci_attach(device_t dev)
+{
+ struct ofw_pci_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
+ if (!sc->sc_initialized) {
+ error = ofw_pci_init(dev);
+ if (error)
+ return (error);
+ }
+
+ device_add_child(dev, "pci", -1);
+ return (bus_generic_attach(dev));
+}
+
+static int
+ofw_pci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+int
+ofw_pci_route_interrupt(device_t bus, device_t dev, int pin)
+{
+ struct ofw_pci_softc *sc;
+ struct ofw_pci_register reg;
+ uint32_t pintr, mintr[PCI_MAP_INTR];
+ int intrcells;
+ phandle_t iparent;
+
+ sc = device_get_softc(bus);
+ pintr = pin;
+
+ /* Fabricate imap information in case this isn't an OFW device */
+ bzero(&reg, sizeof(reg));
+ reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
+ (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
+ (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
+
+ intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
+ &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
+ mintr, sizeof(mintr), &iparent);
+ if (intrcells != 0) {
+ pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
+ return (pintr);
+ }
+
+ /*
+ * Maybe it's a real interrupt, not an intpin
+ */
+ if (pin > PCI_INTR_PINS)
+ return (pin);
+
+ device_printf(bus, "could not route pin %d for device %d.%d\n",
+ pin, pci_get_slot(dev), pci_get_function(dev));
+ return (PCI_INVALID_IRQ);
+}
+
+int
+ofw_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = device_get_unit(dev);
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_bus;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_bus = value;
+ return (0);
+ default:
+ break;
+ }
+
+ return (ENOENT);
+}
+
+int
+ofw_pci_nranges(phandle_t node, struct ofw_pci_cell_info *info)
+{
+ ssize_t nbase_ranges;
+
+ if (info == NULL)
+ return (-1);
+
+ info->host_address_cells = 1;
+ info->size_cells = 2;
+ info->pci_address_cell = 3;
+
+ OF_getencprop(OF_parent(node), "#address-cells",
+ &(info->host_address_cells), sizeof(info->host_address_cells));
+ OF_getencprop(node, "#address-cells",
+ &(info->pci_address_cell), sizeof(info->pci_address_cell));
+ OF_getencprop(node, "#size-cells", &(info->size_cells),
+ sizeof(info->size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+
+ return (nbase_ranges / sizeof(cell_t) /
+ (info->pci_address_cell + info->host_address_cells +
+ info->size_cells));
+}
+
+static struct resource *
+ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct ofw_pci_softc *sc;
+ struct resource *rv;
+ struct rman *rm;
+ int needactivate;
+
+ needactivate = flags & RF_ACTIVE;
+ flags &= ~RF_ACTIVE;
+
+ sc = device_get_softc(bus);
+
+ switch (type) {
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ break;
+
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ break;
+
+ case SYS_RES_IRQ:
+ return (bus_alloc_resource(bus, type, rid, start, end, count,
+ flags));
+
+ default:
+ device_printf(bus, "unknown resource request from %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL) {
+ device_printf(bus, "failed to reserve resource for %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv) != 0) {
+ device_printf(bus,
+ "failed to activate resource for %s\n",
+ device_get_nameunit(child));
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ofw_pci_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+
+ if (rman_get_flags(res) & RF_ACTIVE) {
+ int error = bus_deactivate_resource(child, type, rid, res);
+ if (error)
+ return error;
+ }
+
+ return (rman_release_resource(res));
+}
+
+static int
+ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+ struct ofw_pci_softc *sc;
+ bus_space_handle_t handle;
+ bus_space_tag_t tag;
+ int rv;
+
+ sc = device_get_softc(bus);
+
+ if (type == SYS_RES_IRQ) {
+ return (bus_activate_resource(bus, type, rid, res));
+ }
+ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
+ struct ofw_pci_range *rp;
+ vm_paddr_t start;
+ int space;
+
+ start = (vm_paddr_t)rman_get_start(res);
+
+ /*
+ * Map this through the ranges list
+ */
+ for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
+ rp->pci_hi != 0; rp++) {
+ if (start < rp->pci || start >= rp->pci + rp->size)
+ continue;
+
+ switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
+ case OFW_PCI_PHYS_HI_SPACE_IO:
+ space = SYS_RES_IOPORT;
+ break;
+ case OFW_PCI_PHYS_HI_SPACE_MEM32:
+ case OFW_PCI_PHYS_HI_SPACE_MEM64:
+ space = SYS_RES_MEMORY;
+ break;
+ default:
+ space = -1;
+ }
+
+ if (type == space) {
+ start += (rp->host - rp->pci);
+ break;
+ }
+ }
+
+ if (bootverbose)
+ printf("ofw_pci mapdev: start %jx, len %jd\n",
+ (rman_res_t)start, rman_get_size(res));
+
+ tag = BUS_GET_BUS_TAG(child, child);
+ if (tag == NULL)
+ return (ENOMEM);
+
+ rman_set_bustag(res, tag);
+ rv = bus_space_map(tag, start,
+ rman_get_size(res), 0, &handle);
+ if (rv != 0)
+ return (ENOMEM);
+
+ rman_set_bushandle(res, handle);
+ rman_set_virtual(res, (void *)handle); /* XXX for powerpc only ? */
+ }
+
+ return (rman_activate_resource(res));
+}
+
+#ifdef __powerpc__
+static bus_space_tag_t
+ofw_pci_bus_get_bus_tag(device_t bus, device_t child)
+{
+
+ return (&bs_le_tag);
+}
+#endif
+
+static int
+ofw_pci_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *res)
+{
+
+ /*
+ * If this is a memory resource, unmap it.
+ */
+ if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
+ u_int32_t psize;
+
+ psize = rman_get_size(res);
+ pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
+ }
+
+ return (rman_deactivate_resource(res));
+}
+
+static int
+ofw_pci_adjust_resource(device_t bus, device_t child, int type,
+ struct resource *res, rman_res_t start, rman_res_t end)
+{
+ struct rman *rm = NULL;
+ struct ofw_pci_softc *sc = device_get_softc(bus);
+
+ KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
+ ("active resources cannot be adjusted"));
+ if (rman_get_flags(res) & RF_ACTIVE)
+ return (EINVAL);
+
+ switch (type) {
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ break;
+ default:
+ return (ENXIO);
+ }
+
+ if (!rman_is_region_manager(res, rm))
+ return (EINVAL);
+
+ return (rman_adjust_resource(res, start, end));
+}
+
+static phandle_t
+ofw_pci_get_node(device_t bus, device_t dev)
+{
+ struct ofw_pci_softc *sc;
+
+ sc = device_get_softc(bus);
+ /* We only have one child, the PCI bus, which needs our own node. */
+
+ return (sc->sc_node);
+}
+
+static int
+ofw_pci_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
+{
+ int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
+ cell_t *base_ranges;
+ ssize_t nbase_ranges;
+ int nranges;
+ int i, j, k;
+
+ OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
+ sizeof(host_address_cells));
+ OF_getencprop(node, "#address-cells", &pci_address_cells,
+ sizeof(pci_address_cells));
+ OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
+
+ nbase_ranges = OF_getproplen(node, "ranges");
+ if (nbase_ranges <= 0)
+ return (-1);
+ nranges = nbase_ranges / sizeof(cell_t) /
+ (pci_address_cells + host_address_cells + size_cells);
+
+ base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
+
+ for (i = 0, j = 0; i < nranges; i++) {
+ ranges[i].pci_hi = base_ranges[j++];
+ ranges[i].pci = 0;
+ for (k = 0; k < pci_address_cells - 1; k++) {
+ ranges[i].pci <<= 32;
+ ranges[i].pci |= base_ranges[j++];
+ }
+ ranges[i].host = 0;
+ for (k = 0; k < host_address_cells; k++) {
+ ranges[i].host <<= 32;
+ ranges[i].host |= base_ranges[j++];
+ }
+ ranges[i].size = 0;
+ for (k = 0; k < size_cells; k++) {
+ ranges[i].size <<= 32;
+ ranges[i].size |= base_ranges[j++];
+ }
+ }
+
+ free(base_ranges, M_DEVBUF);
+ return (nranges);
+}
diff --git a/sys/dev/ofw/ofwpci.h b/sys/dev/ofw/ofwpci.h
new file mode 100644
index 0000000..e9825ad
--- /dev/null
+++ b/sys/dev/ofw/ofwpci.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2011 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_OFW_OFWPCI_H_
+#define _DEV_OFW_OFWPCI_H_
+
+/*
+ * Export class definition for inheritance purposes
+ */
+DECLARE_CLASS(ofw_pci_driver);
+
+struct ofw_pci_cell_info {
+ pcell_t host_address_cells;
+ pcell_t pci_address_cell;
+ pcell_t size_cells;
+ };
+
+struct ofw_pci_range {
+ uint32_t pci_hi;
+ uint64_t pci;
+ uint64_t host;
+ uint64_t size;
+};
+
+/*
+ * Quirks for some adapters
+ */
+enum {
+ OFW_PCI_QUIRK_RANGES_ON_CHILDREN = 1,
+};
+
+struct ofw_pci_softc {
+ device_t sc_dev;
+ phandle_t sc_node;
+ int sc_bus;
+ int sc_initialized;
+ int sc_quirks;
+
+ struct ofw_pci_range *sc_range;
+ int sc_nrange;
+ struct ofw_pci_cell_info *sc_cell_info;
+
+ struct rman sc_io_rman;
+ struct rman sc_mem_rman;
+ bus_space_tag_t sc_memt;
+ bus_dma_tag_t sc_dmat;
+
+ struct ofw_bus_iinfo sc_pci_iinfo;
+};
+
+int ofw_pci_init(device_t);
+int ofw_pci_attach(device_t);
+int ofw_pci_read_ivar(device_t, device_t, int, uintptr_t *);
+int ofw_pci_write_ivar(device_t, device_t, int, uintptr_t);
+int ofw_pci_route_interrupt(device_t, device_t, int);
+int ofw_pci_nranges(phandle_t, struct ofw_pci_cell_info *);
+
+#endif /* _DEV_OFW_OFWPCI_H_ */
diff --git a/sys/dev/pccard/pccard.c b/sys/dev/pccard/pccard.c
index 0681242..04dcc44 100644
--- a/sys/dev/pccard/pccard.c
+++ b/sys/dev/pccard/pccard.c
@@ -507,7 +507,7 @@ pccard_function_init(struct pccard_function *pf, int entry)
end = start + ios->length - 1;
else
end = ~0;
- DEVPRINTF((bus, "I/O rid %d start %#lx end %#lx\n",
+ DEVPRINTF((bus, "I/O rid %d start %#jx end %#jx\n",
i, start, end));
rid = i;
len = ios->length;
@@ -531,7 +531,7 @@ pccard_function_init(struct pccard_function *pf, int entry)
end = start + mems->length - 1;
else
end = ~0;
- DEVPRINTF((bus, "Memory rid %d start %#lx end %#lx\ncardaddr %#lx hostaddr %#lx length %#lx\n",
+ DEVPRINTF((bus, "Memory rid %d start %#jx end %#jx\ncardaddr %#jx hostaddr %#jx length %#jx\n",
i, start, end, mems->cardaddr, mems->hostaddr,
mems->length));
rid = i;
@@ -602,7 +602,7 @@ pccard_function_free(struct pccard_function *pf)
device_printf(pf->sc->dev,
"function_free: Resource still owned by "
"child, oops. "
- "(type=%d, rid=%d, addr=%#lx)\n",
+ "(type=%d, rid=%d, addr=%#jx)\n",
rle->type, rle->rid,
rman_get_start(rle->res));
BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
@@ -697,7 +697,7 @@ pccard_function_enable(struct pccard_function *pf)
&pf->ccr_rid, PCCARD_MEM_PAGE_SIZE, RF_ACTIVE);
if (!pf->ccr_res)
goto bad;
- DEVPRINTF((dev, "ccr_res == %#lx-%#lx, base=%#x\n",
+ DEVPRINTF((dev, "ccr_res == %#jx-%#jx, base=%#x\n",
rman_get_start(pf->ccr_res), rman_get_end(pf->ccr_res),
pf->ccr_base));
CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY,
@@ -1025,26 +1025,6 @@ pccard_child_location_str(device_t bus, device_t child, char *buf,
return (0);
}
-/* XXX Maybe this should be in subr_bus? */
-static void
-pccard_safe_quote(char *dst, const char *src, size_t len)
-{
- char *walker = dst, *ep = dst + len - 1;
-
- if (len == 0)
- return;
- while (src != NULL && walker < ep)
- {
- if (*src == '"') {
- if (ep - walker < 2)
- break;
- *walker++ = '\\';
- }
- *walker++ = *src++;
- }
- *walker = '\0';
-}
-
static int
pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
size_t buflen)
@@ -1054,8 +1034,8 @@ pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
struct pccard_softc *sc = PCCARD_SOFTC(bus);
char cis0[128], cis1[128];
- pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
- pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
+ devctl_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
+ devctl_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
snprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
"cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function);
@@ -1197,7 +1177,7 @@ pccard_release_resource(device_t dev, device_t child, int type, int rid,
if (!rle) {
device_printf(dev, "Allocated resource not found, "
- "%d %#x %#lx %#lx\n",
+ "%d %#x %#jx %#jx\n",
type, rid, rman_get_start(r), rman_get_size(r));
return ENOENT;
}
diff --git a/sys/dev/pccard/pccard_cis.c b/sys/dev/pccard/pccard_cis.c
index 4bd06b5..4bd5e77 100644
--- a/sys/dev/pccard/pccard_cis.c
+++ b/sys/dev/pccard/pccard_cis.c
@@ -151,7 +151,7 @@ pccard_scan_cis(device_t bus, device_t dev, pccard_scan_t fct, void *arg)
tuple.memh = rman_get_bushandle(res);
tuple.ptr = 0;
- DPRINTF(("cis mem map %#x (resource: %#lx)\n",
+ DPRINTF(("cis mem map %#x (resource: %#jx)\n",
(unsigned int) tuple.memh, rman_get_start(res)));
tuple.mult = 2;
@@ -576,9 +576,9 @@ pccard_print_cis(device_t dev)
printf("; iomask %#lx, iospace", cfe->iomask);
for (i = 0; i < cfe->num_iospace; i++) {
- printf(" %#lx", cfe->iospace[i].start);
+ printf(" %#jx", cfe->iospace[i].start);
if (cfe->iospace[i].length)
- printf("-%#lx",
+ printf("-%#jx",
cfe->iospace[i].start +
cfe->iospace[i].length - 1);
}
@@ -587,14 +587,14 @@ pccard_print_cis(device_t dev)
printf("; memspace");
for (i = 0; i < cfe->num_memspace; i++) {
- printf(" %#lx",
+ printf(" %#jx",
cfe->memspace[i].cardaddr);
if (cfe->memspace[i].length)
- printf("-%#lx",
+ printf("-%#jx",
cfe->memspace[i].cardaddr +
cfe->memspace[i].length - 1);
if (cfe->memspace[i].hostaddr)
- printf("@%#lx",
+ printf("@%#jx",
cfe->memspace[i].hostaddr);
}
}
diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c
index 9398771..067aa5a 100644
--- a/sys/dev/pccbb/pccbb.c
+++ b/sys/dev/pccbb/pccbb.c
@@ -229,7 +229,7 @@ cbb_destroy_res(struct cbb_softc *sc)
while ((rle = SLIST_FIRST(&sc->rl)) != NULL) {
device_printf(sc->dev, "Danger Will Robinson: Resource "
"left allocated! This is a bug... "
- "(rid=%x, type=%d, addr=%lx)\n", rle->rid, rle->type,
+ "(rid=%x, type=%d, addr=%jx)\n", rle->rid, rle->type,
rman_get_start(rle->res));
SLIST_REMOVE_HEAD(&sc->rl, link);
free(rle, M_DEVBUF);
@@ -1241,8 +1241,8 @@ cbb_cardbus_alloc_resource(device_t brdev, device_t child, int type,
case SYS_RES_IRQ:
tmp = rman_get_start(sc->irq_res);
if (start > tmp || end < tmp || count != 1) {
- device_printf(child, "requested interrupt %ld-%ld,"
- "count = %ld not supported by cbb\n",
+ device_printf(child, "requested interrupt %jd-%jd,"
+ "count = %jd not supported by cbb\n",
start, end, count);
return (NULL);
}
@@ -1425,8 +1425,8 @@ cbb_pcic_alloc_resource(device_t brdev, device_t child, int type, int *rid,
case SYS_RES_IRQ:
tmp = rman_get_start(sc->irq_res);
if (start > tmp || end < tmp || count != 1) {
- device_printf(child, "requested interrupt %ld-%ld,"
- "count = %ld not supported by cbb\n",
+ device_printf(child, "requested interrupt %jd-%jd,"
+ "count = %jd not supported by cbb\n",
start, end, count);
return (NULL);
}
diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c
index e739027..4ec8d9b 100644
--- a/sys/dev/pccbb/pccbb_pci.c
+++ b/sys/dev/pccbb/pccbb_pci.c
@@ -313,7 +313,7 @@ cbb_pci_attach(device_t brdev)
mtx_destroy(&sc->mtx);
return (ENOMEM);
} else {
- DEVPRINTF((brdev, "Found memory at %08lx\n",
+ DEVPRINTF((brdev, "Found memory at %jx\n",
rman_get_start(sc->base_res)));
}
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 492efe0..8343181 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1643,7 +1643,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
if (bootverbose) {
rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1);
if (actual == 1)
- device_printf(child, "using IRQ %lu for MSI-X\n",
+ device_printf(child, "using IRQ %ju for MSI-X\n",
rle->start);
else {
int run;
@@ -1653,7 +1653,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
* IRQ values as ranges. 'irq' is the previous IRQ.
* 'run' is true if we are in a range.
*/
- device_printf(child, "using IRQs %lu", rle->start);
+ device_printf(child, "using IRQs %ju", rle->start);
irq = rle->start;
run = 0;
for (i = 1; i < actual; i++) {
@@ -1674,7 +1674,7 @@ pci_alloc_msix_method(device_t dev, device_t child, int *count)
}
/* Start new range. */
- printf(",%lu", rle->start);
+ printf(",%ju", rle->start);
irq = rle->start;
}
@@ -3572,13 +3572,13 @@ pci_alloc_secbus(device_t dev, device_t child, int *rid, rman_res_t start,
start, end, count, flags & ~RF_ACTIVE);
if (res == NULL) {
resource_list_delete(rl, PCI_RES_BUS, *rid);
- device_printf(child, "allocating %lu bus%s failed\n",
+ device_printf(child, "allocating %ju bus%s failed\n",
count, count == 1 ? "" : "es");
return (NULL);
}
if (bootverbose)
device_printf(child,
- "Lazy allocation of %lu bus%s at %lu\n", count,
+ "Lazy allocation of %ju bus%s at %ju\n", count,
count == 1 ? "" : "es", rman_get_start(res));
PCI_WRITE_CONFIG(dev, child, sec_reg, rman_get_start(res), 1);
PCI_WRITE_CONFIG(dev, child, sub_reg, rman_get_end(res), 1);
@@ -4391,9 +4391,9 @@ pci_print_child(device_t dev, device_t child)
retval += bus_print_child_header(dev, child);
- retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#jx");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
if (device_get_flags(dev))
retval += printf(" flags %#x", device_get_flags(dev));
@@ -4971,13 +4971,13 @@ pci_reserve_map(device_t dev, device_t child, int type, int *rid,
if (res == NULL) {
resource_list_delete(rl, type, *rid);
device_printf(child,
- "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n",
+ "%#jx bytes of rid %#x res %d failed (%#jx, %#jx).\n",
count, *rid, type, start, end);
goto out;
}
if (bootverbose)
device_printf(child,
- "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n",
+ "Lazy allocation of %#jx bytes rid %#x type %d at %#jx\n",
count, *rid, type, rman_get_start(res));
map = rman_get_start(res);
pci_write_bar(child, pm, map);
@@ -5254,7 +5254,7 @@ pci_delete_resource(device_t dev, device_t child, int type, int rid)
resource_list_busy(rl, type, rid)) {
device_printf(dev, "delete_resource: "
"Resource still owned by child, oops. "
- "(type=%d, rid=%d, addr=%lx)\n",
+ "(type=%d, rid=%d, addr=%jx)\n",
type, rid, rman_get_start(rle->res));
return;
}
diff --git a/sys/dev/pci/pci_host_generic.c b/sys/dev/pci/pci_host_generic.c
index f0c8d45..110ee68 100644
--- a/sys/dev/pci/pci_host_generic.c
+++ b/sys/dev/pci/pci_host_generic.c
@@ -540,7 +540,7 @@ generic_pcie_alloc_resource_pcie(device_t dev, device_t child, int type, int *ri
if (bootverbose) {
device_printf(dev,
- "rman_reserve_resource: start=%#lx, end=%#lx, count=%#lx\n",
+ "rman_reserve_resource: start=%#jx, end=%#jx, count=%#jx\n",
start, end, count);
}
@@ -560,7 +560,7 @@ generic_pcie_alloc_resource_pcie(device_t dev, device_t child, int type, int *ri
fail:
device_printf(dev, "%s FAIL: type=%d, rid=%d, "
- "start=%016lx, end=%016lx, count=%016lx, flags=%x\n",
+ "start=%016jx, end=%016jx, count=%016jx, flags=%x\n",
__func__, type, *rid, start, end, count, flags);
return (NULL);
@@ -744,7 +744,7 @@ generic_pcie_alloc_resource_ofw(device_t bus, device_t child, int type, int *rid
if (i == MAX_RANGES_TUPLES) {
device_printf(bus, "Could not map resource "
- "%#lx-%#lx\n", start, end);
+ "%#jx-%#jx\n", start, end);
return (NULL);
}
}
diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c
index 24f9b3a..112b198 100644
--- a/sys/dev/pci/pci_pci.c
+++ b/sys/dev/pci/pci_pci.c
@@ -247,7 +247,7 @@ pcib_is_isa_range(struct pcib_softc *sc, rman_res_t start, rman_res_t end,
alias:
if (bootverbose)
device_printf(sc->dev,
- "I/O range %#lx-%#lx overlaps with an ISA alias\n", start,
+ "I/O range %#jx-%#jx overlaps with an ISA alias\n", start,
end);
return (1);
}
@@ -339,7 +339,7 @@ alloc_ranges(rman_res_t start, rman_res_t end, void *arg)
rid = w->reg;
if (bootverbose)
device_printf(as->sc->dev,
- "allocating non-ISA range %#lx-%#lx\n", start, end);
+ "allocating non-ISA range %#jx-%#jx\n", start, end);
as->res[as->count] = bus_alloc_resource(as->sc->dev, SYS_RES_IOPORT,
&rid, start, end, end - start + 1, 0);
if (as->res[as->count] == NULL)
@@ -621,7 +621,7 @@ pcib_suballoc_bus(struct pcib_secbus *bus, device_t child, int *rid,
if (bootverbose)
device_printf(bus->dev,
- "allocated bus range (%lu-%lu) for rid %d of %s\n",
+ "allocated bus range (%ju-%ju) for rid %d of %s\n",
rman_get_start(res), rman_get_end(res), *rid,
pcib_child_name(child));
rman_set_rid(res, *rid);
@@ -646,7 +646,7 @@ pcib_grow_subbus(struct pcib_secbus *bus, rman_res_t new_end)
if (error)
return (error);
if (bootverbose)
- device_printf(bus->dev, "grew bus range to %lu-%lu\n",
+ device_printf(bus->dev, "grew bus range to %ju-%ju\n",
rman_get_start(bus->res), rman_get_end(bus->res));
error = rman_manage_region(&bus->rman, old_end + 1,
rman_get_end(bus->res));
@@ -694,8 +694,8 @@ pcib_alloc_subbus(struct pcib_secbus *bus, device_t child, int *rid,
/* Finally, attempt to grow the existing resource. */
if (bootverbose) {
device_printf(bus->dev,
- "attempting to grow bus range for %lu buses\n", count);
- printf("\tback candidate range: %lu-%lu\n", start_free,
+ "attempting to grow bus range for %ju buses\n", count);
+ printf("\tback candidate range: %ju-%ju\n", start_free,
new_end);
}
if (pcib_grow_subbus(bus, new_end) == 0)
@@ -1174,7 +1174,7 @@ pcib_suballoc_resource(struct pcib_softc *sc, struct pcib_window *w,
if (bootverbose)
device_printf(sc->dev,
- "allocated %s range (%#lx-%#lx) for rid %x of %s\n",
+ "allocated %s range (%#jx-%#jx) for rid %x of %s\n",
w->name, rman_get_start(res), rman_get_end(res), *rid,
pcib_child_name(child));
rman_set_rid(res, *rid);
@@ -1401,7 +1401,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
if (error) {
if (bootverbose)
device_printf(sc->dev,
- "failed to allocate initial %s window (%#lx-%#lx,%#lx)\n",
+ "failed to allocate initial %s window (%#jx-%#jx,%#jx)\n",
w->name, start, end, count);
return (error);
}
@@ -1433,7 +1433,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (bootverbose)
device_printf(sc->dev,
- "attempting to grow %s window for (%#lx-%#lx,%#lx)\n",
+ "attempting to grow %s window for (%#jx-%#jx,%#jx)\n",
w->name, start, end, count);
align = (rman_res_t)1 << RF_ALIGNMENT(flags);
if (start < w->base) {
@@ -1457,7 +1457,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (front >= start && front <= end_free) {
if (bootverbose)
- printf("\tfront candidate range: %#lx-%#lx\n",
+ printf("\tfront candidate range: %#jx-%#jx\n",
front, end_free);
front &= ~wmask;
front = w->base - front;
@@ -1485,7 +1485,7 @@ pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
*/
if (back <= end && start_free <= back) {
if (bootverbose)
- printf("\tback candidate range: %#lx-%#lx\n",
+ printf("\tback candidate range: %#jx-%#jx\n",
start_free, back);
back |= wmask;
back -= w->limit;
@@ -1709,7 +1709,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
#endif
}
if (end < start) {
- device_printf(dev, "ioport: end (%lx) < start (%lx)\n",
+ device_printf(dev, "ioport: end (%jx) < start (%jx)\n",
end, start);
start = 0;
end = 0;
@@ -1717,13 +1717,13 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
}
if (!ok) {
device_printf(dev, "%s%srequested unsupported I/O "
- "range 0x%lx-0x%lx (decoding 0x%x-0x%x)\n",
+ "range 0x%jx-0x%jx (decoding 0x%x-0x%x)\n",
name, suffix, start, end, sc->iobase, sc->iolimit);
return (NULL);
}
if (bootverbose)
device_printf(dev,
- "%s%srequested I/O range 0x%lx-0x%lx: in range\n",
+ "%s%srequested I/O range 0x%jx-0x%jx: in range\n",
name, suffix, start, end);
break;
@@ -1778,7 +1778,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
#endif
}
if (end < start) {
- device_printf(dev, "memory: end (%lx) < start (%lx)\n",
+ device_printf(dev, "memory: end (%jx) < start (%jx)\n",
end, start);
start = 0;
end = 0;
@@ -1786,7 +1786,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
}
if (!ok && bootverbose)
device_printf(dev,
- "%s%srequested unsupported memory range %#lx-%#lx "
+ "%s%srequested unsupported memory range %#jx-%#jx "
"(decoding %#jx-%#jx, %#jx-%#jx)\n",
name, suffix, start, end,
(uintmax_t)sc->membase, (uintmax_t)sc->memlimit,
@@ -1795,7 +1795,7 @@ pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
return (NULL);
if (bootverbose)
device_printf(dev,"%s%srequested memory range "
- "0x%lx-0x%lx: good\n",
+ "0x%jx-0x%jx: good\n",
name, suffix, start, end);
break;
diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c
index 77c60c3..f281117 100644
--- a/sys/dev/pci/pci_subr.c
+++ b/sys/dev/pci/pci_subr.c
@@ -185,7 +185,7 @@ pcib_host_res_decodes(struct pcib_host_resources *hr, int type, rman_res_t start
int rid;
if (bootverbose)
- device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n",
+ device_printf(hr->hr_pcib, "decoding %d %srange %#jx-%#jx\n",
type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
end);
rid = resource_list_add_next(&hr->hr_rl, type, start, end,
@@ -229,8 +229,8 @@ restart:
if (((flags & RF_PREFETCHABLE) != 0) !=
((rle->flags & RLE_PREFETCH) != 0))
continue;
- new_start = ulmax(start, rle->start);
- new_end = ulmin(end, rle->end);
+ new_start = ummax(start, rle->start);
+ new_end = ummin(end, rle->end);
if (new_start > new_end ||
new_start + count - 1 > new_end ||
new_start + count < new_start)
@@ -240,7 +240,7 @@ restart:
if (r != NULL) {
if (bootverbose)
device_printf(hr->hr_pcib,
- "allocated type %d (%#lx-%#lx) for rid %x of %s\n",
+ "allocated type %d (%#jx-%#jx) for rid %x of %s\n",
type, rman_get_start(r), rman_get_end(r),
*rid, pcib_child_name(dev));
return (r);
diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c
index 9c9054f..f508275 100644
--- a/sys/dev/ppbus/vpo.c
+++ b/sys/dev/ppbus/vpo.c
@@ -187,17 +187,19 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
#ifdef VP0_DEBUG
int i;
#endif
+ uint8_t *ptr;
+ ptr = scsiio_cdb_ptr(csio);
if (vpo->vpo_isplus) {
errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
csio->ccb_h.target_id,
- (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
+ ptr, csio->cdb_len,
(char *)csio->data_ptr, csio->dxfer_len,
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
} else {
errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
csio->ccb_h.target_id,
- (char *)&csio->cdb_io.cdb_bytes, csio->cdb_len,
+ ptr, csio->cdb_len,
(char *)csio->data_ptr, csio->dxfer_len,
&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
}
@@ -208,7 +210,7 @@ vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
/* dump of command */
for (i=0; i<csio->cdb_len; i++)
- printf("%x ", ((char *)&csio->cdb_io.cdb_bytes)[i]);
+ printf("%x ", ((char *)ptr)[i]);
printf("\n");
#endif
@@ -307,11 +309,15 @@ vpo_action(struct cam_sim *sim, union ccb *ccb)
csio = &ccb->csio;
+ if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ break;
+ }
#ifdef VP0_DEBUG
device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n",
- csio->cdb_io.cdb_bytes[0]);
+ *scsiio_cdb_ptr(csio));
#endif
-
vpo_intr(vpo, csio);
xpt_done(ccb);
diff --git a/sys/dev/ppc/ppc.c b/sys/dev/ppc/ppc.c
index a23f06c..4c6761f 100644
--- a/sys/dev/ppc/ppc.c
+++ b/sys/dev/ppc/ppc.c
@@ -1699,7 +1699,7 @@ ppc_probe(device_t dev, int rid)
next_bios_ppc += 1;
if (bootverbose)
device_printf(dev,
- "parallel port found at 0x%lx\n", port);
+ "parallel port found at 0x%jx\n", port);
}
#else
if ((next_bios_ppc < BIOS_MAX_PPC) &&
@@ -1707,7 +1707,7 @@ ppc_probe(device_t dev, int rid)
port = *(BIOS_PORTS + next_bios_ppc++);
if (bootverbose)
device_printf(dev,
- "parallel port found at 0x%lx\n", port);
+ "parallel port found at 0x%jx\n", port);
} else {
device_printf(dev, "parallel port not found.\n");
return (ENXIO);
diff --git a/sys/dev/proto/proto_bus_isa.c b/sys/dev/proto/proto_bus_isa.c
index e7438bf..4dad91c 100644
--- a/sys/dev/proto/proto_bus_isa.c
+++ b/sys/dev/proto/proto_bus_isa.c
@@ -80,7 +80,7 @@ proto_isa_probe(device_t dev)
return (ENODEV);
sb = sbuf_new_auto();
- sbuf_printf(sb, "%s:%#lx", proto_isa_prefix, rman_get_start(res));
+ sbuf_printf(sb, "%s:%#jx", proto_isa_prefix, rman_get_start(res));
sbuf_finish(sb);
device_set_desc_copy(dev, sbuf_data(sb));
sbuf_delete(sb);
diff --git a/sys/dev/qlxgb/qla_isr.c b/sys/dev/qlxgb/qla_isr.c
index 3169fd1..983fc12 100644
--- a/sys/dev/qlxgb/qla_isr.c
+++ b/sys/dev/qlxgb/qla_isr.c
@@ -267,7 +267,6 @@ qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
uint32_t comp_idx, desc_count;
q80_stat_desc_t *sdesc;
struct lro_ctrl *lro;
- struct lro_entry *queued;
uint32_t ret = 0;
dev = ha->pci_dev;
@@ -324,11 +323,7 @@ qla_rcv_isr(qla_host_t *ha, uint32_t sds_idx, uint32_t count)
}
}
- while((!SLIST_EMPTY(&lro->lro_active))) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
if (hw->sds[sds_idx].sdsr_next != comp_idx) {
QL_UPDATE_SDS_CONSUMER_INDEX(ha, sds_idx, comp_idx);
diff --git a/sys/dev/qlxge/qls_isr.c b/sys/dev/qlxge/qls_isr.c
index 03b3a3c..4cca895 100644
--- a/sys/dev/qlxge/qls_isr.c
+++ b/sys/dev/qlxge/qls_isr.c
@@ -232,7 +232,6 @@ qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
uint32_t i, cq_comp_idx;
int ret = 0, tx_comp_done = 0;
struct lro_ctrl *lro;
- struct lro_entry *queued;
cq_b = ha->rx_ring[cq_idx].cq_base_vaddr;
lro = &ha->rx_ring[cq_idx].lro;
@@ -287,11 +286,7 @@ qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
}
}
- while((!SLIST_EMPTY(&lro->lro_active))) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
ha->rx_ring[cq_idx].cq_next = cq_comp_idx;
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index c56d1ec..081ba83 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -183,7 +183,8 @@ random_kthread(void)
/* NOTREACHED */
}
/* This happens well after SI_SUB_RANDOM */
-SYSINIT(random_device_h_proc, SI_SUB_CREATE_INIT, SI_ORDER_ANY, kproc_start, &random_proc_kp);
+SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start,
+ &random_proc_kp);
/*
* Run through all fast sources reading entropy for the given
diff --git a/sys/dev/sdhci/sdhci_fdt.c b/sys/dev/sdhci/sdhci_fdt.c
index e49eda8..27709d0 100644
--- a/sys/dev/sdhci/sdhci_fdt.c
+++ b/sys/dev/sdhci/sdhci_fdt.c
@@ -308,3 +308,4 @@ DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, sdhci_fdt_devclass,
NULL, NULL);
MODULE_DEPEND(sdhci_fdt, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_fdt, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_fdt, mmc, 1, 1, 1);
diff --git a/sys/dev/sdhci/sdhci_pci.c b/sys/dev/sdhci/sdhci_pci.c
index e0fd29c..3ed43ab 100644
--- a/sys/dev/sdhci/sdhci_pci.c
+++ b/sys/dev/sdhci/sdhci_pci.c
@@ -475,3 +475,4 @@ DRIVER_MODULE(sdhci_pci, pci, sdhci_pci_driver, sdhci_pci_devclass, NULL,
NULL);
MODULE_DEPEND(sdhci_pci, sdhci, 1, 1, 1);
DRIVER_MODULE(mmc, sdhci_pci, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_pci, mmc, 1, 1, 1);
diff --git a/sys/dev/sfxge/sfxge_mcdi.c b/sys/dev/sfxge/sfxge_mcdi.c
index 3a85c28..85d7997 100644
--- a/sys/dev/sfxge/sfxge_mcdi.c
+++ b/sys/dev/sfxge/sfxge_mcdi.c
@@ -250,10 +250,6 @@ sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
}
mcdibuf = malloc(SFXGE_MCDI_MAX_PAYLOAD, M_TEMP, M_WAITOK | M_ZERO);
- if (mcdibuf == NULL) {
- rc = ENOMEM;
- goto fail4;
- }
if ((rc = copyin(ip->u.mcdi.payload, mcdibuf, ip->u.mcdi.len)) != 0) {
goto fail5;
}
@@ -292,7 +288,6 @@ sfxge_mcdi_ioctl(struct sfxge_softc *sc, sfxge_ioc_t *ip)
fail6:
fail5:
free(mcdibuf, M_TEMP);
-fail4:
fail3:
fail2:
fail1:
diff --git a/sys/dev/sfxge/sfxge_nvram.c b/sys/dev/sfxge/sfxge_nvram.c
index c4fa224..9113a89 100644
--- a/sys/dev/sfxge/sfxge_nvram.c
+++ b/sys/dev/sfxge/sfxge_nvram.c
@@ -75,10 +75,6 @@ sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
goto fail1;
buf = malloc(chunk_size, M_TEMP, M_WAITOK);
- if (buf == NULL) {
- rc = ENOMEM;
- goto fail2;
- }
off = 0;
while (total_size) {
@@ -108,7 +104,6 @@ sfxge_nvram_rw(struct sfxge_softc *sc, sfxge_ioc_t *ip, efx_nvram_type_t type,
fail3:
free(buf, M_TEMP);
-fail2:
efx_nvram_rw_finish(enp, type);
fail1:
return (rc);
diff --git a/sys/dev/siba/siba.c b/sys/dev/siba/siba.c
index 3489ddc..f0bcd9f 100644
--- a/sys/dev/siba/siba.c
+++ b/sys/dev/siba/siba.c
@@ -597,8 +597,8 @@ siba_print_all_resources(device_t dev)
if (STAILQ_FIRST(rl))
retval += printf(" at");
- retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
- retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
return (retval);
}
diff --git a/sys/dev/siis/siis.c b/sys/dev/siis/siis.c
index 9ceb444..cb9d800 100644
--- a/sys/dev/siis/siis.c
+++ b/sys/dev/siis/siis.c
@@ -320,7 +320,7 @@ siis_alloc_resource(device_t dev, device_t child, int type, int *rid,
int unit = ((struct siis_channel *)device_get_softc(child))->unit;
struct resource *res = NULL;
int offset = unit << 13;
- long st;
+ rman_res_t st;
switch (type) {
case SYS_RES_MEMORY:
diff --git a/sys/dev/sound/isa/ad1816.c b/sys/dev/sound/isa/ad1816.c
index f3bb89a..2ae39cf 100644
--- a/sys/dev/sound/isa/ad1816.c
+++ b/sys/dev/sound/isa/ad1816.c
@@ -624,11 +624,11 @@ ad1816_attach(device_t dev)
goto no;
}
if (ad1816->drq2)
- snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2));
+ snprintf(status2, SND_STATUSLEN, ":%jd", rman_get_start(ad1816->drq2));
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
rman_get_start(ad1816->io_base),
rman_get_start(ad1816->irq),
rman_get_start(ad1816->drq1),
diff --git a/sys/dev/sound/isa/ess.c b/sys/dev/sound/isa/ess.c
index 5fd9529..e4032de 100644
--- a/sys/dev/sound/isa/ess.c
+++ b/sys/dev/sound/isa/ess.c
@@ -867,12 +867,12 @@ ess_attach(device_t dev)
}
if (sc->drq2)
- snprintf(buf, SND_STATUSLEN, ":%ld", rman_get_start(sc->drq2));
+ snprintf(buf, SND_STATUSLEN, ":%jd", rman_get_start(sc->drq2));
else
buf[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
- rman_get_start(sc->io_base), rman_get_start(sc->irq),
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
+ rman_get_start(sc->io_base), rman_get_start(sc->irq),
rman_get_start(sc->drq1), buf, sc->bufsize,
PCM_KLDSTRING(snd_ess));
diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c
index 7aaef06..62f6617 100644
--- a/sys/dev/sound/isa/mss.c
+++ b/sys/dev/sound/isa/mss.c
@@ -1326,7 +1326,7 @@ mss_probe(device_t dev)
}
tmp &= 0x3f;
if (!(tmp == 0x04 || tmp == 0x0f || tmp == 0x00 || tmp == 0x05)) {
- BVDDB(printf("No MSS signature detected on port 0x%lx (0x%x)\n",
+ BVDDB(printf("No MSS signature detected on port 0x%jx (0x%x)\n",
rman_get_start(mss->io_base), tmpx));
goto no;
}
@@ -1767,7 +1767,7 @@ mss_doattach(device_t dev, struct mss_info *mss)
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d%s bufsz %u",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %d%s bufsz %u",
rman_get_start(mss->io_base), rman_get_start(mss->irq), pdma, status2, mss->bufsize);
if (pcm_register(dev, mss, 1, 1)) goto no;
diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c
index 536de77..946c6bf 100644
--- a/sys/dev/sound/isa/sb16.c
+++ b/sys/dev/sound/isa/sb16.c
@@ -854,11 +854,11 @@ sb16_attach(device_t dev)
}
if (!(pcm_getflags(dev) & SD_F_SIMPLEX))
- snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(sb->drq2));
+ snprintf(status2, SND_STATUSLEN, ":%jd", rman_get_start(sb->drq2));
else
status2[0] = '\0';
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
rman_get_start(sb->io_base), rman_get_start(sb->irq),
rman_get_start(sb->drq1), status2, sb->bufsize,
PCM_KLDSTRING(snd_sb16));
diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c
index 7c39515..c9ed746 100644
--- a/sys/dev/sound/isa/sb8.c
+++ b/sys/dev/sound/isa/sb8.c
@@ -749,7 +749,7 @@ sb_attach(device_t dev)
goto no;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld bufsz %u %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd bufsz %u %s",
rman_get_start(sb->io_base), rman_get_start(sb->irq),
rman_get_start(sb->drq), sb->bufsize, PCM_KLDSTRING(snd_sb8));
diff --git a/sys/dev/sound/pci/als4000.c b/sys/dev/sound/pci/als4000.c
index b214333..bb38749 100644
--- a/sys/dev/sound/pci/als4000.c
+++ b/sys/dev/sound/pci/als4000.c
@@ -848,7 +848,7 @@ als_pci_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &alsrchan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_als4000));
pcm_setstatus(dev, status);
return 0;
diff --git a/sys/dev/sound/pci/atiixp.c b/sys/dev/sound/pci/atiixp.c
index 8df67aa..ca9a539 100644
--- a/sys/dev/sound/pci/atiixp.c
+++ b/sys/dev/sound/pci/atiixp.c
@@ -1097,7 +1097,7 @@ atiixp_chip_post_init(void *arg)
"polling", CTLTYPE_INT | CTLFLAG_RW, sc->dev, sizeof(sc->dev),
sysctl_atiixp_polling, "I", "Enable polling mode");
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_atiixp));
diff --git a/sys/dev/sound/pci/aureal.c b/sys/dev/sound/pci/aureal.c
index 67af075..f990f43 100644
--- a/sys/dev/sound/pci/aureal.c
+++ b/sys/dev/sound/pci/aureal.c
@@ -645,7 +645,7 @@ au_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(type[0] == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal));
diff --git a/sys/dev/sound/pci/cmi.c b/sys/dev/sound/pci/cmi.c
index 6075a92..9e62659 100644
--- a/sys/dev/sound/pci/cmi.c
+++ b/sys/dev/sound/pci/cmi.c
@@ -995,7 +995,7 @@ cmi_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cmi));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/cs4281.c b/sys/dev/sound/pci/cs4281.c
index 929b9d7..4750daf 100644
--- a/sys/dev/sound/pci/cs4281.c
+++ b/sys/dev/sound/pci/cs4281.c
@@ -849,7 +849,7 @@ cs4281_pci_attach(device_t dev)
pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc);
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cs4281));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index 89ffd2b..5a1544d 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -821,7 +821,7 @@ pcmcsa_attach(device_t dev)
return (ENXIO);
}
- snprintf(status, SND_STATUSLEN, "at irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at irq %jd %s",
rman_get_start(resp->irq),PCM_KLDSTRING(snd_csa));
/* Enable interrupt. */
diff --git a/sys/dev/sound/pci/ds1.c b/sys/dev/sound/pci/ds1.c
index 302271a..23f3d5c 100644
--- a/sys/dev/sound/pci/ds1.c
+++ b/sys/dev/sound/pci/ds1.c
@@ -1010,7 +1010,7 @@ ds_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_ds1));
if (pcm_register(dev, sc, DS1_CHANS, 2))
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c
index c4a13f3..f1d77ee 100644
--- a/sys/dev/sound/pci/emu10k1.c
+++ b/sys/dev/sound/pci/emu10k1.c
@@ -2132,7 +2132,7 @@ emu_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_emu10k1));
diff --git a/sys/dev/sound/pci/emu10kx.c b/sys/dev/sound/pci/emu10kx.c
index b2eaf2c..bd97ab8 100644
--- a/sys/dev/sound/pci/emu10kx.c
+++ b/sys/dev/sound/pci/emu10kx.c
@@ -3225,7 +3225,7 @@ emu_pci_attach(device_t dev)
device_printf(dev, "unable to create control device\n");
goto bad;
}
- snprintf(status, 255, "rev %d at io 0x%lx irq %ld", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
+ snprintf(status, 255, "rev %d at io 0x%jx irq %jd", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
/* Voices */
for (i = 0; i < NUM_G; i++) {
diff --git a/sys/dev/sound/pci/envy24.c b/sys/dev/sound/pci/envy24.c
index c4eaa10..9272a95 100644
--- a/sys/dev/sound/pci/envy24.c
+++ b/sys/dev/sound/pci/envy24.c
@@ -2599,7 +2599,7 @@ envy24_pci_attach(device_t dev)
/* set status iformation */
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
+ "at io 0x%jx:%jd,0x%jx:%jd,0x%jx:%jd,0x%jx:%jd irq %jd",
rman_get_start(sc->cs),
rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
rman_get_start(sc->ddma),
diff --git a/sys/dev/sound/pci/envy24ht.c b/sys/dev/sound/pci/envy24ht.c
index 85a36c2..fe1fb19 100644
--- a/sys/dev/sound/pci/envy24ht.c
+++ b/sys/dev/sound/pci/envy24ht.c
@@ -2507,7 +2507,7 @@ envy24ht_pci_attach(device_t dev)
/* set status iformation */
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
+ "at io 0x%jx:%jd,0x%jx:%jd irq %jd",
rman_get_start(sc->cs),
rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
rman_get_start(sc->mt),
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index 0dd88a8..7032c84 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -1856,7 +1856,7 @@ es_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(es->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(es->reg), rman_get_start(es->irq),
PCM_KLDSTRING(snd_es137x));
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c
index 82b1d77..252e714 100644
--- a/sys/dev/sound/pci/fm801.c
+++ b/sys/dev/sound/pci/fm801.c
@@ -639,7 +639,7 @@ fm801_pci_attach(device_t dev)
goto oops;
}
- snprintf(status, 64, "at %s 0x%lx irq %ld %s",
+ snprintf(status, 64, "at %s 0x%jx irq %jd %s",
(fm801->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(fm801->reg), rman_get_start(fm801->irq),PCM_KLDSTRING(snd_fm801));
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index b0f250c..c761acb 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -159,6 +159,7 @@ static const struct {
{ HDA_ATI_RV940, "ATI RV940", 0, 0 },
{ HDA_ATI_RV970, "ATI RV970", 0, 0 },
{ HDA_ATI_R1000, "ATI R1000", 0, 0 },
+ { HDA_AMD_HUDSON2, "AMD Hudson-2", 0, 0 },
{ HDA_RDC_M3010, "RDC M3010", 0, 0 },
{ HDA_VIA_VT82XX, "VIA VT8251/8237A",0, 0 },
{ HDA_SIS_966, "SiS 966", 0, 0 },
@@ -167,6 +168,7 @@ static const struct {
{ HDA_INTEL_ALL, "Intel", 0, 0 },
{ HDA_NVIDIA_ALL, "NVIDIA", 0, 0 },
{ HDA_ATI_ALL, "ATI", 0, 0 },
+ { HDA_AMD_ALL, "AMD", 0, 0 },
{ HDA_VIA_ALL, "VIA", 0, 0 },
{ HDA_SIS_ALL, "SiS", 0, 0 },
{ HDA_ULI_ALL, "ULI", 0, 0 },
diff --git a/sys/dev/sound/pci/hda/hdac.h b/sys/dev/sound/pci/hda/hdac.h
index 9538b307..1fc265a 100644
--- a/sys/dev/sound/pci/hda/hdac.h
+++ b/sys/dev/sound/pci/hda/hdac.h
@@ -136,6 +136,10 @@
#define HDA_ATI_R1000 HDA_MODEL_CONSTRUCT(ATI, 0xaaa0)
#define HDA_ATI_ALL HDA_MODEL_CONSTRUCT(ATI, 0xffff)
+#define AMD_VENDORID 0x1022
+#define HDA_AMD_HUDSON2 HDA_MODEL_CONSTRUCT(AMD, 0x780d)
+#define HDA_AMD_ALL HDA_MODEL_CONSTRUCT(AMD, 0xffff)
+
/* RDC */
#define RDC_VENDORID 0x17f3
#define HDA_RDC_M3010 HDA_MODEL_CONSTRUCT(RDC, 0x3010)
diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
index dc62377..d84712d 100644
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -668,7 +668,7 @@ hdspe_pcm_attach(device_t dev)
scp->chnum++;
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(scp->sc->cs),
rman_get_start(scp->sc->irq),
PCM_KLDSTRING(snd_hdspe));
diff --git a/sys/dev/sound/pci/ich.c b/sys/dev/sound/pci/ich.c
index 4895ad6..61b6781 100644
--- a/sys/dev/sound/pci/ich.c
+++ b/sys/dev/sound/pci/ich.c
@@ -687,7 +687,7 @@ ich_setstatus(struct sc_info *sc)
char status[SND_STATUSLEN];
snprintf(status, SND_STATUSLEN,
- "at io 0x%lx, 0x%lx irq %ld bufsz %u %s",
+ "at io 0x%jx, 0x%jx irq %jd bufsz %u %s",
rman_get_start(sc->nambar), rman_get_start(sc->nabmbar),
rman_get_start(sc->irq), sc->bufsz,PCM_KLDSTRING(snd_ich));
diff --git a/sys/dev/sound/pci/maestro.c b/sys/dev/sound/pci/maestro.c
index c7cbb35..fbadf3b 100644
--- a/sys/dev/sound/pci/maestro.c
+++ b/sys/dev/sound/pci/maestro.c
@@ -1917,7 +1917,7 @@ agg_attach(device_t dev)
adjust_pchbase(ess->pch, ess->playchns, ess->bufsz);
snprintf(status, SND_STATUSLEN,
- "port 0x%lx-0x%lx irq %ld at device %d.%d on pci%d",
+ "port 0x%jx-0x%jx irq %jd at device %d.%d on pci%d",
rman_get_start(reg), rman_get_end(reg), rman_get_start(irq),
pci_get_slot(dev), pci_get_function(dev), pci_get_bus(dev));
pcm_setstatus(dev, status);
diff --git a/sys/dev/sound/pci/maestro3.c b/sys/dev/sound/pci/maestro3.c
index 20a9bda..5bab021 100644
--- a/sys/dev/sound/pci/maestro3.c
+++ b/sys/dev/sound/pci/maestro3.c
@@ -1440,7 +1440,7 @@ m3_pci_attach(device_t dev)
goto bad;
}
}
- snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at %s 0x%jx irq %jd %s",
(sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
rman_get_start(sc->reg), rman_get_start(sc->irq),
PCM_KLDSTRING(snd_maestro3));
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 71c1bf1..8a78bf7 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -702,7 +702,7 @@ nm_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, SND_STATUSLEN, "at memory 0x%lx, 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at memory 0x%jx, 0x%jx irq %jd %s",
rman_get_start(sc->buf), rman_get_start(sc->reg),
rman_get_start(sc->irq),PCM_KLDSTRING(snd_neomagic));
diff --git a/sys/dev/sound/pci/solo.c b/sys/dev/sound/pci/solo.c
index 534d810..dc46ac8 100644
--- a/sys/dev/sound/pci/solo.c
+++ b/sys/dev/sound/pci/solo.c
@@ -1051,7 +1051,7 @@ ess_attach(device_t dev)
if (mixer_init(dev, &solomixer_class, sc))
goto no;
- snprintf(status, SND_STATUSLEN, "at io 0x%lx,0x%lx,0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx,0x%jx,0x%jx irq %jd %s",
rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc),
rman_get_start(sc->irq),PCM_KLDSTRING(snd_solo));
diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c
index ef48890..32ddd00 100644
--- a/sys/dev/sound/pci/t4dwave.c
+++ b/sys/dev/sound/pci/t4dwave.c
@@ -948,7 +948,7 @@ tr_pci_attach(device_t dev)
goto bad;
}
- snprintf(status, 64, "at io 0x%lx irq %ld %s",
+ snprintf(status, 64, "at io 0x%jx irq %jd %s",
rman_get_start(tr->reg), rman_get_start(tr->irq),PCM_KLDSTRING(snd_t4dwave));
if (pcm_register(dev, tr, dacn, 1))
diff --git a/sys/dev/sound/pci/via8233.c b/sys/dev/sound/pci/via8233.c
index 0694cef..45fe175 100644
--- a/sys/dev/sound/pci/via8233.c
+++ b/sys/dev/sound/pci/via8233.c
@@ -1348,7 +1348,7 @@ via_attach(device_t dev)
ac97_setextmode(via->codec, ext);
}
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(via->reg), rman_get_start(via->irq),
PCM_KLDSTRING(snd_via8233));
diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c
index 6b615e8..4484d6e 100644
--- a/sys/dev/sound/pci/via82c686.c
+++ b/sys/dev/sound/pci/via82c686.c
@@ -590,7 +590,7 @@ via_attach(device_t dev)
NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0) != 0)
goto bad;
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(via->reg), rman_get_start(via->irq),
PCM_KLDSTRING(snd_via82c686));
diff --git a/sys/dev/sound/pci/vibes.c b/sys/dev/sound/pci/vibes.c
index f16e3ef..22c84c8 100644
--- a/sys/dev/sound/pci/vibes.c
+++ b/sys/dev/sound/pci/vibes.c
@@ -815,7 +815,7 @@ sv_attach(device_t dev) {
((mu - ml) % 0x200)) {
device_printf(dev, "sv_attach: resource assumptions not met "
"(midi 0x%08lx, games 0x%08lx)\n",
- midi_start, games_start);
+ (u_long)midi_start, (u_long)games_start);
goto fail;
}
@@ -874,7 +874,7 @@ sv_attach(device_t dev) {
pcm_addchan(dev, PCMDIR_PLAY, &svpchan_class, sc);
pcm_addchan(dev, PCMDIR_REC, &svrchan_class, sc);
- snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
+ snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
rman_get_start(sc->enh_reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_vibes));
pcm_setstatus(dev, status);
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index cb52ce7..a36afef 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -398,7 +398,6 @@ struct uart_class uart_ns8250_class = {
static struct ofw_compat_data compat_data[] = {
{"ns16550", (uintptr_t)&uart_ns8250_class},
{"ns16550a", (uintptr_t)&uart_ns8250_class},
- {"snps,dw-apb-uart", (uintptr_t)&uart_ns8250_class},
{NULL, (uintptr_t)NULL},
};
UART_FDT_CLASS_AND_DEVICE(compat_data);
@@ -451,19 +450,9 @@ ns8250_bus_attach(struct uart_softc *sc)
pcell_t cell;
#endif
- ns8250->busy_detect = 0;
-
#ifdef FDT
- /*
- * Check whether uart requires to read USR reg when IIR_BUSY and
- * has broken txfifo.
- */
- ns8250->busy_detect = ofw_bus_is_compatible(sc->sc_dev, "snps,dw-apb-uart");
+ /* Check whether uart has a broken txfifo. */
node = ofw_bus_get_node(sc->sc_dev);
- /* XXX: This is kept for a short time for compatibility with older device trees */
- if ((OF_getencprop(node, "busy-detect", &cell, sizeof(cell))) > 0
- && cell != 0)
- ns8250->busy_detect = 1;
if ((OF_getencprop(node, "broken-txfifo", &cell, sizeof(cell))) > 0)
broken_txfifo = cell ? 1 : 0;
#endif
diff --git a/sys/dev/uart/uart_dev_snps.c b/sys/dev/uart/uart_dev_snps.c
new file mode 100644
index 0000000..af4000f
--- /dev/null
+++ b/sys/dev/uart/uart_dev_snps.c
@@ -0,0 +1,283 @@
+/*-
+ * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#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 <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu_fdt.h>
+#include <dev/uart/uart_dev_ns8250.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#endif
+
+#include "uart_if.h"
+
+struct snps_softc {
+ struct ns8250_softc ns8250;
+
+#ifdef EXT_RESOURCES
+ clk_t baudclk;
+ clk_t apb_pclk;
+ hwreset_t reset;
+#endif
+};
+
+static int
+snps_uart_attach(struct uart_softc *uart_sc)
+{
+ struct snps_softc *sc;
+
+ sc = (struct snps_softc *)uart_sc;
+
+ /* UART requires to read USR reg when IIR_BUSY */
+ sc->ns8250.busy_detect = 1;
+
+ return (ns8250_bus_attach(uart_sc));
+}
+
+static kobj_method_t snps_methods[] = {
+ KOBJMETHOD(uart_probe, ns8250_bus_probe),
+ KOBJMETHOD(uart_attach, snps_uart_attach),
+ KOBJMETHOD(uart_detach, ns8250_bus_detach),
+ KOBJMETHOD(uart_flush, ns8250_bus_flush),
+ KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
+ KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl),
+ KOBJMETHOD(uart_ipend, ns8250_bus_ipend),
+ KOBJMETHOD(uart_param, ns8250_bus_param),
+ KOBJMETHOD(uart_receive, ns8250_bus_receive),
+ KOBJMETHOD(uart_setsig, ns8250_bus_setsig),
+ KOBJMETHOD(uart_transmit, ns8250_bus_transmit),
+ KOBJMETHOD(uart_grab, ns8250_bus_grab),
+ KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab),
+ KOBJMETHOD_END
+};
+
+struct uart_class uart_snps_class = {
+ "snps",
+ snps_methods,
+ sizeof(struct snps_softc),
+ .uc_ops = &uart_ns8250_ops,
+ .uc_range = 8,
+ .uc_rclk = 0,
+};
+
+static struct ofw_compat_data compat_data[] = {
+ { "snps,dw-apb-uart", (uintptr_t)&uart_snps_class },
+ { NULL, (uintptr_t)NULL }
+};
+UART_FDT_CLASS(compat_data);
+
+#ifdef EXT_RESOURCES
+static int
+snps_get_clocks(device_t dev, clk_t *baudclk, clk_t *apb_pclk)
+{
+ struct snps_softc *sc;
+
+ sc = device_get_softc(dev);
+ *baudclk = NULL;
+ *apb_pclk = NULL;
+
+ /* Baud clock is either named "baudclk", or there is a single
+ * unnamed clock.
+ */
+ if (clk_get_by_ofw_name(dev, "baudclk", baudclk) != 0 &&
+ clk_get_by_ofw_index(dev, 0, baudclk) != 0)
+ return (ENOENT);
+
+ /* APB peripheral clock is optional */
+ (void)clk_get_by_ofw_name(dev, "apb_pclk", apb_pclk);
+
+ return (0);
+}
+#endif
+
+static int
+snps_probe(device_t dev)
+{
+ struct snps_softc *sc;
+ struct uart_class *uart_class;
+ phandle_t node;
+ uint32_t shift, clock;
+ uint64_t freq;
+ int error;
+#ifdef EXT_RESOURCES
+ clk_t baudclk, apb_pclk;
+ hwreset_t reset;
+#endif
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ uart_class = (struct uart_class *)ofw_bus_search_compatible(dev,
+ compat_data)->ocd_data;
+ if (uart_class == NULL)
+ return (ENXIO);
+
+ freq = 0;
+ sc = device_get_softc(dev);
+ sc->ns8250.base.sc_class = uart_class;
+
+ node = ofw_bus_get_node(dev);
+ if (OF_getencprop(node, "reg-shift", &shift, sizeof(shift)) <= 0)
+ shift = 0;
+ if (OF_getencprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0)
+ clock = 0;
+
+#ifdef EXT_RESOURCES
+ if (hwreset_get_by_ofw_idx(dev, 0, &reset) == 0) {
+ error = hwreset_deassert(reset);
+ if (error != 0) {
+ device_printf(dev, "cannot de-assert reset\n");
+ return (error);
+ }
+ }
+
+ if (snps_get_clocks(dev, &baudclk, &apb_pclk) == 0) {
+ error = clk_enable(baudclk);
+ if (error != 0) {
+ device_printf(dev, "cannot enable baud clock\n");
+ return (error);
+ }
+ if (apb_pclk != NULL) {
+ error = clk_enable(apb_pclk);
+ if (error != 0) {
+ device_printf(dev,
+ "cannot enable peripheral clock\n");
+ return (error);
+ }
+ }
+
+ if (clock == 0) {
+ error = clk_get_freq(baudclk, &freq);
+ if (error != 0) {
+ device_printf(dev, "cannot get frequency\n");
+ return (error);
+ }
+ clock = (uint32_t)freq;
+ }
+ }
+#endif
+
+ if (bootverbose && clock == 0)
+ device_printf(dev, "could not determine frequency\n");
+
+ error = uart_bus_probe(dev, (int)shift, (int)clock, 0, 0);
+ if (error != 0)
+ return (error);
+
+#ifdef EXT_RESOURCES
+ /* XXX uart_bus_probe has changed the softc, so refresh it */
+ sc = device_get_softc(dev);
+
+ /* Store clock and reset handles for detach */
+ sc->baudclk = baudclk;
+ sc->apb_pclk = apb_pclk;
+ sc->reset = reset;
+#endif
+
+ return (0);
+}
+
+static int
+snps_detach(device_t dev)
+{
+#ifdef EXT_RESOURCES
+ struct snps_softc *sc;
+ clk_t baudclk, apb_pclk;
+ hwreset_t reset;
+#endif
+ int error;
+
+#ifdef EXT_RESOURCES
+ sc = device_get_softc(dev);
+ baudclk = sc->baudclk;
+ apb_pclk = sc->apb_pclk;
+ reset = sc->reset;
+#endif
+
+ error = uart_bus_detach(dev);
+ if (error != 0)
+ return (error);
+
+#ifdef EXT_RESOURCES
+ if (reset != NULL) {
+ error = hwreset_assert(reset);
+ if (error != 0) {
+ device_printf(dev, "cannot assert reset\n");
+ return (error);
+ }
+ hwreset_release(reset);
+ }
+ if (apb_pclk != NULL) {
+ error = clk_release(apb_pclk);
+ if (error != 0) {
+ device_printf(dev, "cannot release peripheral clock\n");
+ return (error);
+ }
+ }
+ if (baudclk != NULL) {
+ error = clk_release(baudclk);
+ if (error != 0) {
+ device_printf(dev, "cannot release baud clock\n");
+ return (error);
+ }
+ }
+#endif
+
+ return (0);
+}
+
+static device_method_t snps_bus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, snps_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, snps_detach),
+ DEVMETHOD_END
+};
+
+static driver_t snps_uart_driver = {
+ uart_driver_name,
+ snps_bus_methods,
+ sizeof(struct snps_softc)
+};
+
+DRIVER_MODULE(uart_snps, simplebus, snps_uart_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/usb/wlan/if_urtwn.c b/sys/dev/urtwn/if_urtwn.c
index 8b56847..95de7ce 100644
--- a/sys/dev/usb/wlan/if_urtwn.c
+++ b/sys/dev/urtwn/if_urtwn.c
@@ -78,8 +78,8 @@ __FBSDID("$FreeBSD$");
#include <dev/usb/usb_debug.h>
-#include <dev/usb/wlan/if_urtwnreg.h>
-#include <dev/usb/wlan/if_urtwnvar.h>
+#include <dev/urtwn/if_urtwnreg.h>
+#include <dev/urtwn/if_urtwnvar.h>
#ifdef USB_DEBUG
enum {
@@ -95,6 +95,7 @@ enum {
URTWN_DEBUG_ROM = 0x00000200, /* various ROM info */
URTWN_DEBUG_KEY = 0x00000400, /* crypto keys management */
URTWN_DEBUG_TXPWR = 0x00000800, /* dump Tx power values */
+ URTWN_DEBUG_RSSI = 0x00001000, /* dump RSSI lookups */
URTWN_DEBUG_ANY = 0xffffffff
};
@@ -109,6 +110,9 @@ enum {
#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh)
+static int urtwn_enable_11n = 1;
+TUNABLE_INT("hw.usb.urtwn.enable_11n", &urtwn_enable_11n);
+
/* various supported device vendors/products */
static const STRUCT_USB_HOST_ID urtwn_devs[] = {
#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
@@ -465,6 +469,19 @@ urtwn_match(device_t self)
return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa));
}
+static void
+urtwn_update_chw(struct ieee80211com *ic)
+{
+}
+
+static int
+urtwn_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+
+ /* We're driving this ourselves (eventually); don't involve net80211 */
+ return (0);
+}
+
static int
urtwn_attach(device_t self)
{
@@ -555,7 +572,9 @@ urtwn_attach(device_t self)
| IEEE80211_C_HOSTAP /* hostap mode */
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
+#if 0
| IEEE80211_C_BGSCAN /* capable of bg scanning */
+#endif
| IEEE80211_C_WPA /* 802.11i */
| IEEE80211_C_WME /* 802.11e */
;
@@ -565,9 +584,27 @@ urtwn_attach(device_t self)
IEEE80211_CRYPTO_TKIP |
IEEE80211_CRYPTO_AES_CCM;
+ /* Assume they're all 11n capable for now */
+ if (urtwn_enable_11n) {
+ device_printf(self, "enabling 11n\n");
+ ic->ic_htcaps = IEEE80211_HTC_HT |
+ IEEE80211_HTC_AMPDU |
+ IEEE80211_HTC_AMSDU |
+ IEEE80211_HTCAP_MAXAMSDU_3839 |
+ IEEE80211_HTCAP_SMPS_OFF;
+ /* no HT40 just yet */
+ // ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40;
+
+ /* XXX TODO: verify chains versus streams for urtwn */
+ ic->ic_txstream = sc->ntxchains;
+ ic->ic_rxstream = sc->nrxchains;
+ }
+
memset(bands, 0, sizeof(bands));
setbit(bands, IEEE80211_MODE_11B);
setbit(bands, IEEE80211_MODE_11G);
+ if (urtwn_enable_11n)
+ setbit(bands, IEEE80211_MODE_11NG);
ieee80211_init_channels(ic, NULL, bands);
ieee80211_ifattach(ic);
@@ -589,6 +626,8 @@ urtwn_attach(device_t self)
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = urtwn_r88e_node_free;
}
+ ic->ic_update_chw = urtwn_update_chw;
+ ic->ic_ampdu_enable = urtwn_ampdu_enable;
ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr,
sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT,
@@ -1005,6 +1044,9 @@ urtwn_rx_frame(struct urtwn_softc *sc, struct mbuf *m, int8_t *rssi_p)
tap->wr_tsft &= 0xffffffff00000000;
tap->wr_tsft += stat->rxdw5;
+ /* XXX 20/40? */
+ /* XXX shortgi? */
+
/* Map HW rate index to 802.11 rate. */
if (!(rxdw3 & R92C_RXDW3_HT)) {
tap->wr_rate = ridx2rate[rate];
@@ -1081,6 +1123,8 @@ tr_setup:
nf = URTWN_NOISE_FLOOR;
if (ni != NULL) {
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ m->m_flags |= M_AMPDU;
(void)ieee80211_input(ni, m, rssi - nf, nf);
ieee80211_free_node(ni);
} else {
@@ -1827,7 +1871,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
struct ieee80211_node *ni;
- struct ieee80211_rateset *rs;
+ struct ieee80211_rateset *rs, *rs_ht;
struct r92c_fw_cmd_macid_cfg cmd;
uint32_t rates, basicrates;
uint8_t mode;
@@ -1835,10 +1879,13 @@ urtwn_ra_init(struct urtwn_softc *sc)
ni = ieee80211_ref_node(vap->iv_bss);
rs = &ni->ni_rates;
+ rs_ht = (struct ieee80211_rateset *) &ni->ni_htrates;
/* Get normal and basic rates mask. */
rates = basicrates = 0;
maxrate = maxbasicrate = 0;
+
+ /* This is for 11bg */
for (i = 0; i < rs->rs_nrates; i++) {
/* Convert 802.11 rate to HW rate index. */
for (j = 0; j < nitems(ridx2rate); j++)
@@ -1856,10 +1903,32 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxbasicrate = j;
}
}
+
+ /* If we're doing 11n, enable 11n rates */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ for (i = 0; i < rs_ht->rs_nrates; i++) {
+ if ((rs_ht->rs_rates[i] & 0x7f) > 0xf)
+ continue;
+ /* 11n rates start at index 12 */
+ j = ((rs_ht->rs_rates[i]) & 0xf) + 12;
+ rates |= (1 << j);
+
+ /* Guard against the rate table being oddly ordered */
+ if (j > maxrate)
+ maxrate = j;
+ }
+ }
+
+#if 0
+ if (ic->ic_curmode == IEEE80211_MODE_11NG)
+ raid = R92C_RAID_11GN;
+#endif
+ /* NB: group addressed frames are done at 11bg rates for now */
if (ic->ic_curmode == IEEE80211_MODE_11B)
mode = R92C_RAID_11B;
else
mode = R92C_RAID_11BG;
+ /* XXX misleading 'mode' value here for unicast frames */
URTWN_DPRINTF(sc, URTWN_DEBUG_RA,
"%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__,
mode, rates, basicrates);
@@ -1874,6 +1943,7 @@ urtwn_ra_init(struct urtwn_softc *sc)
"could not add broadcast station\n");
return (error);
}
+
/* Set initial MRR rate. */
URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxbasicrate %d\n", __func__,
maxbasicrate);
@@ -1881,6 +1951,12 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxbasicrate);
/* Set rates mask for unicast frames. */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ mode = R92C_RAID_11GN;
+ else if (ic->ic_curmode == IEEE80211_MODE_11B)
+ mode = R92C_RAID_11B;
+ else
+ mode = R92C_RAID_11BG;
cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID;
cmd.mask = htole32(mode << 28 | rates);
error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
@@ -1896,7 +1972,11 @@ urtwn_ra_init(struct urtwn_softc *sc)
maxrate);
/* Indicate highest supported rate. */
- ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ni->ni_txrate = rs_ht->rs_rates[rs_ht->rs_nrates - 1]
+ | IEEE80211_RATE_MCS;
+ else
+ ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1];
ieee80211_free_node(ni);
return (0);
@@ -2559,7 +2639,7 @@ urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi)
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
else
sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
- URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: PWDB %d, EMA %d\n", __func__,
+ URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: PWDB %d, EMA %d\n", __func__,
pwdb, sc->avg_pwdb);
}
@@ -2643,7 +2723,12 @@ urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt)
static __inline uint8_t
rate2ridx(uint8_t rate)
{
+ if (rate & IEEE80211_RATE_MCS) {
+ /* 11n rates start at idx 12 */
+ return ((rate & 0xf) + 12);
+ }
switch (rate) {
+ /* 11g */
case 12: return 4;
case 18: return 5;
case 24: return 6;
@@ -2652,6 +2737,7 @@ rate2ridx(uint8_t rate)
case 72: return 9;
case 96: return 10;
case 108: return 11;
+ /* 11b */
case 2: return 0;
case 4: return 1;
case 11: return 2;
@@ -2711,15 +2797,24 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
} else {
- if (ic->ic_curmode != IEEE80211_MODE_11B)
+ /* XXX TODO: drop the default rate for 11b/11g? */
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */
+ else if (ic->ic_curmode != IEEE80211_MODE_11B)
rate = 108;
else
rate = 22;
}
}
+ /*
+ * XXX TODO: this should be per-node, for 11b versus 11bg
+ * nodes in hostap mode
+ */
ridx = rate2ridx(rate);
- if (ic->ic_curmode != IEEE80211_MODE_11B)
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ raid = R92C_RAID_11GN;
+ else if (ic->ic_curmode != IEEE80211_MODE_11B)
raid = R92C_RAID_11BG;
else
raid = R92C_RAID_11B;
@@ -2763,7 +2858,10 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
} else
txd->txdw1 |= htole32(R92C_TXDW1_AGGBK);
- if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ /* protmode, non-HT */
+ /* XXX TODO: noack frames? */
+ if ((rate & 0x80) == 0 &&
+ (ic->ic_flags & IEEE80211_F_USEPROT)) {
switch (ic->ic_protmode) {
case IEEE80211_PROT_CTSONLY:
txd->txdw4 |= htole32(
@@ -2779,8 +2877,21 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
break;
}
}
+
+ /* protmode, HT */
+ /* XXX TODO: noack frames? */
+ if ((rate & 0x80) &&
+ (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) {
+ txd->txdw4 |= htole32(
+ R92C_TXDW4_RTSEN |
+ R92C_TXDW4_HWRTSEN);
+ }
+
+ /* XXX TODO: rtsrate is configurable? 24mbit may
+ * be a bit high for RTS rate? */
txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE,
URTWN_RIDX_OFDM24));
+
txd->txdw5 |= htole32(0x0001ff00);
} else /* IEEE80211_FC0_TYPE_MGT */
qsel = R92C_TXDW1_QSEL_MGNT;
@@ -2793,14 +2904,21 @@ urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni,
SM(R92C_TXDW1_QSEL, qsel) |
SM(R92C_TXDW1_RAID, raid));
+ /* XXX TODO: 40MHZ flag? */
+ /* XXX TODO: AMPDU flag? (AGG_ENABLE or AGG_BREAK?) Density shift? */
+ /* XXX Short preamble? */
+ /* XXX Short-GI? */
+
if (sc->chip & URTWN_CHIP_88E)
txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid));
else
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid));
txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx));
+
/* Force this rate if needed. */
if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast ||
+ (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) ||
(m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA)
txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE);
@@ -2888,6 +3006,8 @@ urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni,
}
}
+ /* XXX TODO: 11n checks, matching urtwn_tx_data() */
+
wh = mtod(m, struct ieee80211_frame *);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
@@ -2916,6 +3036,7 @@ urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni,
else
txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC));
+ /* XXX TODO: rate index/config (RAID) for 11n? */
txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT));
txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
diff --git a/sys/dev/usb/wlan/if_urtwnreg.h b/sys/dev/urtwn/if_urtwnreg.h
index 72835f3..72835f3 100644
--- a/sys/dev/usb/wlan/if_urtwnreg.h
+++ b/sys/dev/urtwn/if_urtwnreg.h
diff --git a/sys/dev/usb/wlan/if_urtwnvar.h b/sys/dev/urtwn/if_urtwnvar.h
index ba8ca81..ba8ca81 100644
--- a/sys/dev/usb/wlan/if_urtwnvar.h
+++ b/sys/dev/urtwn/if_urtwnvar.h
diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c
index 3a6f725..cad351c 100644
--- a/sys/dev/usb/controller/ehci_pci.c
+++ b/sys/dev/usb/controller/ehci_pci.c
@@ -112,6 +112,8 @@ ehci_pci_match(device_t self)
case 0x20951022:
return ("AMD CS5536 (Geode) USB 2.0 controller");
+ case 0x78081022:
+ return ("AMD FCH USB 2.0 controller");
case 0x43451002:
return "ATI SB200 USB 2.0 controller";
@@ -168,6 +170,10 @@ ehci_pci_match(device_t self)
return ("Intel Wildcat Point USB 2.0 controller USB-A");
case 0x8cad8086:
return ("Intel Wildcat Point USB 2.0 controller USB-B");
+ case 0x8d268086:
+ return ("Intel Wellsburg USB 2.0 controller");
+ case 0x8d2d8086:
+ return ("Intel Wellsburg USB 2.0 controller");
case 0x9c268086:
return ("Intel Lynx Point LP USB 2.0 controller USB");
diff --git a/sys/dev/usb/controller/ohci_pci.c b/sys/dev/usb/controller/ohci_pci.c
index c50de54..96950a7 100644
--- a/sys/dev/usb/controller/ohci_pci.c
+++ b/sys/dev/usb/controller/ohci_pci.c
@@ -124,9 +124,10 @@ ohci_pci_match(device_t self)
case 0x740c1022:
return ("AMD-756 USB Controller");
-
case 0x74141022:
return ("AMD-766 USB Controller");
+ case 0x78071022:
+ return ("AMD FCH USB Controller");
case 0x43741002:
return "ATI SB400 USB Controller";
diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c
index e7e4412..5916996 100644
--- a/sys/dev/usb/controller/uhci_pci.c
+++ b/sys/dev/usb/controller/uhci_pci.c
@@ -161,6 +161,12 @@ uhci_pci_match(device_t self)
case 0x24de8086:
return ("Intel 82801EB (ICH5) USB controller USB-D");
+ case 0x25a98086:
+ return ("Intel 6300ESB USB controller USB-A");
+
+ case 0x25aa8086:
+ return ("Intel 6300ESB USB controller USB-B");
+
case 0x26588086:
return ("Intel 82801FB/FR/FW/FRW (ICH6) USB controller USB-A");
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
index 0a8a95b..d4355e9 100644
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -95,6 +95,9 @@ xhci_pci_match(device_t self)
uint32_t device_id = pci_get_devid(self);
switch (device_id) {
+ case 0x78141022:
+ return ("AMD FCH USB 3.0 controller");
+
case 0x01941033:
return ("NEC uPD720200 USB 3.0 controller");
@@ -115,6 +118,8 @@ xhci_pci_match(device_t self)
return ("Intel Lynx Point USB 3.0 controller");
case 0x8cb18086:
return ("Intel Wildcat Point USB 3.0 controller");
+ case 0x8d318086:
+ return ("Intel Wellsburg USB 3.0 controller");
case 0x9cb18086:
return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller");
diff --git a/sys/dev/usb/usb_busdma.c b/sys/dev/usb/usb_busdma.c
index 821e0fb..75378a2 100644
--- a/sys/dev/usb/usb_busdma.c
+++ b/sys/dev/usb/usb_busdma.c
@@ -472,17 +472,22 @@ usb_pc_common_mem_cb(void *arg, bus_dma_segment_t *segs,
pc->page_offset_buf = rem;
pc->page_offset_end += rem;
#ifdef USB_DEBUG
- if (nseg > 1 &&
- ((segs->ds_addr + segs->ds_len) & (USB_PAGE_SIZE - 1)) !=
- ((segs + 1)->ds_addr & (USB_PAGE_SIZE - 1))) {
- /*
- * This check verifies there is no page offset hole
- * between the first and second segment. See the
- * BUS_DMA_KEEP_PG_OFFSET flag.
- */
- DPRINTFN(0, "Page offset was not preserved\n");
- error = 1;
- goto done;
+ if (nseg > 1) {
+ int x;
+
+ for (x = 0; x != nseg - 1; x++) {
+ if (((segs[x].ds_addr + segs[x].ds_len) & (USB_PAGE_SIZE - 1)) ==
+ ((segs[x + 1].ds_addr & (USB_PAGE_SIZE - 1))))
+ continue;
+ /*
+ * This check verifies there is no page offset
+ * hole between any of the segments. See the
+ * BUS_DMA_KEEP_PG_OFFSET flag.
+ */
+ DPRINTFN(0, "Page offset was not preserved\n");
+ error = 1;
+ goto done;
+ }
}
#endif
while (pc->ismultiseg) {
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 07b3f73..7f75d5a 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -1700,6 +1700,7 @@ product DISPLAYLINK UM7X0 0x401a nanovision MiMo
product DISPLAYLINK LT1421 0x03e0 Lenovo ThinkVision LT1421
product DISPLAYLINK POLARIS2 0x0117 Polaris2 USB dock
product DISPLAYLINK PLUGABLE 0x0377 Plugable docking station
+product DISPLAYLINK ITEC 0x02e9 i-tec USB 2.0 Docking Station
/* DMI products */
product DMI CFSM_RW 0xa109 CF/SM Reader/Writer
diff --git a/sys/dev/usb/video/udl.c b/sys/dev/usb/video/udl.c
index 0d7c504..1096ed3 100644
--- a/sys/dev/usb/video/udl.c
+++ b/sys/dev/usb/video/udl.c
@@ -177,7 +177,8 @@ static const STRUCT_USB_HOST_ID udl_devs[] = {
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_PLUGABLE, DL160)},
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70, DL125)},
{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2, DLUNK)},
- {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)}
+ {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)},
+ {USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_ITEC, DL165)},
};
static void
diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c
index e428a8f..08be717 100644
--- a/sys/dev/usb/wlan/if_rum.c
+++ b/sys/dev/usb/wlan/if_rum.c
@@ -154,6 +154,7 @@ static usb_callback_t rum_bulk_write_callback;
static usb_error_t rum_do_request(struct rum_softc *sc,
struct usb_device_request *req, void *data);
+static usb_error_t rum_do_mcu_request(struct rum_softc *sc, int);
static struct ieee80211vap *rum_vap_create(struct ieee80211com *,
const char [IFNAMSIZ], int, enum ieee80211_opmode,
int, const uint8_t [IEEE80211_ADDR_LEN],
@@ -165,6 +166,11 @@ static int rum_cmd_sleepable(struct rum_softc *, const void *,
static void rum_tx_free(struct rum_tx_data *, int);
static void rum_setup_tx_list(struct rum_softc *);
static void rum_unsetup_tx_list(struct rum_softc *);
+static void rum_beacon_miss(struct ieee80211vap *);
+static void rum_sta_recv_mgmt(struct ieee80211_node *,
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *, int, int);
+static int rum_set_power_state(struct rum_softc *, int);
static int rum_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static uint8_t rum_crypto_mode(struct rum_softc *, u_int, int);
@@ -232,6 +238,8 @@ static int rum_init(struct rum_softc *);
static void rum_stop(struct rum_softc *);
static void rum_load_microcode(struct rum_softc *, const uint8_t *,
size_t);
+static int rum_set_sleep_time(struct rum_softc *, uint16_t);
+static int rum_reset(struct ieee80211vap *, u_long);
static int rum_set_beacon(struct rum_softc *,
struct ieee80211vap *);
static int rum_alloc_beacon(struct rum_softc *,
@@ -530,6 +538,8 @@ rum_attach(device_t self)
| IEEE80211_C_BGSCAN /* bg scanning supported */
| IEEE80211_C_WPA /* 802.11i */
| IEEE80211_C_WME /* 802.11e */
+ | IEEE80211_C_PMGT /* Station-side power mgmt */
+ | IEEE80211_C_SWSLEEP /* net80211 managed power mgmt */
;
ic->ic_cryptocaps =
@@ -629,6 +639,20 @@ rum_do_request(struct rum_softc *sc,
return (err);
}
+static usb_error_t
+rum_do_mcu_request(struct rum_softc *sc, int request)
+{
+ struct usb_device_request req;
+
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ req.bRequest = RT2573_MCU_CNTL;
+ USETW(req.wValue, request);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+
+ return (rum_do_request(sc, &req, NULL));
+}
+
static struct ieee80211vap *
rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
enum ieee80211_opmode opmode, int flags,
@@ -659,8 +683,24 @@ rum_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
vap->iv_key_set = rum_key_set;
vap->iv_key_delete = rum_key_delete;
vap->iv_update_beacon = rum_update_beacon;
+ vap->iv_reset = rum_reset;
vap->iv_max_aid = RT2573_ADDR_MAX;
+ if (opmode == IEEE80211_M_STA) {
+ /*
+ * Move device to the sleep state when
+ * beacon is received and there is no data for us.
+ *
+ * Used only for IEEE80211_S_SLEEP state.
+ */
+ rvp->recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = rum_sta_recv_mgmt;
+
+ /* Ignored while sleeping. */
+ rvp->bmiss = vap->iv_bmiss;
+ vap->iv_bmiss = rum_beacon_miss;
+ }
+
usb_callout_init_mtx(&rvp->ratectl_ch, &sc->sc_mtx, 0);
TASK_INIT(&rvp->ratectl_task, 0, rum_ratectl_task, rvp);
ieee80211_ratectl_init(vap);
@@ -795,6 +835,89 @@ rum_unsetup_tx_list(struct rum_softc *sc)
}
}
+static void
+rum_beacon_miss(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct rum_softc *sc = ic->ic_softc;
+ struct rum_vap *rvp = RUM_VAP(vap);
+ int sleep;
+
+ RUM_LOCK(sc);
+ if (sc->sc_sleeping && sc->sc_sleep_end < ticks) {
+ DPRINTFN(12, "dropping 'sleeping' bit, "
+ "device must be awake now\n");
+
+ sc->sc_sleeping = 0;
+ }
+
+ sleep = sc->sc_sleeping;
+ RUM_UNLOCK(sc);
+
+ if (!sleep)
+ rvp->bmiss(vap);
+#ifdef USB_DEBUG
+ else
+ DPRINTFN(13, "bmiss event is ignored whilst sleeping\n");
+#endif
+}
+
+static void
+rum_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
+ const struct ieee80211_rx_stats *rxs,
+ int rssi, int nf)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct rum_softc *sc = vap->iv_ic->ic_softc;
+ struct rum_vap *rvp = RUM_VAP(vap);
+
+ if (vap->iv_state == IEEE80211_S_SLEEP &&
+ subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
+ RUM_LOCK(sc);
+ DPRINTFN(12, "beacon, mybss %d (flags %02X)\n",
+ !!(sc->last_rx_flags & RT2573_RX_MYBSS),
+ sc->last_rx_flags);
+
+ if ((sc->last_rx_flags & (RT2573_RX_MYBSS | RT2573_RX_BC)) ==
+ (RT2573_RX_MYBSS | RT2573_RX_BC)) {
+ /*
+ * Put it to sleep here; in case if there is a data
+ * for us, iv_recv_mgmt() will wakeup the device via
+ * SLEEP -> RUN state transition.
+ */
+ rum_set_power_state(sc, 1);
+ }
+ RUM_UNLOCK(sc);
+ }
+
+ rvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
+}
+
+static int
+rum_set_power_state(struct rum_softc *sc, int sleep)
+{
+ usb_error_t uerror;
+
+ RUM_LOCK_ASSERT(sc);
+
+ DPRINTFN(12, "moving to %s state (sleep time %u)\n",
+ sleep ? "sleep" : "awake", sc->sc_sleep_time);
+
+ uerror = rum_do_mcu_request(sc,
+ sleep ? RT2573_MCU_SLEEP : RT2573_MCU_WAKEUP);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ device_printf(sc->sc_dev,
+ "%s: could not change power state: %s\n",
+ __func__, usbd_errstr(uerror));
+ return (EIO);
+ }
+
+ sc->sc_sleeping = !!sleep;
+ sc->sc_sleep_end = sleep ? ticks + sc->sc_sleep_time : 0;
+
+ return (0);
+}
+
static int
rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
@@ -804,7 +927,8 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
const struct ieee80211_txparam *tp;
enum ieee80211_state ostate;
struct ieee80211_node *ni;
- int ret;
+ usb_error_t uerror;
+ int ret = 0;
ostate = vap->iv_state;
DPRINTF("%s -> %s\n",
@@ -815,6 +939,17 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
RUM_LOCK(sc);
usb_callout_stop(&rvp->ratectl_ch);
+ if (ostate == IEEE80211_S_SLEEP && vap->iv_opmode == IEEE80211_M_STA) {
+ rum_clrbits(sc, RT2573_TXRX_CSR4, RT2573_ACKCTS_PWRMGT);
+ rum_clrbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+
+ /*
+ * Ignore any errors;
+ * any subsequent TX will wakeup it anyway
+ */
+ (void) rum_set_power_state(sc, 0);
+ }
+
switch (nstate) {
case IEEE80211_S_INIT:
if (ostate == IEEE80211_S_RUN)
@@ -823,6 +958,9 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
break;
case IEEE80211_S_RUN:
+ if (ostate == IEEE80211_S_SLEEP)
+ break; /* already handled */
+
ni = ieee80211_ref_node(vap->iv_bss);
if (vap->iv_opmode != IEEE80211_M_MONITOR) {
@@ -857,20 +995,39 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE)
rum_ratectl_start(sc, ni);
+run_fail:
ieee80211_free_node(ni);
break;
+ case IEEE80211_S_SLEEP:
+ /* Implemented for STA mode only. */
+ if (vap->iv_opmode != IEEE80211_M_STA)
+ break;
+
+ uerror = rum_setbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ ret = EIO;
+ break;
+ }
+
+ uerror = rum_setbits(sc, RT2573_TXRX_CSR4, RT2573_ACKCTS_PWRMGT);
+ if (uerror != USB_ERR_NORMAL_COMPLETION) {
+ ret = EIO;
+ break;
+ }
+
+ ret = rum_set_power_state(sc, 1);
+ if (ret != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not move to the SLEEP state: %s\n",
+ __func__, usbd_errstr(uerror));
+ }
+ break;
default:
break;
}
RUM_UNLOCK(sc);
IEEE80211_LOCK(ic);
- return (rvp->newstate(vap, nstate, arg));
-
-run_fail:
- RUM_UNLOCK(sc);
- IEEE80211_LOCK(ic);
- ieee80211_free_node(ni);
- return ret;
+ return (ret == 0 ? rvp->newstate(vap, nstate, arg) : ret);
}
static void
@@ -1001,6 +1158,7 @@ rum_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
rssi = rum_get_rssi(sc, sc->sc_rx_desc.rssi);
flags = le32toh(sc->sc_rx_desc.flags);
+ sc->last_rx_flags = flags;
if (flags & RT2573_RX_CRC_ERROR) {
/*
* This should not happen since we did not
@@ -1995,6 +2153,7 @@ rum_enable_tsf_sync(struct rum_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
uint32_t tmp;
+ uint16_t bintval;
if (vap->iv_opmode != IEEE80211_M_STA) {
/*
@@ -2008,7 +2167,8 @@ rum_enable_tsf_sync(struct rum_softc *sc)
tmp = rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000;
/* set beacon interval (in 1/16ms unit) */
- tmp |= vap->iv_bss->ni_intval * 16;
+ bintval = vap->iv_bss->ni_intval;
+ tmp |= bintval * 16;
tmp |= RT2573_TSF_TIMER_EN | RT2573_TBTT_TIMER_EN;
switch (vap->iv_opmode) {
@@ -2042,7 +2202,8 @@ rum_enable_tsf_sync(struct rum_softc *sc)
if (rum_write(sc, RT2573_TXRX_CSR9, tmp) != 0)
return EIO;
- return 0;
+ /* refresh current sleep time */
+ return (rum_set_sleep_time(sc, bintval));
}
static void
@@ -2460,7 +2621,6 @@ rum_stop(struct rum_softc *sc)
static void
rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
{
- struct usb_device_request req;
uint16_t reg = RT2573_MCU_CODE_BASE;
usb_error_t err;
@@ -2475,14 +2635,8 @@ rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
}
}
- req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
- req.bRequest = RT2573_MCU_CNTL;
- USETW(req.wValue, RT2573_MCU_RUN);
- USETW(req.wIndex, 0);
- USETW(req.wLength, 0);
-
- err = rum_do_request(sc, &req, NULL);
- if (err != 0) {
+ err = rum_do_mcu_request(sc, RT2573_MCU_RUN);
+ if (err != USB_ERR_NORMAL_COMPLETION) {
device_printf(sc->sc_dev, "could not run firmware: %s\n",
usbd_errstr(err));
}
@@ -2492,6 +2646,72 @@ rum_load_microcode(struct rum_softc *sc, const uint8_t *ucode, size_t size)
}
static int
+rum_set_sleep_time(struct rum_softc *sc, uint16_t bintval)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ usb_error_t uerror;
+ int exp, delay;
+
+ RUM_LOCK_ASSERT(sc);
+
+ exp = ic->ic_lintval / bintval;
+ delay = ic->ic_lintval % bintval;
+
+ if (exp > RT2573_TBCN_EXP_MAX)
+ exp = RT2573_TBCN_EXP_MAX;
+ if (delay > RT2573_TBCN_DELAY_MAX)
+ delay = RT2573_TBCN_DELAY_MAX;
+
+ uerror = rum_modbits(sc, RT2573_MAC_CSR11,
+ RT2573_TBCN_EXP(exp) |
+ RT2573_TBCN_DELAY(delay),
+ RT2573_TBCN_EXP(RT2573_TBCN_EXP_MAX) |
+ RT2573_TBCN_DELAY(RT2573_TBCN_DELAY_MAX));
+
+ if (uerror != USB_ERR_NORMAL_COMPLETION)
+ return (EIO);
+
+ sc->sc_sleep_time = IEEE80211_TU_TO_TICKS(exp * bintval + delay);
+
+ return (0);
+}
+
+static int
+rum_reset(struct ieee80211vap *vap, u_long cmd)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_node *ni;
+ struct rum_softc *sc = ic->ic_softc;
+ int error;
+
+ switch (cmd) {
+ case IEEE80211_IOC_POWERSAVE:
+ error = 0;
+ break;
+ case IEEE80211_IOC_POWERSAVESLEEP:
+ ni = ieee80211_ref_node(vap->iv_bss);
+
+ RUM_LOCK(sc);
+ error = rum_set_sleep_time(sc, ni->ni_intval);
+ if (vap->iv_state == IEEE80211_S_SLEEP) {
+ /* Use new values for wakeup timer. */
+ rum_clrbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ rum_setbits(sc, RT2573_MAC_CSR11, RT2573_AUTO_WAKEUP);
+ }
+ /* XXX send reassoc */
+ RUM_UNLOCK(sc);
+
+ ieee80211_free_node(ni);
+ break;
+ default:
+ error = ENETRESET;
+ break;
+ }
+
+ return (error);
+}
+
+static int
rum_set_beacon(struct rum_softc *sc, struct ieee80211vap *vap)
{
struct ieee80211com *ic = vap->iv_ic;
@@ -2924,14 +3144,15 @@ rum_scan_end(struct ieee80211com *ic)
{
struct rum_softc *sc = ic->ic_softc;
- RUM_LOCK(sc);
- if (ic->ic_opmode != IEEE80211_M_AHDEMO)
- rum_enable_tsf_sync(sc);
- else
- rum_enable_tsf(sc);
- rum_set_bssid(sc, sc->sc_bssid);
- RUM_UNLOCK(sc);
-
+ if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) {
+ RUM_LOCK(sc);
+ if (ic->ic_opmode != IEEE80211_M_AHDEMO)
+ rum_enable_tsf_sync(sc);
+ else
+ rum_enable_tsf(sc);
+ rum_set_bssid(sc, sc->sc_bssid);
+ RUM_UNLOCK(sc);
+ }
}
static void
diff --git a/sys/dev/usb/wlan/if_rumreg.h b/sys/dev/usb/wlan/if_rumreg.h
index 06c0a81..96726b1 100644
--- a/sys/dev/usb/wlan/if_rumreg.h
+++ b/sys/dev/usb/wlan/if_rumreg.h
@@ -136,6 +136,13 @@
/* possible flags for register MAC_CSR5 */
#define RT2573_NUM_BSSID_MSK(n) (((n * 3) & 3) << 16)
+/* possible flags for register MAC_CSR11 */
+#define RT2573_AUTO_WAKEUP (1 << 15)
+#define RT2573_TBCN_EXP(n) ((n) << 8)
+#define RT2573_TBCN_EXP_MAX 0x7f
+#define RT2573_TBCN_DELAY(t) (t)
+#define RT2573_TBCN_DELAY_MAX 0xff
+
/* possible flags for register TXRX_CSR0 */
/* Tx filter flags are in the low 16 bits */
#define RT2573_AUTO_TX_SEQ (1 << 15)
@@ -152,6 +159,7 @@
#define RT2573_DROP_ACKCTS (1 << 25)
/* possible flags for register TXRX_CSR4 */
+#define RT2573_ACKCTS_PWRMGT (1 << 16)
#define RT2573_SHORT_PREAMBLE (1 << 18)
#define RT2573_MRR_ENABLED (1 << 19)
#define RT2573_MRR_CCK_FALLBACK (1 << 22)
@@ -188,7 +196,10 @@
#define RT2573_LED_ON 0x1e1e
#define RT2573_LED_OFF 0x0
-#define RT2573_MCU_RUN (1 << 3)
+/* USB vendor requests */
+#define RT2573_MCU_SLEEP 7
+#define RT2573_MCU_RUN 8
+#define RT2573_MCU_WAKEUP 9
#define RT2573_SMART_MODE (1 << 0)
diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h
index d494468..6c42569 100644
--- a/sys/dev/usb/wlan/if_rumvar.h
+++ b/sys/dev/usb/wlan/if_rumvar.h
@@ -96,6 +96,11 @@ struct rum_vap {
int (*newstate)(struct ieee80211vap *,
enum ieee80211_state, int);
+ void (*bmiss)(struct ieee80211vap *);
+ void (*recv_mgmt)(struct ieee80211_node *,
+ struct mbuf *, int,
+ const struct ieee80211_rx_stats *,
+ int, int);
};
#define RUM_VAP(vap) ((struct rum_vap *)(vap))
@@ -124,6 +129,10 @@ struct rum_softc {
struct mtx sc_mtx;
+ int sc_sleep_end;
+ int sc_sleep_time;
+ uint8_t last_rx_flags;
+
struct rum_cmdq cmdq[RUM_CMDQ_SIZE];
struct mtx cmdq_mtx;
struct task cmdq_task;
@@ -135,6 +144,7 @@ struct rum_softc {
uint8_t txpow[44];
u_int sc_detached:1,
sc_running:1,
+ sc_sleeping:1,
sc_clr_shkeys:1;
uint8_t sc_bssid[IEEE80211_ADDR_LEN];
diff --git a/sys/dev/vnic/nic_main.c b/sys/dev/vnic/nic_main.c
index 0b21952..ae04326 100644
--- a/sys/dev/vnic/nic_main.c
+++ b/sys/dev/vnic/nic_main.c
@@ -119,7 +119,7 @@ static int nicpf_detach(device_t);
#ifdef PCI_IOV
static int nicpf_iov_init(device_t, uint16_t, const nvlist_t *);
static void nicpf_iov_uninit(device_t);
-static int nicpf_iov_addr_vf(device_t, uint16_t, const nvlist_t *);
+static int nicpf_iov_add_vf(device_t, uint16_t, const nvlist_t *);
#endif
static device_method_t nicpf_methods[] = {
@@ -131,7 +131,7 @@ static device_method_t nicpf_methods[] = {
#ifdef PCI_IOV
DEVMETHOD(pci_iov_init, nicpf_iov_init),
DEVMETHOD(pci_iov_uninit, nicpf_iov_uninit),
- DEVMETHOD(pci_iov_add_vf, nicpf_iov_addr_vf),
+ DEVMETHOD(pci_iov_add_vf, nicpf_iov_add_vf),
#endif
DEVMETHOD_END,
};
@@ -269,18 +269,9 @@ nicpf_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
nic = device_get_softc(dev);
- nic->num_vf_en = 0;
if (num_vfs == 0)
return (ENXIO);
- if (num_vfs > MAX_NUM_VFS_SUPPORTED)
- return (EINVAL);
- /*
- * Just set variables here.
- * The number of VFs will be written to configuration
- * space later in PCI_ADD_VF().
- */
- nic->num_vf_en = num_vfs;
nic->flags |= NIC_SRIOV_ENABLED;
return (0);
@@ -294,7 +285,7 @@ nicpf_iov_uninit(device_t dev)
}
static int
-nicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
+nicpf_iov_add_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
{
const void *mac;
struct nicpf *nic;
@@ -306,6 +297,9 @@ nicpf_iov_addr_vf(device_t dev, uint16_t vfnum, const nvlist_t *params)
if ((nic->flags & NIC_SRIOV_ENABLED) == 0)
return (ENXIO);
+ if (vfnum > (nic->num_vf_en - 1))
+ return (EINVAL);
+
if (nvlist_exists_binary(params, "mac-addr") != 0) {
mac = nvlist_get_binary(params, "mac-addr", &size);
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vfnum]);
@@ -1094,11 +1088,8 @@ static int nic_sriov_init(device_t dev, struct nicpf *nic)
}
/* Fix-up the number of enabled VFs */
total_vf_cnt = pci_read_config(dev, iov_pos + PCIR_SRIOV_TOTAL_VFS, 2);
- if (total_vf_cnt < nic->num_vf_en)
- nic->num_vf_en = total_vf_cnt;
-
if (total_vf_cnt == 0)
- return (0);
+ return (ENXIO);
/* Attach SR-IOV */
pf_schema = pci_iov_schema_alloc_node();
@@ -1116,7 +1107,6 @@ static int nic_sriov_init(device_t dev, struct nicpf *nic)
device_printf(dev,
"Failed to initialize SR-IOV (error=%d)\n",
err);
- nic->num_vf_en = 0;
return (err);
}
#endif
diff --git a/sys/dev/vnic/nicvf_main.c b/sys/dev/vnic/nicvf_main.c
index 4625846..5b74ac9 100644
--- a/sys/dev/vnic/nicvf_main.c
+++ b/sys/dev/vnic/nicvf_main.c
@@ -661,12 +661,6 @@ nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf)
sq = &qs->sq[qidx];
- if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
- IFF_DRV_RUNNING) {
- err = drbr_enqueue(ifp, sq->br, mbuf);
- return (err);
- }
-
if (mbuf->m_next != NULL &&
(mbuf->m_pkthdr.csum_flags &
(CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_SCTP)) != 0) {
@@ -679,17 +673,23 @@ nicvf_if_transmit(struct ifnet *ifp, struct mbuf *mbuf)
}
}
+ err = drbr_enqueue(ifp, sq->br, mbuf);
+ if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING) || !nic->link_up || (err != 0)) {
+ /*
+ * Try to enqueue packet to the ring buffer.
+ * If the driver is not active, link down or enqueue operation
+ * failed, return with the appropriate error code.
+ */
+ return (err);
+ }
+
if (NICVF_TX_TRYLOCK(sq) != 0) {
- err = nicvf_tx_mbuf_locked(sq, mbuf);
+ err = nicvf_xmit_locked(sq);
NICVF_TX_UNLOCK(sq);
return (err);
- } else {
- err = drbr_enqueue(ifp, sq->br, mbuf);
- if (err != 0)
- return (err);
-
+ } else
taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
- }
return (0);
}
diff --git a/sys/dev/vnic/nicvf_queues.c b/sys/dev/vnic/nicvf_queues.c
index 13ea636..9b46d7c 100644
--- a/sys/dev/vnic/nicvf_queues.c
+++ b/sys/dev/vnic/nicvf_queues.c
@@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/sockio.h>
#include <sys/socket.h>
-#include <sys/stdatomic.h>
#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -61,11 +60,12 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/vmparam.h>
-#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_media.h>
#include <net/ifq.h>
+#include <net/bpf.h>
+#include <net/ethernet.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
@@ -106,6 +106,8 @@ static void nicvf_cmp_queue_config(struct nicvf *, struct queue_set *, int,
boolean_t);
static void nicvf_sq_free_used_descs(struct nicvf *, struct snd_queue *, int);
+static int nicvf_tx_mbuf_locked(struct snd_queue *, struct mbuf **);
+
static void nicvf_rbdr_task(void *, int);
static void nicvf_rbdr_task_nowait(void *, int);
@@ -740,10 +742,10 @@ nicvf_cq_intr_handler(struct nicvf *nic, uint8_t cq_idx)
int cqe_count, cqe_head;
struct queue_set *qs = nic->qs;
struct cmp_queue *cq = &qs->cq[cq_idx];
+ struct snd_queue *sq = &qs->sq[cq_idx];
struct rcv_queue *rq;
struct cqe_rx_t *cq_desc;
struct lro_ctrl *lro;
- struct lro_entry *queued;
int rq_idx;
int cmp_err;
@@ -819,6 +821,7 @@ done:
((if_getdrvflags(nic->ifp) & IFF_DRV_RUNNING) != 0)) {
/* Reenable TXQ if its stopped earlier due to SQ full */
if_setdrvflagbits(nic->ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
+ taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
}
out:
/*
@@ -827,10 +830,7 @@ out:
rq_idx = cq_idx;
rq = &nic->qs->rq[rq_idx];
lro = &rq->lro;
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
NICVF_CMP_UNLOCK(cq);
@@ -992,25 +992,62 @@ nicvf_free_cmp_queue(struct nicvf *nic, struct cmp_queue *cq)
memset(cq->mtx_name, 0, sizeof(cq->mtx_name));
}
-static void
-nicvf_snd_task(void *arg, int pending)
+int
+nicvf_xmit_locked(struct snd_queue *sq)
{
- struct snd_queue *sq = (struct snd_queue *)arg;
- struct mbuf *mbuf;
+ struct nicvf *nic;
+ struct ifnet *ifp;
+ struct mbuf *next;
+ int err;
- NICVF_TX_LOCK(sq);
- while (1) {
- mbuf = drbr_dequeue(NULL, sq->br);
- if (mbuf == NULL)
- break;
+ NICVF_TX_LOCK_ASSERT(sq);
+
+ nic = sq->nic;
+ ifp = nic->ifp;
+ err = 0;
+
+ while ((next = drbr_peek(ifp, sq->br)) != NULL) {
+ err = nicvf_tx_mbuf_locked(sq, &next);
+ if (err != 0) {
+ if (next == NULL)
+ drbr_advance(ifp, sq->br);
+ else
+ drbr_putback(ifp, sq->br, next);
- if (nicvf_tx_mbuf_locked(sq, mbuf) != 0) {
- /* XXX ARM64TODO: Increase Tx drop counter */
- m_freem(mbuf);
break;
}
+ drbr_advance(ifp, sq->br);
+ /* Send a copy of the frame to the BPF listener */
+ ETHER_BPF_MTAP(ifp, next);
}
+ return (err);
+}
+
+static void
+nicvf_snd_task(void *arg, int pending)
+{
+ struct snd_queue *sq = (struct snd_queue *)arg;
+ struct nicvf *nic;
+ struct ifnet *ifp;
+ int err;
+
+ nic = sq->nic;
+ ifp = nic->ifp;
+
+ /*
+ * Skip sending anything if the driver is not running,
+ * SQ full or link is down.
+ */
+ if (((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING) || !nic->link_up)
+ return;
+
+ NICVF_TX_LOCK(sq);
+ err = nicvf_xmit_locked(sq);
NICVF_TX_UNLOCK(sq);
+ /* Try again */
+ if (err != 0)
+ taskqueue_enqueue(sq->snd_taskq, &sq->snd_task);
}
/* Initialize transmit queue */
@@ -1048,7 +1085,7 @@ nicvf_init_snd_queue(struct nicvf *nic, struct snd_queue *sq, int q_len,
sq->desc = sq->dmem.base;
sq->head = sq->tail = 0;
- atomic_store_rel_int(&sq->free_cnt, q_len - 1);
+ sq->free_cnt = q_len - 1;
sq->thresh = SND_QUEUE_THRESH;
sq->idx = qidx;
sq->nic = nic;
@@ -1640,7 +1677,7 @@ nicvf_get_sq_desc(struct snd_queue *sq, int desc_cnt)
int qentry;
qentry = sq->tail;
- atomic_subtract_int(&sq->free_cnt, desc_cnt);
+ sq->free_cnt -= desc_cnt;
sq->tail += desc_cnt;
sq->tail &= (sq->dmem.q_len - 1);
@@ -1652,7 +1689,7 @@ static void
nicvf_put_sq_desc(struct snd_queue *sq, int desc_cnt)
{
- atomic_add_int(&sq->free_cnt, desc_cnt);
+ sq->free_cnt += desc_cnt;
sq->head += desc_cnt;
sq->head &= (sq->dmem.q_len - 1);
}
@@ -1772,7 +1809,6 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry,
}
ip = (struct ip *)(mbuf->m_data + ehdrlen);
- ip->ip_sum = 0;
iphlen = ip->ip_hl << 2;
poff = ehdrlen + iphlen;
@@ -1864,8 +1900,8 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry,
}
/* Put an mbuf to a SQ for packet transfer. */
-int
-nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
+static int
+nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf **mbufp)
{
bus_dma_segment_t segs[256];
struct nicvf *nic;
@@ -1883,15 +1919,17 @@ nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
snd_buff = &sq->snd_buff[sq->tail];
err = bus_dmamap_load_mbuf_sg(sq->snd_buff_dmat, snd_buff->dmap,
- mbuf, segs, &nsegs, BUS_DMA_NOWAIT);
- if (err != 0) {
+ *mbufp, segs, &nsegs, BUS_DMA_NOWAIT);
+ if (__predict_false(err != 0)) {
/* ARM64TODO: Add mbuf defragmenting if we lack maps */
+ m_freem(*mbufp);
+ *mbufp = NULL;
return (err);
}
/* Set how many subdescriptors is required */
nic = sq->nic;
- if (mbuf->m_pkthdr.tso_segsz != 0 && nic->hw_tso)
+ if ((*mbufp)->m_pkthdr.tso_segsz != 0 && nic->hw_tso)
subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT;
else
subdesc_cnt = MIN_SQ_DESC_PER_PKT_XMIT + nsegs - 1;
@@ -1905,10 +1943,15 @@ nicvf_tx_mbuf_locked(struct snd_queue *sq, struct mbuf *mbuf)
qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
/* Add SQ header subdesc */
- err = nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, mbuf,
- mbuf->m_pkthdr.len);
+ err = nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, *mbufp,
+ (*mbufp)->m_pkthdr.len);
if (err != 0) {
+ nicvf_put_sq_desc(sq, subdesc_cnt);
bus_dmamap_unload(sq->snd_buff_dmat, snd_buff->dmap);
+ if (err == ENOBUFS) {
+ m_freem(*mbufp);
+ *mbufp = NULL;
+ }
return (err);
}
@@ -1985,19 +2028,23 @@ nicvf_get_rcv_mbuf(struct nicvf *nic, struct cqe_rx_t *cqe_rx)
/*
* HW by default verifies IP & TCP/UDP/SCTP checksums
*/
-
- /* XXX: Do we need to include IP with options too? */
- if (__predict_true(cqe_rx->l3_type == L3TYPE_IPV4 ||
- cqe_rx->l3_type == L3TYPE_IPV6)) {
+ if (__predict_true(cqe_rx->l3_type == L3TYPE_IPV4)) {
mbuf->m_pkthdr.csum_flags =
(CSUM_IP_CHECKED | CSUM_IP_VALID);
}
- if (cqe_rx->l4_type == L4TYPE_TCP ||
- cqe_rx->l4_type == L4TYPE_UDP ||
- cqe_rx->l4_type == L4TYPE_SCTP) {
+
+ switch (cqe_rx->l4_type) {
+ case L4TYPE_UDP:
+ case L4TYPE_TCP: /* fall through */
mbuf->m_pkthdr.csum_flags |=
(CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
- mbuf->m_pkthdr.csum_data = htons(0xffff);
+ mbuf->m_pkthdr.csum_data = 0xffff;
+ break;
+ case L4TYPE_SCTP:
+ mbuf->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;
+ break;
+ default:
+ break;
}
}
}
diff --git a/sys/dev/vnic/nicvf_queues.h b/sys/dev/vnic/nicvf_queues.h
index 8a27880..0fe8e3b 100644
--- a/sys/dev/vnic/nicvf_queues.h
+++ b/sys/dev/vnic/nicvf_queues.h
@@ -388,7 +388,7 @@ void nicvf_disable_intr(struct nicvf *, int, int);
void nicvf_clear_intr(struct nicvf *, int, int);
int nicvf_is_intr_enabled(struct nicvf *, int, int);
-int nicvf_tx_mbuf_locked(struct snd_queue *, struct mbuf *);
+int nicvf_xmit_locked(struct snd_queue *sq);
/* Register access APIs */
void nicvf_reg_write(struct nicvf *, uint64_t, uint64_t);
diff --git a/sys/dev/vnic/thunder_bgx_fdt.c b/sys/dev/vnic/thunder_bgx_fdt.c
index ec6e68f..b4d77cf 100644
--- a/sys/dev/vnic/thunder_bgx_fdt.c
+++ b/sys/dev/vnic/thunder_bgx_fdt.c
@@ -285,18 +285,9 @@ bgx_fdt_init_phy(struct bgx *bgx)
continue;
}
- if (OF_getencprop(child, "phy-handle", &phy,
- sizeof(phy)) <= 0) {
- if (bootverbose) {
- device_printf(bgx->dev,
- "No phy-handle in PHY node. Skipping...\n");
- }
- continue;
- }
/* Acquire PHY address */
- phy = OF_node_from_xref(phy);
- if (OF_getencprop(phy, "reg", &bgx->lmac[lmac].phyaddr,
+ if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr,
sizeof(bgx->lmac[lmac].phyaddr)) <= 0) {
if (bootverbose) {
device_printf(bgx->dev,
@@ -305,6 +296,15 @@ bgx_fdt_init_phy(struct bgx *bgx)
bgx->lmac[lmac].phyaddr = MII_PHY_ANY;
}
+ if (OF_getencprop(child, "phy-handle", &phy,
+ sizeof(phy)) <= 0) {
+ if (bootverbose) {
+ device_printf(bgx->dev,
+ "No phy-handle in PHY node. Skipping...\n");
+ }
+ continue;
+ }
+ phy = OF_instance_to_package(phy);
/*
* Get PHY interface (MDIO bus) device.
* Driver must be already attached.
@@ -321,7 +321,7 @@ bgx_fdt_init_phy(struct bgx *bgx)
}
/* Get mac address from FDT */
- bgx_fdt_get_macaddr(phy, bgx->lmac[lmac].mac);
+ bgx_fdt_get_macaddr(child, bgx->lmac[lmac].mac);
bgx->lmac[lmac].lmacid = lmac;
lmac++;
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 4661f35..62c9bf3 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -1214,7 +1214,6 @@ vga_init(struct vt_device *vd)
if (vd->vd_softc == NULL)
vd->vd_softc = (void *)&vga_conssoftc;
sc = vd->vd_softc;
- textmode = 0;
if (vd->vd_flags & VDF_DOWNGRADE && vd->vd_video_dev != NULL)
vga_pci_repost(vd->vd_video_dev);
@@ -1229,6 +1228,13 @@ vga_init(struct vt_device *vd)
bus_space_map(sc->vga_reg_tag, VGA_REG_BASE, VGA_REG_SIZE, 0,
&sc->vga_reg_handle);
+ /*
+ * If "hw.vga.textmode" is not set and we're running on hypervisor,
+ * we use text mode by default, this is because when we're on
+ * hypervisor, vt(4) is usually much slower in graphics mode than
+ * in text mode, especially when we're on Hyper-V.
+ */
+ textmode = vm_guest != VM_GUEST_NO;
TUNABLE_INT_FETCH("hw.vga.textmode", &textmode);
if (textmode) {
vd->vd_flags |= VDF_TEXTMODE;
diff --git a/sys/dev/vxge/vxge.c b/sys/dev/vxge/vxge.c
index 9a3cab6..84320f6 100644
--- a/sys/dev/vxge/vxge.c
+++ b/sys/dev/vxge/vxge.c
@@ -996,7 +996,6 @@ vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
vxge_vpath_t *vpath = (vxge_vpath_t *) userdata;
vxge_dev_t *vdev = vpath->vdev;
- struct lro_entry *queued = NULL;
struct lro_ctrl *lro = &vpath->lro;
/* get the interface pointer */
@@ -1083,12 +1082,8 @@ vxge_rx_compl(vxge_hal_vpath_h vpath_handle, vxge_hal_rxd_h rxdh,
&dtr_priv, &t_code) == VXGE_HAL_OK);
/* Flush any outstanding LRO work */
- if (vpath->lro_enable && vpath->lro.lro_cnt) {
- while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
- }
+ if (vpath->lro_enable && vpath->lro.lro_cnt)
+ tcp_lro_flush_all(lro);
return (status);
}
diff --git a/sys/dev/wbwd/wbwd.c b/sys/dev/wbwd/wbwd.c
index 484b5bf..53e9084 100644
--- a/sys/dev/wbwd/wbwd.c
+++ b/sys/dev/wbwd/wbwd.c
@@ -91,8 +91,11 @@ __FBSDID("$FreeBSD$");
#define WB_LDN8_CRF7_FORCE 0x20 /* 1: force timeout (self-clear) */
#define WB_LDN8_CRF7_TS 0x10 /* 0: counting, 1: fired */
#define WB_LDN8_CRF7_IRQS 0x0f /* irq source for watchdog, 2 == SMI */
-#define WB_LDN8_CRF7_CLEAR_MASK \
- (WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_KEYB|WB_LDN8_CRF7_TS|WB_LDN8_CRF7_IRQS)
+
+enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
+ w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg,
+ w83627dhg_p, w83667hg_b, nct6775, nct6776, nct6779, nct6791,
+ nct6792, nct6102 };
struct wb_softc {
device_t dev;
@@ -103,6 +106,10 @@ struct wb_softc {
eventhandler_tag ev_tag;
int (*ext_cfg_enter_f)(struct wb_softc *, u_short);
void (*ext_cfg_exit_f)(struct wb_softc *, u_short);
+ enum chips chip;
+ uint8_t ctl_reg;
+ uint8_t time_reg;
+ uint8_t csr_reg;
int debug_verbose;
/*
@@ -144,46 +151,104 @@ struct winbond_superio_cfg {
};
struct winbond_vendor_device_id {
- uint16_t vendor_id;
uint8_t device_id;
- uint8_t device_rev;
+ enum chips chip;
const char * descr;
} wb_devs[] = {
{
- .vendor_id = 0x5ca3,
.device_id = 0x52,
- .device_rev = 0x17,
- .descr = "Winbond 83627HF/F/HG/G Rev. G",
+ .chip = w83627hf,
+ .descr = "Winbond 83627HF/F/HG/G",
},
{
- .vendor_id = 0x5ca3,
- .device_id = 0x52,
- .device_rev = 0x3a,
- .descr = "Winbond 83627HF/F/HG/G Rev. J",
+ .device_id = 0x59,
+ .chip = w83627s,
+ .descr = "Winbond 83627S",
},
{
- .vendor_id = 0x5ca3,
- .device_id = 0x52,
- .device_rev = 0x41,
- .descr = "Winbond 83627HF/F/HG/G Rev. UD-A",
+ .device_id = 0x60,
+ .chip = w83697hf,
+ .descr = "Winbond 83697HF",
+ },
+ {
+ .device_id = 0x68,
+ .chip = w83697ug,
+ .descr = "Winbond 83697UG",
+ },
+ {
+ .device_id = 0x70,
+ .chip = w83637hf,
+ .descr = "Winbond 83637HF",
+ },
+ {
+ .device_id = 0x82,
+ .chip = w83627thf,
+ .descr = "Winbond 83627THF",
+ },
+ {
+ .device_id = 0x85,
+ .chip = w83687thf,
+ .descr = "Winbond 83687THF",
+ },
+ {
+ .device_id = 0x88,
+ .chip = w83627ehf,
+ .descr = "Winbond 83627EHF",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xa0,
- .device_rev = 0x25,
- .descr = "Winbond 83627DHG IC ver. 5",
+ .chip = w83627dhg,
+ .descr = "Winbond 83627DHG",
+ },
+ {
+ .device_id = 0xa2,
+ .chip = w83627uhg,
+ .descr = "Winbond 83627UHG",
+ },
+ {
+ .device_id = 0xa5,
+ .chip = w83667hg,
+ .descr = "Winbond 83667HG",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xb0,
- .device_rev = 0x73,
- .descr = "Winbond 83627DHG-P",
+ .chip = w83627dhg_p,
+ .descr = "Winbond 83627DHG-P",
+ },
+ {
+ .device_id = 0xb3,
+ .chip = w83667hg_b,
+ .descr = "Winbond 83667HG-B",
+ },
+ {
+ .device_id = 0xb4,
+ .chip = nct6775,
+ .descr = "Nuvoton NCT6775",
},
{
- .vendor_id = 0x5ca3,
.device_id = 0xc3,
- .device_rev = 0x33,
- .descr = "Nuvoton WPCM450RA0BX",
+ .chip = nct6776,
+ .descr = "Nuvoton NCT6776",
+ },
+ {
+ .device_id = 0xc4,
+ .chip = nct6102,
+ .descr = "Nuvoton NCT6102",
+ },
+ {
+ .device_id = 0xc5,
+ .chip = nct6779,
+ .descr = "Nuvoton NCT6779",
+ },
+ {
+ .device_id = 0xc8,
+ .chip = nct6791,
+ .descr = "Nuvoton NCT6791",
+ },
+ {
+ .device_id = 0xc9,
+ .chip = nct6792,
+ .descr = "Nuvoton NCT6792",
},
};
@@ -231,6 +296,22 @@ read_efdr_1(struct wb_softc *sc, u_short baseport)
return (inb(baseport + 1));
}
+static void
+write_reg(struct wb_softc *sc, uint8_t reg, uint8_t value)
+{
+
+ write_efir_1(sc, 0, reg);
+ write_efdr_1(sc, 0, value);
+}
+
+static uint8_t
+read_reg(struct wb_softc *sc, uint8_t reg)
+{
+
+ write_efir_1(sc, 0, reg);
+ return (read_efdr_1(sc, 0));
+}
+
/*
* Return the watchdog related registers as we last read them. This will
* usually not give the current timeout or state on whether the watchdog
@@ -248,9 +329,9 @@ sysctl_wb_debug(SYSCTL_HANDLER_ARGS)
sbuf_new_for_sysctl(&sb, NULL, 64, req);
sbuf_printf(&sb, "LDN8 (GPIO2, Watchdog): ");
- sbuf_printf(&sb, "CRF5 0x%02x ", sc->reg_1);
- sbuf_printf(&sb, "CRF6 0x%02x ", sc->reg_timeout);
- sbuf_printf(&sb, "CRF7 0x%02x", sc->reg_2);
+ sbuf_printf(&sb, "CR%02X 0x%02x ", sc->ctl_reg, sc->reg_1);
+ sbuf_printf(&sb, "CR%02X 0x%02x ", sc->time_reg, sc->reg_timeout);
+ sbuf_printf(&sb, "CR%02X 0x%02x", sc->csr_reg, sc->reg_2);
error = sbuf_finish(&sb);
sbuf_delete(&sb);
@@ -269,23 +350,17 @@ sysctl_wb_debug_current(SYSCTL_HANDLER_ARGS)
sc = arg1;
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
+
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ (*sc->ext_cfg_exit_f)(sc, 0);
return (sysctl_wb_debug(oidp, arg1, arg2, req));
}
@@ -326,10 +401,6 @@ sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
}
#endif
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
@@ -343,16 +414,14 @@ sysctl_wb_force_test_nmi(SYSCTL_HANDLER_ARGS)
#endif
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
/* Force watchdog to fire. */
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
sc->reg_2 |= WB_LDN8_CRF7_FORCE;
+ write_reg(sc, sc->csr_reg, sc->reg_2);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ (*sc->ext_cfg_exit_f)(sc, 0);
return (0);
}
@@ -414,30 +483,36 @@ static int
wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
{
+ if (timeout != 0) {
+ /*
+ * In case an override is set, let it override. It may lead
+ * to strange results as we do not check the input of the sysctl.
+ */
+ if (sc->timeout_override > 0)
+ timeout = sc->timeout_override;
+
+ /* Make sure we support the requested timeout. */
+ if (timeout > 255 * 60)
+ return (EINVAL);
+ }
+
if (sc->debug_verbose)
wb_print_state(sc, "Before watchdog counter (re)load");
- /*
- * Enter extended function mode in case someone else has been
- * poking on the registers. We will not leave it though.
- */
if ((*sc->ext_cfg_enter_f)(sc, 0) != 0)
return (ENXIO);
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog) */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
/* Disable and validate or arm/reset watchdog. */
if (timeout == 0) {
/* Disable watchdog. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- write_efdr_1(sc, 0, 0x00);
+ write_reg(sc, sc->time_reg, 0x00);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ (*sc->ext_cfg_exit_f)(sc, 0);
/* Re-check. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
-
if (sc->reg_timeout != 0x00) {
device_printf(sc->dev, "Failed to disable watchdog: "
"0x%02x.\n", sc->reg_timeout);
@@ -445,20 +520,8 @@ wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
}
} else {
- /*
- * In case an override is set, let it override. It may lead
- * to strange results as we do not check the input of the sysctl.
- */
- if (sc->timeout_override > 0)
- timeout = sc->timeout_override;
-
- /* Make sure we support the requested timeout. */
- if (timeout > 255 * 60)
- return (EINVAL);
-
/* Read current scaling factor. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
if (timeout > 255) {
/* Set scaling factor to 60s. */
@@ -473,21 +536,18 @@ wb_set_watchdog(struct wb_softc *sc, unsigned int timeout)
}
/* In case we fired before we need to clear to fire again. */
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
if (sc->reg_2 & WB_LDN8_CRF7_TS) {
sc->reg_2 &= ~WB_LDN8_CRF7_TS;
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ write_reg(sc, sc->csr_reg, sc->reg_2);
}
/* Write back scaling factor. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- write_efdr_1(sc, 0, sc->reg_1);
+ write_reg(sc, sc->ctl_reg, sc->reg_1);
/* Set timer and arm/reset the watchdog. */
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- write_efdr_1(sc, 0, sc->reg_timeout);
+ write_reg(sc, sc->time_reg, sc->reg_timeout);
+ (*sc->ext_cfg_exit_f)(sc, 0);
}
if (sc->debug_verbose)
@@ -556,6 +616,7 @@ wb_probe_enable(device_t dev, int probe)
struct wb_softc *sc;
int error, found, i, j;
uint8_t dev_id, dev_rev, cr26;
+ char buf[128];
if (dev == NULL)
sc = NULL;
@@ -566,6 +627,7 @@ wb_probe_enable(device_t dev, int probe)
}
error = ENXIO;
+ found = 0;
for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) {
if (sc != NULL) {
@@ -578,7 +640,6 @@ wb_probe_enable(device_t dev, int probe)
sc->bsh = rman_get_bushandle(sc->portres);
}
- found = 0;
error = (*probe_addrs[i].ext_cfg_enter_f)(sc, probe_addrs[i].efer);
if (error != 0)
goto cleanup;
@@ -591,6 +652,9 @@ wb_probe_enable(device_t dev, int probe)
write_efir_1(sc, probe_addrs[i].efer, WB_CR26);
cr26 = read_efdr_1(sc, probe_addrs[i].efer);
+ if (dev_id == 0xff && dev_rev == 0xff)
+ goto cleanup;
+
/* HEFRAS of 0 means EFER at 0x2e, 1 means EFER at 0x4e. */
if (((cr26 & 0x40) == 0x00 && probe_addrs[i].efer != 0x2e) ||
((cr26 & 0x40) == 0x40 && probe_addrs[i].efer != 0x4e)) {
@@ -602,36 +666,30 @@ wb_probe_enable(device_t dev, int probe)
goto cleanup;
}
- if (dev_id == 0xff && dev_rev == 0xff)
- goto cleanup;
-
for (j = 0; j < sizeof(wb_devs) / sizeof(*wb_devs); j++) {
- if (wb_devs[j].device_id == dev_id &&
- wb_devs[j].device_rev == dev_rev) {
- if (probe && dev != NULL)
- device_set_desc(dev, wb_devs[j].descr);
- found++;
+ if (wb_devs[j].device_id == dev_id) {
+ found = 1;
break;
}
}
- if (!found) {
- if (probe && dev != NULL) {
- device_set_desc(dev, "Unknown Winbond/Nuvoton model");
- device_printf(dev, "DevID 0x%02x DevRev 0x%02x, "
- "please report this.\n", dev_id, dev_rev);
- }
- found++;
+ if (probe && dev != NULL) {
+ snprintf(buf, sizeof(buf),
+ "%s (0x%02x/0x%02x) Watchdog Timer",
+ found ? wb_devs[j].descr :
+ "Unknown Winbond/Nuvoton", dev_id, dev_rev);
+ device_set_desc_copy(dev, buf);
+ }
+
+ /* If this is hinted attach, try to guess the model. */
+ if (dev != NULL && !found) {
+ found = 1;
+ j = 0;
}
- if (probe && found && bootverbose && dev != NULL)
- device_printf(dev, "%s EFER 0x%02x ID 0x%02x Rev 0x%02x"
- " CR26 0x%02x (probing)\n", device_get_desc(dev),
- probe_addrs[i].efer, dev_id, dev_rev, cr26);
cleanup:
if (probe || !found) {
(*probe_addrs[i].ext_cfg_exit_f)(sc, probe_addrs[i].efer);
-
if (sc != NULL)
(void) bus_release_resource(dev, SYS_RES_IOPORT,
sc->rid, sc->portres);
@@ -646,9 +704,21 @@ cleanup:
if (sc != NULL) {
sc->ext_cfg_enter_f = probe_addrs[i].ext_cfg_enter_f;
sc->ext_cfg_exit_f = probe_addrs[i].ext_cfg_exit_f;
+ sc->chip = wb_devs[j].chip;
+ sc->ctl_reg = 0xf5;
+ sc->time_reg = 0xf6;
+ sc->csr_reg = 0xf7;
+ if (sc->chip == w83697hf ||
+ sc->chip == w83697ug) {
+ sc->ctl_reg = 0xf3;
+ sc->time_reg = 0xf4;
+ } else if (sc->chip == nct6102) {
+ sc->ctl_reg = 0xf0;
+ sc->time_reg = 0xf1;
+ sc->csr_reg = 0xf2;
+ }
}
- error = BUS_PROBE_DEFAULT;
- break;
+ return (BUS_PROBE_SPECIFIC);
} else
error = ENXIO;
}
@@ -659,15 +729,10 @@ cleanup:
static void
wb_identify(driver_t *driver, device_t parent)
{
- device_t dev;
- if ((dev = device_find_child(parent, driver->name, 0)) == NULL) {
- if (wb_probe_enable(dev, 1) != BUS_PROBE_DEFAULT) {
- if (bootverbose)
- device_printf(dev, "can not find compatible Winbond chip.\n");
- } else
- dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);
- return;
+ if (device_find_child(parent, driver->name, 0) == NULL) {
+ if (wb_probe_enable(NULL, 1) <= 0)
+ BUS_ADD_CHILD(parent, 0, driver->name, 0);
}
}
@@ -690,6 +755,7 @@ wb_attach(device_t dev)
struct sysctl_oid *soid;
unsigned long timeout;
int error;
+ uint8_t t;
error = wb_probe_enable(dev, 0);
if (error > 0)
@@ -700,37 +766,95 @@ wb_attach(device_t dev)
("%s: successfull probe result but not setup correctly", __func__));
/* Watchdog is configured as part of LDN 8 (GPIO Port2, Watchdog). */
- write_efir_1(sc, 0, WB_LDN_REG);
- write_efdr_1(sc, 0, WB_LDN_REG_LDN8);
-
- /* Make sure LDN8 is enabled (Do we need to? Also affects GPIO). */
- write_efir_1(sc, 0, WB_LDN8_CR30);
- write_efdr_1(sc, 0, WB_LDN8_CR30_ACTIVE);
+ write_reg(sc, WB_LDN_REG, WB_LDN_REG_LDN8);
+
+ /* Make sure WDT is enabled. */
+ write_reg(sc, WB_LDN8_CR30,
+ read_reg(sc, WB_LDN8_CR30) | WB_LDN8_CR30_ACTIVE);
+
+ switch (sc->chip) {
+ case w83627hf:
+ case w83627s:
+ t = read_reg(sc, 0x2B) & ~0x10;
+ write_reg(sc, 0x2B, t); /* set GPIO24 to WDT0 */
+ break;
+ case w83697hf:
+ /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
+ t = read_reg(sc, 0x29) & ~0x60;
+ t |= 0x20;
+ write_reg(sc, 0x29, t);
+ break;
+ case w83697ug:
+ /* Set pin 118 to WDTO# mode */
+ t = read_reg(sc, 0x2b) & ~0x04;
+ write_reg(sc, 0x2b, t);
+ break;
+ case w83627thf:
+ t = (read_reg(sc, 0x2B) & ~0x08) | 0x04;
+ write_reg(sc, 0x2B, t); /* set GPIO3 to WDT0 */
+ break;
+ case w83627dhg:
+ case w83627dhg_p:
+ t = read_reg(sc, 0x2D) & ~0x01; /* PIN77 -> WDT0# */
+ write_reg(sc, 0x2D, t); /* set GPIO5 to WDT0 */
+ t = read_reg(sc, sc->ctl_reg);
+ t |= 0x02; /* enable the WDTO# output low pulse
+ * to the KBRST# pin */
+ write_reg(sc, sc->ctl_reg, t);
+ break;
+ case w83637hf:
+ break;
+ case w83687thf:
+ t = read_reg(sc, 0x2C) & ~0x80; /* PIN47 -> WDT0# */
+ write_reg(sc, 0x2C, t);
+ break;
+ case w83627ehf:
+ case w83627uhg:
+ case w83667hg:
+ case w83667hg_b:
+ case nct6775:
+ case nct6776:
+ case nct6779:
+ case nct6791:
+ case nct6792:
+ case nct6102:
+ /*
+ * These chips have a fixed WDTO# output pin (W83627UHG),
+ * or support more than one WDTO# output pin.
+ * Don't touch its configuration, and hope the BIOS
+ * does the right thing.
+ */
+ t = read_reg(sc, sc->ctl_reg);
+ t |= 0x02; /* enable the WDTO# output low pulse
+ * to the KBRST# pin */
+ write_reg(sc, sc->ctl_reg, t);
+ break;
+ default:
+ break;
+ }
/* Read the current watchdog configuration. */
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- sc->reg_1 = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF6);
- sc->reg_timeout = read_efdr_1(sc, 0);
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- sc->reg_2 = read_efdr_1(sc, 0);
+ sc->reg_1 = read_reg(sc, sc->ctl_reg);
+ sc->reg_timeout = read_reg(sc, sc->time_reg);
+ sc->reg_2 = read_reg(sc, sc->csr_reg);
/* Print current state if bootverbose or watchdog already enabled. */
if (bootverbose || (sc->reg_timeout > 0x00))
wb_print_state(sc, "Before watchdog attach");
+ sc->reg_1 &= ~WB_LDN8_CRF5_KEYB_P20;
+ sc->reg_1 |= WB_LDN8_CRF5_KBRST;
+ write_reg(sc, sc->ctl_reg, sc->reg_1);
+
/*
- * Clear a previous watchdog timeout event (if (still) set).
- * Disable all all interrupt reset sources (defaults).
+ * Clear a previous watchdog timeout event (if still set).
+ * Disable timer reset on mouse interrupts. Leave reset on keyboard,
+ * since one of my boards is getting stuck in reboot without it.
*/
- sc->reg_1 &= ~(WB_LDN8_CRF5_KEYB_P20);
- sc->reg_1 |= WB_LDN8_CRF5_KBRST;
- write_efir_1(sc, 0, WB_LDN8_CRF5);
- write_efdr_1(sc, 0, sc->reg_1);
+ sc->reg_2 &= ~(WB_LDN8_CRF7_MOUSE|WB_LDN8_CRF7_TS);
+ write_reg(sc, sc->csr_reg, sc->reg_2);
- sc->reg_2 &= ~WB_LDN8_CRF7_CLEAR_MASK;
- write_efir_1(sc, 0, WB_LDN8_CRF7);
- write_efdr_1(sc, 0, sc->reg_2);
+ (*sc->ext_cfg_exit_f)(sc, 0);
/* Read global timeout override tunable, Add per device sysctls. */
if (TUNABLE_ULONG_FETCH("hw.wbwd.timeout_override", &timeout)) {
diff --git a/sys/dev/wl/if_wl.c b/sys/dev/wl/if_wl.c
index 7146a25..6414d33 100644
--- a/sys/dev/wl/if_wl.c
+++ b/sys/dev/wl/if_wl.c
@@ -495,7 +495,7 @@ wlattach(device_t device)
}
#ifdef WLDEBUG
- printf("wlattach: base %lx, unit %d\n", rman_get_start(sc->res_ioport),
+ printf("wlattach: base %jx, unit %d\n", rman_get_start(sc->res_ioport),
device_get_unit(device));
#endif
diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c
index 824f75b..e435096 100644
--- a/sys/dev/wpi/if_wpi.c
+++ b/sys/dev/wpi/if_wpi.c
@@ -284,7 +284,6 @@ static void wpi_scan_end(struct ieee80211com *);
static void wpi_set_channel(struct ieee80211com *);
static void wpi_scan_curchan(struct ieee80211_scan_state *, unsigned long);
static void wpi_scan_mindwell(struct ieee80211_scan_state *);
-static void wpi_hw_reset(void *, int);
static device_method_t wpi_methods[] = {
/* Device interface */
@@ -531,18 +530,9 @@ wpi_attach(device_t dev)
callout_init_mtx(&sc->scan_timeout, &sc->rxon_mtx, 0);
callout_init_mtx(&sc->tx_timeout, &sc->txq_state_mtx, 0);
callout_init_mtx(&sc->watchdog_rfkill, &sc->sc_mtx, 0);
- TASK_INIT(&sc->sc_reinittask, 0, wpi_hw_reset, sc);
TASK_INIT(&sc->sc_radiooff_task, 0, wpi_radio_off, sc);
TASK_INIT(&sc->sc_radioon_task, 0, wpi_radio_on, sc);
- sc->sc_tq = taskqueue_create("wpi_taskq", M_WAITOK,
- taskqueue_thread_enqueue, &sc->sc_tq);
- error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "wpi_taskq");
- if (error != 0) {
- device_printf(dev, "can't start threads, error %d\n", error);
- goto fail;
- }
-
wpi_sysctlattach(sc);
/*
@@ -695,14 +685,10 @@ wpi_detach(device_t dev)
if (ic->ic_vap_create == wpi_vap_create) {
ieee80211_draintask(ic, &sc->sc_radioon_task);
+ ieee80211_draintask(ic, &sc->sc_radiooff_task);
wpi_stop(sc);
- if (sc->sc_tq != NULL) {
- taskqueue_drain_all(sc->sc_tq);
- taskqueue_free(sc->sc_tq);
- }
-
callout_drain(&sc->watchdog_rfkill);
callout_drain(&sc->tx_timeout);
callout_drain(&sc->scan_timeout);
@@ -1517,7 +1503,8 @@ wpi_find_eeprom_channel(struct wpi_softc *sc, struct ieee80211_channel *c)
for (j = 0; j < WPI_CHAN_BANDS_COUNT; j++)
for (i = 0; i < wpi_bands[j].nchan; i++)
- if (wpi_bands[j].chan[i] == c->ic_ieee)
+ if (wpi_bands[j].chan[i] == c->ic_ieee &&
+ ((j == 0) ^ IEEE80211_IS_CHAN_A(c)) == 1)
return &sc->eeprom_channels[j][i];
return NULL;
@@ -2332,7 +2319,7 @@ wpi_notif_intr(struct wpi_softc *sc)
WPI_NT_LOCK(sc);
wpi_clear_node_table(sc);
WPI_NT_UNLOCK(sc);
- taskqueue_enqueue(sc->sc_tq,
+ ieee80211_runtask(ic,
&sc->sc_radiooff_task);
return;
}
@@ -2569,6 +2556,8 @@ wpi_intr(void *arg)
WPI_WRITE(sc, WPI_FH_INT, r2);
if (__predict_false(r1 & (WPI_INT_SW_ERR | WPI_INT_HW_ERR))) {
+ struct ieee80211com *ic = &sc->sc_ic;
+
device_printf(sc->sc_dev, "fatal firmware error\n");
#ifdef WPI_DEBUG
wpi_debug_registers(sc);
@@ -2577,7 +2566,7 @@ wpi_intr(void *arg)
DPRINTF(sc, WPI_DEBUG_HW,
"(%s)\n", (r1 & WPI_INT_SW_ERR) ? "(Software Error)" :
"(Hardware Error)");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
goto end;
}
@@ -3200,7 +3189,7 @@ wpi_scan_timeout(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
ic_printf(ic, "scan timeout\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
}
static void
@@ -3210,7 +3199,7 @@ wpi_tx_timeout(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
ic_printf(ic, "device timeout\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_reinittask);
+ ieee80211_restart_all(ic);
}
static void
@@ -3227,8 +3216,10 @@ wpi_parent(struct ieee80211com *ic)
ieee80211_notify_radio(ic, 0);
ieee80211_stop(vap);
}
- } else
+ } else {
+ ieee80211_notify_radio(ic, 0);
wpi_stop(sc);
+ }
}
/*
@@ -5654,23 +5645,3 @@ wpi_scan_mindwell(struct ieee80211_scan_state *ss)
{
/* NB: don't try to abort scan; wait for firmware to finish */
}
-
-static void
-wpi_hw_reset(void *arg, int pending)
-{
- struct wpi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-
- DPRINTF(sc, WPI_DEBUG_TRACE, TRACE_STR_DOING, __func__);
-
- ieee80211_notify_radio(ic, 0);
- if (vap != NULL && (ic->ic_flags & IEEE80211_F_SCAN))
- ieee80211_cancel_scan(vap);
-
- wpi_stop(sc);
- if (vap != NULL) {
- ieee80211_stop(vap);
- ieee80211_init(vap);
- }
-}
diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h
index 1957740..437f1d8 100644
--- a/sys/dev/wpi/if_wpivar.h
+++ b/sys/dev/wpi/if_wpivar.h
@@ -228,13 +228,9 @@ struct wpi_softc {
struct wpi_dma_info fw_dma;
/* Tasks used by the driver. */
- struct task sc_reinittask;
struct task sc_radiooff_task;
struct task sc_radioon_task;
- /* Taskqueue */
- struct taskqueue *sc_tq;
-
/* Eeprom info. */
uint8_t cap;
uint16_t rev;
diff --git a/sys/dev/xe/if_xe.c b/sys/dev/xe/if_xe.c
index d6ccae9..e18af8c 100644
--- a/sys/dev/xe/if_xe.c
+++ b/sys/dev/xe/if_xe.c
@@ -1984,7 +1984,7 @@ xe_activate(device_t dev)
sc->port_res);
start = (rman_get_start(sc->port_res) + 15) & ~0xf;
} while (1);
- DEVPRINTF(1, (dev, "RealPort port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "RealPort port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
} else if (sc->ce2) {
@@ -2024,7 +2024,7 @@ xe_activate(device_t dev)
sc->port_res);
sc->port_res = NULL;
}
- DEVPRINTF(1, (dev, "CEM2/CEM3 port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "CEM2/CEM3 port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
}
diff --git a/sys/dev/xe/if_xe_pccard.c b/sys/dev/xe/if_xe_pccard.c
index bbe6253..fb2cff6 100644
--- a/sys/dev/xe/if_xe_pccard.c
+++ b/sys/dev/xe/if_xe_pccard.c
@@ -140,7 +140,7 @@ xe_cemfix(device_t dev)
DEVPRINTF(2, (dev, "cemfix\n"));
- DEVPRINTF(1, (dev, "CEM I/O port 0x%0lx, size 0x%0lx\n",
+ DEVPRINTF(1, (dev, "CEM I/O port 0x%0jx, size 0x%0jx\n",
bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)));
diff --git a/sys/dev/xen/blkfront/blkfront.c b/sys/dev/xen/blkfront/blkfront.c
index d35e04a..ef36b94 100644
--- a/sys/dev/xen/blkfront/blkfront.c
+++ b/sys/dev/xen/blkfront/blkfront.c
@@ -855,6 +855,20 @@ xbd_feature_string(struct xbd_softc *sc, char *features, size_t len)
feature_cnt++;
}
+ if ((sc->xbd_flags & XBDF_DISCARD) != 0) {
+ if (feature_cnt != 0)
+ sbuf_printf(&sb, ", ");
+ sbuf_printf(&sb, "discard");
+ feature_cnt++;
+ }
+
+ if ((sc->xbd_flags & XBDF_PERSISTENT) != 0) {
+ if (feature_cnt != 0)
+ sbuf_printf(&sb, ", ");
+ sbuf_printf(&sb, "persistent_grants");
+ feature_cnt++;
+ }
+
(void) sbuf_finish(&sb);
return (sbuf_len(&sb));
}
@@ -985,7 +999,8 @@ xbd_vdevice_to_unit(uint32_t vdevice, int *unit, const char **name)
int
xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
- int vdevice, uint16_t vdisk_info, unsigned long sector_size)
+ int vdevice, uint16_t vdisk_info, unsigned long sector_size,
+ unsigned long phys_sector_size)
{
char features[80];
int unit, error = 0;
@@ -1013,6 +1028,8 @@ xbd_instance_create(struct xbd_softc *sc, blkif_sector_t sectors,
sc->xbd_disk->d_name = name;
sc->xbd_disk->d_drv1 = sc;
sc->xbd_disk->d_sectorsize = sector_size;
+ sc->xbd_disk->d_stripesize = phys_sector_size;
+ sc->xbd_disk->d_stripeoffset = 0;
sc->xbd_disk->d_mediasize = sectors * sector_size;
sc->xbd_disk->d_maxsize = sc->xbd_max_request_size;
@@ -1206,7 +1223,7 @@ static void
xbd_connect(struct xbd_softc *sc)
{
device_t dev = sc->xbd_dev;
- unsigned long sectors, sector_size;
+ unsigned long sectors, sector_size, phys_sector_size;
unsigned int binfo;
int err, feature_barrier, feature_flush;
int i, j;
@@ -1229,6 +1246,11 @@ xbd_connect(struct xbd_softc *sc)
return;
}
err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
+ "physical-sector-size", "%lu", &phys_sector_size,
+ NULL);
+ if (err || phys_sector_size <= sector_size)
+ phys_sector_size = 0;
+ err = xs_gather(XST_NIL, xenbus_get_otherend_path(dev),
"feature-barrier", "%lu", &feature_barrier,
NULL);
if (err == 0 && feature_barrier != 0)
@@ -1330,7 +1352,7 @@ xbd_connect(struct xbd_softc *sc)
bus_print_child_footer(device_get_parent(dev), dev);
xbd_instance_create(sc, sectors, sc->xbd_vdevice, binfo,
- sector_size);
+ sector_size, phys_sector_size);
}
(void)xenbus_set_state(dev, XenbusStateConnected);
diff --git a/sys/dev/xen/blkfront/block.h b/sys/dev/xen/blkfront/block.h
index 28c6ff2..ddb4088 100644
--- a/sys/dev/xen/blkfront/block.h
+++ b/sys/dev/xen/blkfront/block.h
@@ -159,10 +159,12 @@ typedef enum {
XBDF_READY = 1 << 3, /* Is ready */
XBDF_CM_SHORTAGE = 1 << 4, /* Free cm resource shortage active. */
XBDF_GNT_SHORTAGE = 1 << 5, /* Grant ref resource shortage active */
- XBDF_WAIT_IDLE = 1 << 6 /*
+ XBDF_WAIT_IDLE = 1 << 6, /*
* No new work until oustanding work
* completes.
*/
+ XBDF_DISCARD = 1 << 7, /* backend supports discard */
+ XBDF_PERSISTENT = 1 << 8 /* backend supports persistent grants */
} xbd_flag_t;
/*
@@ -200,7 +202,8 @@ struct xbd_softc {
};
int xbd_instance_create(struct xbd_softc *, blkif_sector_t sectors, int device,
- uint16_t vdisk_info, unsigned long sector_size);
+ uint16_t vdisk_info, unsigned long sector_size,
+ unsigned long phys_sector_size);
static inline void
xbd_added_qentry(struct xbd_softc *sc, xbd_q_index_t index)
diff --git a/sys/dev/xen/netfront/netfront.c b/sys/dev/xen/netfront/netfront.c
index 22ca81c..7add70a 100644
--- a/sys/dev/xen/netfront/netfront.c
+++ b/sys/dev/xen/netfront/netfront.c
@@ -1202,7 +1202,6 @@ xn_rxeof(struct netfront_rxq *rxq)
struct netfront_info *np = rxq->info;
#if (defined(INET) || defined(INET6))
struct lro_ctrl *lro = &rxq->lro;
- struct lro_entry *queued;
#endif
struct netfront_rx_info rinfo;
struct netif_rx_response *rx = &rinfo.rx;
@@ -1296,11 +1295,7 @@ xn_rxeof(struct netfront_rxq *rxq)
/*
* Flush any outstanding LRO work
*/
- while (!SLIST_EMPTY(&lro->lro_active)) {
- queued = SLIST_FIRST(&lro->lro_active);
- SLIST_REMOVE_HEAD(&lro->lro_active, next);
- tcp_lro_flush(lro, queued);
- }
+ tcp_lro_flush_all(lro);
#endif
xn_alloc_rx_buffers(rxq);
OpenPOWER on IntegriCloud