diff options
author | gjb <gjb@FreeBSD.org> | 2016-04-04 23:55:32 +0000 |
---|---|---|
committer | gjb <gjb@FreeBSD.org> | 2016-04-04 23:55:32 +0000 |
commit | 1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f (patch) | |
tree | a027fe5a27446f32854d6a07b34b5f2a992bf283 /sys/dev | |
parent | 3669a0dced7e344be71d234ffc3a71530ef0ae08 (diff) | |
parent | 589cedfe0cde2b49d5f47fc240de37c8bf307abd (diff) | |
download | FreeBSD-src-1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f.zip FreeBSD-src-1dc4c40e3b35564cb2e787ad968e6b4a9fb7eb0f.tar.gz |
MFH
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/dev')
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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); - 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, ®); + 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, ®node_topo_lock, "Regulator topology lock"); + +#define REG_TOPO_SLOCK() sx_slock(®node_topo_lock) +#define REG_TOPO_XLOCK() sx_xlock(®node_topo_lock) +#define REG_TOPO_UNLOCK() sx_unlock(®node_topo_lock) +#define REG_TOPO_ASSERT() sx_assert(®node_topo_lock, SA_LOCKED) +#define REG_TOPO_XASSERT() sx_assert(®node_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, ®node_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, ®node_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(®node->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(®node->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(®node_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 (®node->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, ®node->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(®node->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(®node->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, ®node_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(®, 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, ®, 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); |