diff options
Diffstat (limited to 'sys')
60 files changed, 2169 insertions, 1462 deletions
diff --git a/sys/conf/files b/sys/conf/files index f6456a7..ec77e97 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2258,6 +2258,7 @@ dev/random/hash.c optional random dev/random/rwfile.c optional random dev/rc/rc.c optional rc dev/re/if_re.c optional re +dev/rl/if_rl.c optional rl pci dev/rndtest/rndtest.c optional rndtest dev/rp/rp.c optional rp dev/rp/rp_isa.c optional rp isa @@ -3552,6 +3553,7 @@ netinet/sctp_usrreq.c optional inet sctp | inet6 sctp netinet/sctputil.c optional inet sctp | inet6 sctp netinet/siftr.c optional inet siftr alq | inet6 siftr alq netinet/tcp_debug.c optional tcpdebug +netinet/tcp_fastopen.c optional inet tcp_rfc7413 | inet6 tcp_rfc7413 netinet/tcp_hostcache.c optional inet | inet6 netinet/tcp_input.c optional inet | inet6 netinet/tcp_lro.c optional inet | inet6 @@ -4046,7 +4048,6 @@ opencrypto/xform.c optional crypto pci/alpm.c optional alpm pci pci/amdpm.c optional amdpm pci | nfpm pci pci/amdsmb.c optional amdsmb pci -pci/if_rl.c optional rl pci pci/intpm.c optional intpm pci pci/ncr.c optional ncr pci \ compile-with "${NORMAL_C} -Wno-unused" diff --git a/sys/conf/files.sparc64 b/sys/conf/files.sparc64 index 5775d9b..9fbc226 100644 --- a/sys/conf/files.sparc64 +++ b/sys/conf/files.sparc64 @@ -81,6 +81,7 @@ sparc64/isa/isa_dma.c optional isa sparc64/isa/ofw_isa.c optional ebus | isa sparc64/pci/apb.c optional pci sparc64/pci/fire.c optional pci +sparc64/pci/ofw_pci.c optional pci sparc64/pci/ofw_pcib.c optional pci sparc64/pci/ofw_pcib_subr.c optional pci sparc64/pci/ofw_pcibus.c optional pci diff --git a/sys/conf/options b/sys/conf/options index 96253be..d8dffe9 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -444,6 +444,8 @@ SLIP_IFF_OPTS opt_slip.h TCPDEBUG SIFTR TCP_OFFLOAD opt_inet.h # Enable code to dispatch TCP offloading +TCP_RFC7413 opt_inet.h +TCP_RFC7413_MAX_KEYS opt_inet.h TCP_SIGNATURE opt_inet.h VLAN_ARRAY opt_vlan.h XBONEHACK diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 6c93810..6ca938a 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -5123,7 +5123,7 @@ ipf_nat_out(fin, nat, natadd, nflags) ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0); } #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ - defined(linux) || defined(BRIDGE_IPF) + defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD__) else { /* * Strictly speaking, this isn't necessary on BSD @@ -5235,7 +5235,7 @@ ipf_nat_out(fin, nat, natadd, nflags) uh->uh_ulen += fin->fin_plen; uh->uh_ulen = htons(uh->uh_ulen); #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ - defined(linux) || defined(BRIDGE_IPF) + defined(linux) || defined(BRIDGE_IPF) || defined(__FreeBSD) ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0); #endif diff --git a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c index d13ece5..d17d696 100644 --- a/sys/dev/hyperv/vmbus/hv_channel_mgmt.c +++ b/sys/dev/hyperv/vmbus/hv_channel_mgmt.c @@ -53,8 +53,6 @@ static void vmbus_channel_on_gpadl_torndown(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_on_offers_delivered(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_on_version_response(hv_vmbus_channel_msg_header* hdr); static void vmbus_channel_process_offer(void *context); -struct hv_vmbus_channel* - vmbus_select_outgoing_channel(struct hv_vmbus_channel *promary); /** * Channel message dispatch table diff --git a/sys/dev/if_ndis/if_ndis_pci.c b/sys/dev/if_ndis/if_ndis_pci.c index 8ed6c5a..326e3de 100644 --- a/sys/dev/if_ndis/if_ndis_pci.c +++ b/sys/dev/if_ndis/if_ndis_pci.c @@ -295,8 +295,7 @@ ndis_attach_pci(dev) BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ - BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ - NDIS_NSEG_NEW, /* nsegments */ + DFLTPHYS, NDIS_NSEG_NEW,/* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ BUS_DMA_ALLOCNOW, /* flags */ NULL, NULL, /* lockfunc, lockarg */ diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 18c41e9..d394011 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -277,6 +277,9 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) case ISP_HA_FC_2500: btype = "2532"; break; + case ISP_HA_FC_2600: + btype = "2031"; + break; default: break; } @@ -655,8 +658,10 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) ISP_WRITE(isp, isp->isp_respinrp, 0); ISP_WRITE(isp, isp->isp_respoutrp, 0); if (IS_24XX(isp)) { - ISP_WRITE(isp, BIU2400_PRI_REQINP, 0); - ISP_WRITE(isp, BIU2400_PRI_REQOUTP, 0); + if (!IS_26XX(isp)) { + ISP_WRITE(isp, BIU2400_PRI_REQINP, 0); + ISP_WRITE(isp, BIU2400_PRI_REQOUTP, 0); + } ISP_WRITE(isp, BIU2400_ATIO_RSPINP, 0); ISP_WRITE(isp, BIU2400_ATIO_RSPOUTP, 0); } @@ -761,6 +766,7 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) code_org = ISP_CODE_ORG; } + isp->isp_loaded_fw = 0; if (dodnld && IS_24XX(isp)) { const uint32_t *ptr = isp->isp_mdvec->dv_ispfw; int wordload; @@ -956,8 +962,17 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) ISP_RESET0(isp); return; } + } else if (IS_26XX(isp)) { + MBSINIT(&mbs, MBOX_LOAD_FLASH_FIRMWARE, MBLOGALL, 5000000); + mbs.ibitm = 0x01; + mbs.obitm = 0x07; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "Flash F/W load failed"); + ISP_RESET0(isp); + return; + } } else { - isp->isp_loaded_fw = 0; isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download"); } @@ -966,7 +981,6 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) */ if (isp->isp_loaded_fw) { MBSINIT(&mbs, MBOX_VERIFY_CHECKSUM, MBLOGNONE, 0); - mbs.param[0] = MBOX_VERIFY_CHECKSUM; if (IS_24XX(isp)) { mbs.param[1] = code_org >> 16; mbs.param[2] = code_org; @@ -998,9 +1012,6 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults) } else { mbs.param[3] = 1; } - if (IS_25XX(isp)) { - mbs.ibits |= 0x10; - } } else if (IS_2322(isp)) { mbs.param[1] = code_org; if (isp->isp_loaded_fw) { @@ -1861,16 +1872,16 @@ isp_fibre_init(ispsoftc_t *isp) icbp->icb_idelaytimer = 10; } icbp->icb_zfwoptions = fcp->isp_zfwoptions; - if (isp->isp_confopts & ISP_CFG_ONEGB) { + if (isp->isp_confopts & ISP_CFG_1GB) { icbp->icb_zfwoptions &= ~ICBZOPT_RATE_MASK; - icbp->icb_zfwoptions |= ICBZOPT_RATE_ONEGB; - } else if (isp->isp_confopts & ISP_CFG_TWOGB) { + icbp->icb_zfwoptions |= ICBZOPT_RATE_1GB; + } else if (isp->isp_confopts & ISP_CFG_2GB) { icbp->icb_zfwoptions &= ~ICBZOPT_RATE_MASK; - icbp->icb_zfwoptions |= ICBZOPT_RATE_TWOGB; + icbp->icb_zfwoptions |= ICBZOPT_RATE_2GB; } else { switch (icbp->icb_zfwoptions & ICBZOPT_RATE_MASK) { - case ICBZOPT_RATE_ONEGB: - case ICBZOPT_RATE_TWOGB: + case ICBZOPT_RATE_1GB: + case ICBZOPT_RATE_2GB: case ICBZOPT_RATE_AUTO: break; default: @@ -2122,18 +2133,26 @@ isp_fibre_init_2400(ispsoftc_t *isp) break; } + if (IS_26XX(isp)) { + /* We don't support MSI-X yet, so set this unconditionally. */ + icbp->icb_fwoptions2 |= ICB2400_OPT2_ENA_IHR; + icbp->icb_fwoptions2 |= ICB2400_OPT2_ENA_IHA; + } + if ((icbp->icb_fwoptions3 & ICB2400_OPT3_RSPSZ_MASK) == 0) { icbp->icb_fwoptions3 |= ICB2400_OPT3_RSPSZ_24; } icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO; - if (isp->isp_confopts & ISP_CFG_ONEGB) { - icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_ONEGB; - } else if (isp->isp_confopts & ISP_CFG_TWOGB) { - icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_TWOGB; - } else if (isp->isp_confopts & ISP_CFG_FOURGB) { - icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_FOURGB; - } else if (IS_25XX(isp) && (isp->isp_confopts & ISP_CFG_EIGHTGB)) { - icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_EIGHTGB; + if (isp->isp_confopts & ISP_CFG_1GB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_1GB; + } else if (isp->isp_confopts & ISP_CFG_2GB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_2GB; + } else if (isp->isp_confopts & ISP_CFG_4GB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_4GB; + } else if (isp->isp_confopts & ISP_CFG_8GB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_8GB; + } else if (isp->isp_confopts & ISP_CFG_16GB) { + icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_16GB; } else { icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO; } @@ -6828,7 +6847,7 @@ static const char *scsi_mbcmd_names[] = { static const uint32_t mbpfc[] = { ISP_FC_OPMAP(0x01, 0x01), /* 0x00: MBOX_NO_OP */ ISP_FC_OPMAP(0x1f, 0x01), /* 0x01: MBOX_LOAD_RAM */ - ISP_FC_OPMAP(0x0f, 0x01), /* 0x02: MBOX_EXEC_FIRMWARE */ + ISP_FC_OPMAP_HALF(0x07, 0xff, 0x00, 0x03), /* 0x02: MBOX_EXEC_FIRMWARE */ ISP_FC_OPMAP(0xdf, 0x01), /* 0x03: MBOX_DUMP_RAM */ ISP_FC_OPMAP(0x07, 0x07), /* 0x04: MBOX_WRITE_RAM_WORD */ ISP_FC_OPMAP(0x03, 0x07), /* 0x05: MBOX_READ_RAM_WORD */ @@ -7602,6 +7621,8 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan) fcp->isp_wwnn_nvram = DEFAULT_NODEWWN(isp, chan); fcp->isp_wwpn_nvram = DEFAULT_PORTWWN(isp, chan); fcp->isp_fwoptions = 0; + fcp->isp_xfwoptions = 0; + fcp->isp_zfwoptions = 0; fcp->isp_lasthdl = NIL_HANDLE; if (IS_24XX(isp)) { @@ -7899,7 +7920,9 @@ isp_rd_2400_nvram(ispsoftc_t *isp, uint32_t addr, uint32_t *rp) uint32_t base = 0x7ffe0000; uint32_t tmp = 0; - if (IS_25XX(isp)) { + if (IS_26XX(isp)) { + base = 0x7fe7c000; /* XXX: Observation, may be wrong. */ + } else if (IS_25XX(isp)) { base = 0x7ff00000 | 0x48000; } ISP_WRITE(isp, BIU2400_FLASH_ADDR, base | addr); diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 73741eb..c533d69 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -4550,91 +4550,52 @@ isp_uninit(ispsoftc_t *isp) ISP_DISABLE_INTS(isp); } -/* - * When we want to get the 'default' WWNs (when lacking NVRAM), we pick them - * up from our platform default (defww{p|n}n) and morph them based upon - * channel. - * - * When we want to get the 'active' WWNs, we get NVRAM WWNs and then morph them - * based upon channel. - */ - uint64_t isp_default_wwn(ispsoftc_t * isp, int chan, int isactive, int iswwnn) { uint64_t seed; struct isp_fc *fc = ISP_FC_PC(isp, chan); - /* - * If we're asking for a active WWN, the default overrides get - * returned, otherwise the NVRAM value is picked. - * - * If we're asking for a default WWN, we just pick the default override. - */ + /* First try to use explicitly configured WWNs. */ + seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; + if (seed) + return (seed); + + /* Otherwise try to use WWNs from NVRAM. */ if (isactive) { - seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; - if (seed) { - return (seed); - } - seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : FCPARAM(isp, chan)->isp_wwpn_nvram; - if (seed) { + seed = iswwnn ? FCPARAM(isp, chan)->isp_wwnn_nvram : + FCPARAM(isp, chan)->isp_wwpn_nvram; + if (seed) return (seed); - } - return (0x400000007F000009ull); } - seed = iswwnn ? fc->def_wwnn : fc->def_wwpn; - - /* - * For channel zero just return what we have. For either ACTIVE or - * DEFAULT cases, we depend on default override of NVRAM values for - * channel zero. - */ - if (chan == 0) { - return (seed); + /* If still no WWNs, try to steal them from the first channel. */ + if (chan > 0) { + seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : + ISP_FC_PC(isp, 0)->def_wwpn; + if (seed == 0) { + seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : + FCPARAM(isp, 0)->isp_wwpn_nvram; + } } - /* - * For other channels, we are doing one of three things: - * - * 1. If what we have now is non-zero, return it. Otherwise we morph - * values from channel 0. 2. If we're here for a WWPN we synthesize - * it if Channel 0's wwpn has a type 2 NAA. 3. If we're here for a - * WWNN we synthesize it if Channel 0's wwnn has a type 2 NAA. - */ - - if (seed) { - return (seed); + /* If still nothing -- improvise. */ + if (seed == 0) { + seed = 0x400000007F000000ull + device_get_unit(isp->isp_dev); + if (!iswwnn) + seed ^= 0x0100000000000000ULL; } - seed = iswwnn ? ISP_FC_PC(isp, 0)->def_wwnn : ISP_FC_PC(isp, 0)->def_wwpn; - if (seed == 0) - seed = iswwnn ? FCPARAM(isp, 0)->isp_wwnn_nvram : FCPARAM(isp, 0)->isp_wwpn_nvram; - if (((seed >> 60) & 0xf) == 2) { + /* For additional channels we have to improvise even more. */ + if (!iswwnn && chan > 0) { /* - * The type 2 NAA fields for QLogic cards appear be laid out - * thusly: - * - * bits 63..60 NAA == 2 bits 59..57 unused/zero bit 56 - * port (1) or node (0) WWN distinguishor bit 48 - * physical port on dual-port chips (23XX/24XX) - * - * This is somewhat nutty, particularly since bit 48 is - * irrelevant as they assign separate serial numbers to - * different physical ports anyway. - * * We'll stick our channel number plus one first into bits * 57..59 and thence into bits 52..55 which allows for 8 bits - * of channel which is comfortably more than our maximum - * (126) now. + * of channel which is enough for our maximum of 255 channels. */ - seed &= ~0x0FF0000000000000ULL; - if (iswwnn == 0) { - seed |= ((uint64_t) (chan + 1) & 0xf) << 56; - seed |= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52; - } - } else { - seed = 0; + seed ^= 0x0100000000000000ULL; + seed ^= ((uint64_t) (chan + 1) & 0xf) << 56; + seed ^= ((uint64_t) ((chan + 1) >> 4) & 0xf) << 52; } return (seed); } diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h index ff9a5a3..9a9093a 100644 --- a/sys/dev/isp/isp_freebsd.h +++ b/sys/dev/isp/isp_freebsd.h @@ -38,6 +38,7 @@ #include <sys/malloc.h> #include <sys/mutex.h> #include <sys/condvar.h> +#include <sys/rman.h> #include <sys/sysctl.h> #include <sys/proc.h> @@ -286,9 +287,9 @@ struct isposinfo { /* * DMA related sdtuff */ - bus_space_tag_t bus_tag; + struct resource * regs; + struct resource * regs2; bus_dma_tag_t dmat; - bus_space_handle_t bus_handle; bus_dma_tag_t cdmat; bus_dmamap_t cdmap; @@ -361,8 +362,8 @@ struct isposinfo { #define FCP_NEXT_CRN isp_fcp_next_crn #define isp_lock isp_osinfo.lock -#define isp_bus_tag isp_osinfo.bus_tag -#define isp_bus_handle isp_osinfo.bus_handle +#define isp_regs isp_osinfo.regs +#define isp_regs2 isp_osinfo.regs2 /* * Locking macros... @@ -430,8 +431,7 @@ case SYNC_RESULT: \ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \ break; \ case SYNC_REG: \ - bus_space_barrier(isp->isp_osinfo.bus_tag, \ - isp->isp_osinfo.bus_handle, offset, size, \ + bus_barrier(isp->isp_osinfo.regs, offset, size, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \ break; \ default: \ @@ -463,8 +463,7 @@ case SYNC_RESULT: \ isp->isp_osinfo.cdmap, BUS_DMASYNC_POSTWRITE); \ break; \ case SYNC_REG: \ - bus_space_barrier(isp->isp_osinfo.bus_tag, \ - isp->isp_osinfo.bus_handle, offset, size, \ + bus_barrier(isp->isp_osinfo.regs, offset, size, \ BUS_SPACE_BARRIER_WRITE); \ break; \ default: \ diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index 9e8f3ab..ec99244 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -1402,7 +1402,9 @@ isp_put_icb_2400(ispsoftc_t *isp, isp_icb_2400_t *src, isp_icb_2400_t *dst) for (i = 0; i < 4; i++) { ISP_IOXPUT_16(isp, src->icb_priaddr[i], &dst->icb_priaddr[i]); } - for (i = 0; i < 4; i++) { + ISP_IOXPUT_16(isp, src->icb_msixresp, &dst->icb_msixresp); + ISP_IOXPUT_16(isp, src->icb_msixatio, &dst->icb_msixatio); + for (i = 0; i < 2; i++) { ISP_IOXPUT_16(isp, src->icb_reserved1[i], &dst->icb_reserved1[i]); } ISP_IOXPUT_16(isp, src->icb_atio_in, &dst->icb_atio_in); @@ -1415,9 +1417,14 @@ isp_put_icb_2400(ispsoftc_t *isp, isp_icb_2400_t *src, isp_icb_2400_t *dst) ISP_IOXPUT_32(isp, src->icb_fwoptions1, &dst->icb_fwoptions1); ISP_IOXPUT_32(isp, src->icb_fwoptions2, &dst->icb_fwoptions2); ISP_IOXPUT_32(isp, src->icb_fwoptions3, &dst->icb_fwoptions3); - for (i = 0; i < 12; i++) { + ISP_IOXPUT_16(isp, src->icb_qos, &dst->icb_qos); + for (i = 0; i < 3; i++) ISP_IOXPUT_16(isp, src->icb_reserved2[i], &dst->icb_reserved2[i]); - } + for (i = 0; i < 3; i++) + ISP_IOXPUT_16(isp, src->icb_enodemac[i], &dst->icb_enodemac[i]); + ISP_IOXPUT_16(isp, src->icb_disctime, &dst->icb_disctime); + for (i = 0; i < 4; i++) + ISP_IOXPUT_16(isp, src->icb_reserved3[i], &dst->icb_reserved3[i]); } void diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c index 55cb034..e5ea359 100644 --- a/sys/dev/isp/isp_pci.c +++ b/sys/dev/isp/isp_pci.c @@ -59,6 +59,8 @@ static uint32_t isp_pci_rd_reg_1080(ispsoftc_t *, int); static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint32_t); static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int); static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t); +static uint32_t isp_pci_rd_reg_2600(ispsoftc_t *, int); +static void isp_pci_wr_reg_2600(ispsoftc_t *, int, uint32_t); static int isp_pci_rd_isr(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *); static int isp_pci_rd_isr_2300(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *); static int isp_pci_rd_isr_2400(ispsoftc_t *, uint16_t *, uint16_t *, uint16_t *); @@ -172,6 +174,18 @@ static struct ispmdvec mdvec_2500 = { NULL }; +static struct ispmdvec mdvec_2600 = { + isp_pci_rd_isr_2400, + isp_pci_rd_reg_2600, + isp_pci_wr_reg_2600, + isp_pci_mbxdma, + isp_pci_dmasetup, + isp_common_dmateardown, + isp_pci_reset0, + isp_pci_reset1, + NULL +}; + #ifndef PCIM_CMD_INVEN #define PCIM_CMD_INVEN 0x10 #endif @@ -276,6 +290,14 @@ static struct ispmdvec mdvec_2500 = { #define PCI_PRODUCT_QLOGIC_ISP5432 0x5432 #endif +#ifndef PCI_PRODUCT_QLOGIC_ISP2031 +#define PCI_PRODUCT_QLOGIC_ISP2031 0x2031 +#endif + +#ifndef PCI_PRODUCT_QLOGIC_ISP8031 +#define PCI_PRODUCT_QLOGIC_ISP8031 0x8031 +#endif + #define PCI_QLOGIC_ISP5432 \ ((PCI_PRODUCT_QLOGIC_ISP5432 << 16) | PCI_VENDOR_QLOGIC) @@ -327,14 +349,17 @@ static struct ispmdvec mdvec_2500 = { #define PCI_QLOGIC_ISP6322 \ ((PCI_PRODUCT_QLOGIC_ISP6322 << 16) | PCI_VENDOR_QLOGIC) +#define PCI_QLOGIC_ISP2031 \ + ((PCI_PRODUCT_QLOGIC_ISP2031 << 16) | PCI_VENDOR_QLOGIC) + +#define PCI_QLOGIC_ISP8031 \ + ((PCI_PRODUCT_QLOGIC_ISP8031 << 16) | PCI_VENDOR_QLOGIC) + /* * Odd case for some AMI raid cards... We need to *not* attach to this. */ #define AMI_RAID_SUBVENDOR_ID 0x101e -#define IO_MAP_REG 0x10 -#define MEM_MAP_REG 0x14 - #define PCI_DFLT_LTNCY 0x40 #define PCI_DFLT_LNSZ 0x10 @@ -348,10 +373,16 @@ struct isp_pcisoftc { ispsoftc_t pci_isp; device_t pci_dev; struct resource * regs; + struct resource * regs1; + struct resource * regs2; void * irq; int iqd; int rtp; int rgd; + int rtp1; + int rgd1; + int rtp2; + int rgd2; void * ih; int16_t pci_poff[_NREG_BLKS]; bus_dma_tag_t dmat; @@ -434,6 +465,12 @@ isp_pci_probe(device_t dev) case PCI_QLOGIC_ISP6322: device_set_desc(dev, "Qlogic ISP 6322 PCI FC-AL Adapter"); break; + case PCI_QLOGIC_ISP2031: + device_set_desc(dev, "Qlogic ISP 2031 PCI FC-AL Adapter"); + break; + case PCI_QLOGIC_ISP8031: + device_set_desc(dev, "Qlogic ISP 8031 PCI FCoE Adapter"); + break; default: return (ENXIO); } @@ -485,31 +522,6 @@ isp_get_generic_options(device_t dev, ispsoftc_t *isp) } static void -isp_get_pci_options(device_t dev, int *m1, int *m2) -{ - int tval; - /* - * Which we should try first - memory mapping or i/o mapping? - * - * We used to try memory first followed by i/o on alpha, otherwise - * the reverse, but we should just try memory first all the time now. - */ - *m1 = PCIM_CMD_MEMEN; - *m2 = PCIM_CMD_PORTEN; - - tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_iomap", &tval) == 0 && tval != 0) { - *m1 = PCIM_CMD_PORTEN; - *m2 = PCIM_CMD_MEMEN; - } - tval = 0; - if (resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer_memmap", &tval) == 0 && tval != 0) { - *m1 = PCIM_CMD_MEMEN; - *m2 = PCIM_CMD_PORTEN; - } -} - -static void isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp) { const char *sptr; @@ -662,7 +674,7 @@ isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp) static int isp_pci_attach(device_t dev) { - int i, m1, m2, locksetup = 0; + int i, locksetup = 0; uint32_t data, cmd, linesz, did; struct isp_pcisoftc *pcs; ispsoftc_t *isp; @@ -689,33 +701,10 @@ isp_pci_attach(device_t dev) isp_nvports = 0; isp_get_generic_options(dev, isp); - /* - * Get PCI options- which in this case are just mapping preferences. - */ - isp_get_pci_options(dev, &m1, &m2); - linesz = PCI_DFLT_LNSZ; - pcs->irq = pcs->regs = NULL; + pcs->irq = pcs->regs = pcs->regs2 = NULL; pcs->rgd = pcs->rtp = pcs->iqd = 0; - pcs->rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; - pcs->rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; - pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE); - if (pcs->regs == NULL) { - pcs->rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT; - pcs->rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG; - pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, RF_ACTIVE); - } - if (pcs->regs == NULL) { - device_printf(dev, "unable to map any ports\n"); - goto bad; - } - if (bootverbose) { - device_printf(dev, "using %s space register mapping\n", (pcs->rgd == IO_MAP_REG)? "I/O" : "Memory"); - } - isp->isp_bus_tag = rman_get_bustag(pcs->regs); - isp->isp_bus_handle = rman_get_bushandle(pcs->regs); - pcs->pci_dev = dev; pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF; pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF; @@ -823,6 +812,14 @@ isp_pci_attach(device_t dev) isp->isp_type = ISP_HA_FC_2500; pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF; break; + case PCI_QLOGIC_ISP2031: + case PCI_QLOGIC_ISP8031: + did = 0x2600; + isp->isp_nchan += isp_nvports; + isp->isp_mdvec = &mdvec_2600; + isp->isp_type = ISP_HA_FC_2600; + pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS2400_OFF; + break; default: device_printf(dev, "unknown device type\n"); goto bad; @@ -830,6 +827,42 @@ isp_pci_attach(device_t dev) } isp->isp_revision = pci_get_revid(dev); + if (IS_26XX(isp)) { + pcs->rtp = SYS_RES_MEMORY; + pcs->rgd = PCIR_BAR(0); + pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, + RF_ACTIVE); + pcs->rtp1 = SYS_RES_MEMORY; + pcs->rgd1 = PCIR_BAR(2); + pcs->regs1 = bus_alloc_resource_any(dev, pcs->rtp1, &pcs->rgd1, + RF_ACTIVE); + pcs->rtp2 = SYS_RES_MEMORY; + pcs->rgd2 = PCIR_BAR(4); + pcs->regs2 = bus_alloc_resource_any(dev, pcs->rtp2, &pcs->rgd2, + RF_ACTIVE); + } else { + pcs->rtp = SYS_RES_MEMORY; + pcs->rgd = PCIR_BAR(1); + pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, &pcs->rgd, + RF_ACTIVE); + if (pcs->regs == NULL) { + pcs->rtp = SYS_RES_IOPORT; + pcs->rgd = PCIR_BAR(0); + pcs->regs = bus_alloc_resource_any(dev, pcs->rtp, + &pcs->rgd, RF_ACTIVE); + } + } + if (pcs->regs == NULL) { + device_printf(dev, "Unable to map any ports\n"); + goto bad; + } + if (bootverbose) { + device_printf(dev, "Using %s space register mapping\n", + (pcs->rtp == SYS_RES_IOPORT)? "I/O" : "Memory"); + } + isp->isp_regs = pcs->regs; + isp->isp_regs2 = pcs->regs2; + if (IS_FC(isp)) { psize = sizeof (fcparam); xsize = sizeof (struct isp_fc); @@ -910,20 +943,28 @@ isp_pci_attach(device_t dev) data &= ~1; pci_write_config(dev, PCIR_ROMADDR, data, 4); - /* - * Do MSI - * - * NB: MSI-X needs to be disabled for the 2432 (PCI-Express) - */ - if (IS_24XX(isp) || IS_2322(isp)) { - pcs->msicount = pci_msi_count(dev); - if (pcs->msicount > 1) { - pcs->msicount = 1; + if (IS_26XX(isp)) { + /* 26XX chips support only MSI-X, so start from them. */ + pcs->msicount = imin(pci_msix_count(dev), 1); + if (pcs->msicount > 0 && + (i = pci_alloc_msix(dev, &pcs->msicount)) == 0) { + pcs->iqd = 1; + } else { + pcs->msicount = 0; } - if (pci_alloc_msi(dev, &pcs->msicount) == 0) { + } + if (pcs->msicount == 0 && (IS_24XX(isp) || IS_2322(isp))) { + /* + * Older chips support both MSI and MSI-X, but I have + * feeling that older firmware may not support MSI-X, + * but we have no way to check the firmware flag here. + */ + pcs->msicount = imin(pci_msi_count(dev), 1); + if (pcs->msicount > 0 && + pci_alloc_msi(dev, &pcs->msicount) == 0) { pcs->iqd = 1; } else { - pcs->iqd = 0; + pcs->msicount = 0; } } pcs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &pcs->iqd, RF_ACTIVE | RF_SHAREABLE); @@ -978,9 +1019,12 @@ bad: if (pcs->msicount) { pci_release_msi(dev); } - if (pcs->regs) { + if (pcs->regs) (void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs); - } + if (pcs->regs1) + (void) bus_release_resource(dev, pcs->rtp1, pcs->rgd1, pcs->regs1); + if (pcs->regs2) + (void) bus_release_resource(dev, pcs->rtp2, pcs->rgd2, pcs->regs2); if (pcs->pci_isp.isp_param) { free(pcs->pci_isp.isp_param, M_DEVBUF); pcs->pci_isp.isp_param = NULL; @@ -1019,6 +1063,10 @@ isp_pci_detach(device_t dev) pci_release_msi(dev); } (void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs); + if (pcs->regs1) + (void) bus_release_resource(dev, pcs->rtp1, pcs->rgd1, pcs->regs1); + if (pcs->regs2) + (void) bus_release_resource(dev, pcs->rtp2, pcs->rgd2, pcs->regs2); /* * XXX: THERE IS A LOT OF LEAKAGE HERE */ @@ -1037,15 +1085,12 @@ isp_pci_detach(device_t dev) (((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \ _BLK_REG_SHFT] + ((x) & 0xfff)) -#define BXR2(isp, off) \ - bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, off) -#define BXW2(isp, off, v) \ - bus_space_write_2(isp->isp_bus_tag, isp->isp_bus_handle, off, v) -#define BXR4(isp, off) \ - bus_space_read_4(isp->isp_bus_tag, isp->isp_bus_handle, off) -#define BXW4(isp, off, v) \ - bus_space_write_4(isp->isp_bus_tag, isp->isp_bus_handle, off, v) - +#define BXR2(isp, off) bus_read_2((isp)->isp_regs, (off)) +#define BXW2(isp, off, v) bus_write_2((isp)->isp_regs, (off), (v)) +#define BXR4(isp, off) bus_read_4((isp)->isp_regs, (off)) +#define BXW4(isp, off, v) bus_write_4((isp)->isp_regs, (off), (v)) +#define B2R4(isp, off) bus_read_4((isp)->isp_regs2, (off)) +#define B2W4(isp, off, v) bus_write_4((isp)->isp_regs2, (off), (v)) static ISP_INLINE int isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp) @@ -1308,20 +1353,19 @@ isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff) case MBOX_BLOCK: return (BXR2(isp, IspVirt2Off(isp, regoff))); case SXP_BLOCK: - isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK read at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "SXP_BLOCK read at 0x%x", regoff); return (0xffffffff); case RISC_BLOCK: - isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK read at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "RISC_BLOCK read at 0x%x", regoff); return (0xffffffff); case DMA_BLOCK: - isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK read at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "DMA_BLOCK read at 0x%x", regoff); return (0xffffffff); default: - isp_prt(isp, ISP_LOGWARN, "unknown block read at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "unknown block read at 0x%x", regoff); return (0xffffffff); } - switch (regoff) { case BIU2400_FLASH_ADDR: case BIU2400_FLASH_DATA: @@ -1349,8 +1393,8 @@ isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff) rv = BXR4(isp, IspVirt2Off(isp, regoff)) >> 16; break; default: - isp_prt(isp, ISP_LOGERR, - "isp_pci_rd_reg_2400: unknown offset %x", regoff); + isp_prt(isp, ISP_LOGERR, "unknown register read at 0x%x", + regoff); rv = 0xffffffff; break; } @@ -1370,17 +1414,16 @@ isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val) MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 2, -1); return; case SXP_BLOCK: - isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK write at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "SXP_BLOCK write at 0x%x", regoff); return; case RISC_BLOCK: - isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK write at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "RISC_BLOCK write at 0x%x", regoff); return; case DMA_BLOCK: - isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK write at 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "DMA_BLOCK write at 0x%x", regoff); return; default: - isp_prt(isp, ISP_LOGWARN, "unknown block write at 0x%x", - regoff); + isp_prt(isp, ISP_LOGERR, "unknown block write at 0x%x", regoff); break; } @@ -1415,10 +1458,83 @@ isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val) MEMORYBARRIER(isp, SYNC_REG, IspVirt2Off(isp, regoff), 4, -1); break; default: - isp_prt(isp, ISP_LOGERR, - "isp_pci_wr_reg_2400: bad offset 0x%x", regoff); + isp_prt(isp, ISP_LOGERR, "unknown register write at 0x%x", + regoff); + break; + } +} + +static uint32_t +isp_pci_rd_reg_2600(ispsoftc_t *isp, int regoff) +{ + uint32_t rv; + + switch (regoff) { + case BIU2400_PRI_REQINP: + case BIU2400_PRI_REQOUTP: + isp_prt(isp, ISP_LOGERR, "unknown register read at 0x%x", + regoff); + rv = 0xffffffff; + break; + case BIU2400_REQINP: + rv = B2R4(isp, 0x00); + break; + case BIU2400_REQOUTP: + rv = B2R4(isp, 0x04); break; + case BIU2400_RSPINP: + rv = B2R4(isp, 0x08); + break; + case BIU2400_RSPOUTP: + rv = B2R4(isp, 0x0c); + break; + case BIU2400_ATIO_RSPINP: + rv = B2R4(isp, 0x10); + break; + case BIU2400_ATIO_RSPOUTP: + rv = B2R4(isp, 0x14); + break; + default: + rv = isp_pci_rd_reg_2400(isp, regoff); + break; + } + return (rv); +} + +static void +isp_pci_wr_reg_2600(ispsoftc_t *isp, int regoff, uint32_t val) +{ + int off; + + switch (regoff) { + case BIU2400_PRI_REQINP: + case BIU2400_PRI_REQOUTP: + isp_prt(isp, ISP_LOGERR, "unknown register write at 0x%x", + regoff); + return; + case BIU2400_REQINP: + off = 0x00; + break; + case BIU2400_REQOUTP: + off = 0x04; + break; + case BIU2400_RSPINP: + off = 0x08; + break; + case BIU2400_RSPOUTP: + off = 0x0c; + break; + case BIU2400_ATIO_RSPINP: + off = 0x10; + break; + case BIU2400_ATIO_RSPOUTP: + off = 0x14; + break; + default: + isp_pci_wr_reg_2400(isp, regoff, val); + return; } + B2W4(isp, off, val); } diff --git a/sys/dev/isp/isp_sbus.c b/sys/dev/isp/isp_sbus.c index cb8f169..2abfc64 100644 --- a/sys/dev/isp/isp_sbus.c +++ b/sys/dev/isp/isp_sbus.c @@ -180,8 +180,7 @@ isp_sbus_attach(device_t dev) sbs->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF; sbs->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF; isp = &sbs->sbus_isp; - isp->isp_bus_tag = rman_get_bustag(sbs->regs); - isp->isp_bus_handle = rman_get_bushandle(sbs->regs); + isp->isp_regs = sbs->regs; isp->isp_mdvec = &sbs->sbus_mdvec; isp->isp_bustype = ISP_BT_SBUS; isp->isp_type = ISP_HA_SCSI_UNKNOWN; @@ -367,16 +366,15 @@ isp_sbus_detach(device_t dev) (((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \ _BLK_REG_SHFT] + ((x) & 0xff)) -#define BXR2(sbc, off) \ - bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, off) +#define BXR2(isp, off) bus_read_2((isp)->isp_regs, (off)) static int isp_sbus_rd_isr(ispsoftc_t *isp, uint16_t *isrp, uint16_t *semap, uint16_t *info) { uint16_t isr, sema; - isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR)); - sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA)); + isr = BXR2(isp, IspVirt2Off(isp, BIU_ISR)); + sema = BXR2(isp, IspVirt2Off(isp, BIU_SEMA)); isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema); isr &= INT_PENDING_MASK(isp); sema &= BIU_SEMA_LOCK; @@ -385,7 +383,7 @@ isp_sbus_rd_isr(ispsoftc_t *isp, uint16_t *isrp, uint16_t *semap, uint16_t *info } *isrp = isr; if ((*semap = sema) != 0) - *info = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0)); + *info = BXR2(isp, IspVirt2Off(isp, OUTMAILBOX0)); return (1); } @@ -396,7 +394,7 @@ isp_sbus_rd_reg(ispsoftc_t *isp, int regoff) struct isp_sbussoftc *sbs = (struct isp_sbussoftc *) isp; int offset = sbs->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT]; offset += (regoff & 0xff); - rval = bus_space_read_2(isp->isp_bus_tag, isp->isp_bus_handle, offset); + rval = BXR2(isp, offset); isp_prt(isp, ISP_LOGDEBUG3, "isp_sbus_rd_reg(off %x) = %x", regoff, rval); return (rval); @@ -410,7 +408,7 @@ isp_sbus_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val) offset += (regoff & 0xff); isp_prt(isp, ISP_LOGDEBUG3, "isp_sbus_wr_reg(off %x) = %x", regoff, val); - bus_space_write_2(isp->isp_bus_tag, isp->isp_bus_handle, offset, val); + bus_write_2(isp->isp_regs, offset, val); MEMORYBARRIER(isp, SYNC_REG, offset, 2, -1); } diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index d724679..a89228b 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -122,6 +122,7 @@ #define MBOX_GET_TARGET_STATUS 0x0056 /* These are for the ISP2X00 FC cards */ +#define MBOX_LOAD_FLASH_FIRMWARE 0x0003 #define MBOX_WRITE_FC_SERDES_REG 0x0003 /* FC only */ #define MBOX_READ_FC_SERDES_REG 0x0004 /* FC only */ #define MBOX_GET_IO_STATUS 0x0012 @@ -1007,9 +1008,9 @@ typedef struct { #define ICBXOPT_TIMER_MASK 0x7 #define ICBZOPT_RATE_MASK 0xC000 -#define ICBZOPT_RATE_ONEGB 0x0000 +#define ICBZOPT_RATE_1GB 0x0000 #define ICBZOPT_RATE_AUTO 0x8000 -#define ICBZOPT_RATE_TWOGB 0x4000 +#define ICBZOPT_RATE_2GB 0x4000 #define ICBZOPT_50_OHM 0x2000 #define ICBZOPT_NO_LOCAL_PLOGI 0x0080 #define ICBZOPT_ENA_OOF 0x0040 /* out of order frame handling */ @@ -1058,14 +1059,14 @@ typedef struct { #define ICB2400_OPT3_ENA_ETH_RESP 0x08000000 #define ICB2400_OPT3_ENA_ETH_ATIO 0x04000000 #define ICB2400_OPT3_ENA_MFCF 0x00020000 -#define ICB2400_OPT3_SKIP_FOURGB 0x00010000 +#define ICB2400_OPT3_SKIP_4GB 0x00010000 #define ICB2400_OPT3_RATE_MASK 0x0000E000 -#define ICB2400_OPT3_RATE_ONEGB 0x00000000 -#define ICB2400_OPT3_RATE_TWOGB 0x00002000 +#define ICB2400_OPT3_RATE_1GB 0x00000000 +#define ICB2400_OPT3_RATE_2GB 0x00002000 #define ICB2400_OPT3_RATE_AUTO 0x00004000 -#define ICB2400_OPT3_RATE_FOURGB 0x00006000 -#define ICB2400_OPT3_RATE_EIGHTGB 0x00008000 -#define ICB2400_OPT3_RATE_SIXTEENGB 0x0000A000 +#define ICB2400_OPT3_RATE_4GB 0x00006000 +#define ICB2400_OPT3_RATE_8GB 0x00008000 +#define ICB2400_OPT3_RATE_16GB 0x0000A000 #define ICB2400_OPT3_ENA_OOF_XFRDY 0x00000200 #define ICB2400_OPT3_NO_N2N_LOGI 0x00000100 #define ICB2400_OPT3_NO_LOCAL_PLOGI 0x00000080 diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index 10060e1..0c42642 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -653,8 +653,8 @@ struct ispsoftc { #define ISP_CFG_NPORT 0x04 /* prefer {N/F}-Port connection */ #define ISP_CFG_NPORT_ONLY 0x08 /* insist on {N/F}-Port connection */ #define ISP_CFG_LPORT_ONLY 0x0c /* insist on {N/F}L-Port connection */ -#define ISP_CFG_ONEGB 0x10 /* force 1GB connection (23XX only) */ -#define ISP_CFG_TWOGB 0x20 /* force 2GB connection (23XX only) */ +#define ISP_CFG_1GB 0x10 /* force 1GB connection (23XX only) */ +#define ISP_CFG_2GB 0x20 /* force 2GB connection (23XX only) */ #define ISP_CFG_NORELOAD 0x80 /* don't download f/w */ #define ISP_CFG_NONVRAM 0x40 /* ignore NVRAM */ #define ISP_CFG_NOFCTAPE 0x100 /* disable FC-Tape */ @@ -662,9 +662,9 @@ struct ispsoftc { #define ISP_CFG_OWNFSZ 0x400 /* override NVRAM frame size */ #define ISP_CFG_OWNLOOPID 0x800 /* override NVRAM loopid */ #define ISP_CFG_OWNEXCTHROTTLE 0x1000 /* override NVRAM execution throttle */ -#define ISP_CFG_FOURGB 0x2000 /* force 4GB connection (24XX only) */ -#define ISP_CFG_EIGHTGB 0x4000 /* force 8GB connection (25XX only) */ -#define ISP_CFG_SIXTEENGB 0x8000 /* force 16GB connection (82XX only) */ +#define ISP_CFG_4GB 0x2000 /* force 4GB connection (24XX only) */ +#define ISP_CFG_8GB 0x4000 /* force 8GB connection (25XX only) */ +#define ISP_CFG_16GB 0x8000 /* force 16GB connection (82XX only) */ /* * For each channel, the outer layers should know what role that channel @@ -764,6 +764,7 @@ struct ispsoftc { #define ISP_HA_FC_2322 0x50 #define ISP_HA_FC_2400 0x60 #define ISP_HA_FC_2500 0x70 +#define ISP_HA_FC_2600 0x80 #define IS_SCSI(isp) (isp->isp_type & ISP_HA_SCSI) #define IS_1020(isp) (isp->isp_type < ISP_HA_SCSI_1240) @@ -789,6 +790,7 @@ struct ispsoftc { #define IS_2322(isp) ((isp)->isp_type == ISP_HA_FC_2322) #define IS_24XX(isp) ((isp)->isp_type >= ISP_HA_FC_2400) #define IS_25XX(isp) ((isp)->isp_type >= ISP_HA_FC_2500) +#define IS_26XX(isp) ((isp)->isp_type >= ISP_HA_FC_2600) /* * DMA related macros diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c index 27ef8b3..693f000 100644 --- a/sys/dev/md/md.c +++ b/sys/dev/md/md.c @@ -825,8 +825,8 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) struct buf *pb; bus_dma_segment_t *vlist; struct thread *td; - off_t len, zerosize; - int ma_offs; + off_t iolen, len, zerosize; + int ma_offs, npages; switch (bp->bio_cmd) { case BIO_READ: @@ -847,6 +847,7 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) pb = NULL; piov = NULL; ma_offs = bp->bio_ma_offset; + len = bp->bio_length; /* * VNODE I/O @@ -879,7 +880,6 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) auio.uio_iovcnt = howmany(bp->bio_length, zerosize); piov = malloc(sizeof(*piov) * auio.uio_iovcnt, M_MD, M_WAITOK); auio.uio_iov = piov; - len = bp->bio_length; while (len > 0) { piov->iov_base = __DECONST(void *, zero_region); piov->iov_len = len; @@ -893,7 +893,6 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) piov = malloc(sizeof(*piov) * bp->bio_ma_n, M_MD, M_WAITOK); auio.uio_iov = piov; vlist = (bus_dma_segment_t *)bp->bio_data; - len = bp->bio_length; while (len > 0) { piov->iov_base = (void *)(uintptr_t)(vlist->ds_addr + ma_offs); @@ -909,11 +908,20 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) piov = auio.uio_iov; } else if ((bp->bio_flags & BIO_UNMAPPED) != 0) { pb = getpbuf(&md_vnode_pbuf_freecnt); - pmap_qenter((vm_offset_t)pb->b_data, bp->bio_ma, bp->bio_ma_n); - aiov.iov_base = (void *)((vm_offset_t)pb->b_data + ma_offs); - aiov.iov_len = bp->bio_length; + bp->bio_resid = len; +unmapped_step: + npages = atop(min(MAXPHYS, round_page(len + (ma_offs & + PAGE_MASK)))); + iolen = min(ptoa(npages) - (ma_offs & PAGE_MASK), len); + KASSERT(iolen > 0, ("zero iolen")); + pmap_qenter((vm_offset_t)pb->b_data, + &bp->bio_ma[atop(ma_offs)], npages); + aiov.iov_base = (void *)((vm_offset_t)pb->b_data + + (ma_offs & PAGE_MASK)); + aiov.iov_len = iolen; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; + auio.uio_resid = iolen; } else { aiov.iov_base = bp->bio_data; aiov.iov_len = bp->bio_length; @@ -937,15 +945,21 @@ mdstart_vnode(struct md_s *sc, struct bio *bp) vn_finished_write(mp); } - if (pb) { - pmap_qremove((vm_offset_t)pb->b_data, bp->bio_ma_n); + if (pb != NULL) { + pmap_qremove((vm_offset_t)pb->b_data, npages); + if (error == 0) { + len -= iolen; + bp->bio_resid -= iolen; + ma_offs += iolen; + if (len > 0) + goto unmapped_step; + } relpbuf(pb, &md_vnode_pbuf_freecnt); } - if (piov != NULL) - free(piov, M_MD); - - bp->bio_resid = auio.uio_resid; + free(piov, M_MD); + if (pb == NULL) + bp->bio_resid = auio.uio_resid; return (error); } diff --git a/sys/dev/mii/rgephy.c b/sys/dev/mii/rgephy.c index 2c28068..ff7c470 100644 --- a/sys/dev/mii/rgephy.c +++ b/sys/dev/mii/rgephy.c @@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$"); #include "miibus_if.h" #include <machine/bus.h> -#include <pci/if_rlreg.h> +#include <dev/rl/if_rlreg.h> static int rgephy_probe(device_t); static int rgephy_attach(device_t); diff --git a/sys/dev/mii/rlphy.c b/sys/dev/mii/rlphy.c index ddf8d73..308ee22 100644 --- a/sys/dev/mii/rlphy.c +++ b/sys/dev/mii/rlphy.c @@ -53,7 +53,7 @@ __FBSDID("$FreeBSD$"); #include "miidevs.h" #include <machine/bus.h> -#include <pci/if_rlreg.h> +#include <dev/rl/if_rlreg.h> #include "miibus_if.h" diff --git a/sys/dev/mii/rlswitch.c b/sys/dev/mii/rlswitch.c index b158fd4..2e9188e 100644 --- a/sys/dev/mii/rlswitch.c +++ b/sys/dev/mii/rlswitch.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); #include "miidevs.h" #include <machine/bus.h> -#include <pci/if_rlreg.h> +#include <dev/rl/if_rlreg.h> #include "miibus_if.h" diff --git a/sys/dev/mpt/mpt.c b/sys/dev/mpt/mpt.c index d5b2a18..9317965 100644 --- a/sys/dev/mpt/mpt.c +++ b/sys/dev/mpt/mpt.c @@ -1423,7 +1423,7 @@ mpt_send_handshake_cmd(struct mpt_softc *mpt, size_t len, void *cmd) /* Send the command */ for (i = 0; i < len; i++) { - mpt_write(mpt, MPT_OFFSET_DOORBELL, htole32(*data32++)); + mpt_write_stream(mpt, MPT_OFFSET_DOORBELL, *data32++); if (mpt_wait_db_ack(mpt) != MPT_OK) { mpt_prt(mpt, "mpt_send_handshake_cmd: timeout @ index %d\n", i); @@ -1457,7 +1457,7 @@ mpt_recv_handshake_reply(struct mpt_softc *mpt, size_t reply_len, void *reply) *data16++ = le16toh(data & MPT_DB_DATA_MASK); mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); - /* Get Second Word */ + /* Get second word */ if (mpt_wait_db_int(mpt) != MPT_OK) { mpt_prt(mpt, "mpt_recv_handshake_cmd timeout2\n"); return ETIMEDOUT; @@ -1481,18 +1481,13 @@ mpt_recv_handshake_reply(struct mpt_softc *mpt, size_t reply_len, void *reply) left = (hdr->MsgLength << 1) - 2; reply_left = reply_len - 2; while (left--) { - u_int16_t datum; - if (mpt_wait_db_int(mpt) != MPT_OK) { mpt_prt(mpt, "mpt_recv_handshake_cmd timeout3\n"); return ETIMEDOUT; } data = mpt_read(mpt, MPT_OFFSET_DOORBELL); - datum = le16toh(data & MPT_DB_DATA_MASK); - if (reply_left-- > 0) - *data16++ = datum; - + *data16++ = le16toh(data & MPT_DB_DATA_MASK); mpt_write(mpt, MPT_OFFSET_INTR_STATUS, 0); } diff --git a/sys/dev/mpt/mpt.h b/sys/dev/mpt/mpt.h index 1dcd76f..57dbe7b 100644 --- a/sys/dev/mpt/mpt.h +++ b/sys/dev/mpt/mpt.h @@ -329,7 +329,6 @@ typedef struct mpt_config_params { } cfgparms_t; /**************************** MPI Target State Info ***************************/ - typedef struct { uint32_t reply_desc; /* current reply descriptor */ uint32_t resid; /* current data residual */ @@ -784,6 +783,7 @@ mpt_assign_serno(struct mpt_softc *mpt, request_t *req) /******************************* Register Access ******************************/ static __inline void mpt_write(struct mpt_softc *, size_t, uint32_t); +static __inline void mpt_write_stream(struct mpt_softc *, size_t, uint32_t); static __inline uint32_t mpt_read(struct mpt_softc *, int); static __inline void mpt_pio_write(struct mpt_softc *, size_t, uint32_t); static __inline uint32_t mpt_pio_read(struct mpt_softc *, int); @@ -794,6 +794,12 @@ mpt_write(struct mpt_softc *mpt, size_t offset, uint32_t val) bus_space_write_4(mpt->pci_st, mpt->pci_sh, offset, val); } +static __inline void +mpt_write_stream(struct mpt_softc *mpt, size_t offset, uint32_t val) +{ + bus_space_write_stream_4(mpt->pci_st, mpt->pci_sh, offset, val); +} + static __inline uint32_t mpt_read(struct mpt_softc *mpt, int offset) { @@ -818,6 +824,7 @@ mpt_pio_read(struct mpt_softc *mpt, int offset) KASSERT(mpt->pci_pio_reg != NULL, ("no PIO resource")); return (bus_space_read_4(mpt->pci_pio_st, mpt->pci_pio_sh, offset)); } + /*********************** Reply Frame/Request Management ***********************/ /* Max MPT Reply we are willing to accept (must be power of 2) */ #define MPT_REPLY_SIZE 256 @@ -958,6 +965,7 @@ mpt_cdblen(uint8_t cdb0, int maxlen) return (16); } } + #ifdef INVARIANTS static __inline request_t * mpt_tag_2_req(struct mpt_softc *, uint32_t); static __inline request_t * @@ -1136,6 +1144,7 @@ mpt_write_cur_cfg_page(struct mpt_softc *mpt, uint32_t PageAddress, PageAddress, hdr, len, sleep_ok, timeout_ms)); } + /* mpt_debug.c functions */ void mpt_print_reply(void *vmsg); void mpt_print_db(uint32_t mb); @@ -1145,4 +1154,5 @@ void mpt_req_state(mpt_req_state_t state); void mpt_print_config_request(void *vmsg); void mpt_print_request(void *vmsg); void mpt_dump_sgl(SGE_IO_UNION *se, int offset); + #endif /* _MPT_H_ */ diff --git a/sys/dev/qlxgbe/ql_hw.c b/sys/dev/qlxgbe/ql_hw.c index 0e389d6..3efca30 100644 --- a/sys/dev/qlxgbe/ql_hw.c +++ b/sys/dev/qlxgbe/ql_hw.c @@ -387,6 +387,7 @@ ql_hw_add_sysctls(qla_host_t *ha) "Minidump Utility can start minidump process"); #ifdef QL_DBG + ha->err_inject = 0; SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "err_inject", @@ -3057,7 +3058,7 @@ ql_hw_check_health(qla_host_t *ha) val = READ_REG32(ha, Q8_FIRMWARE_HEARTBEAT); if ((val != ha->hw.hbeat_value) && - (!(QL_ERR_INJECT(ha, INJCT_TEMPERATURE_FAILURE)))) { + (!(QL_ERR_INJECT(ha, INJCT_HEARTBEAT_FAILURE)))) { ha->hw.hbeat_value = val; return 0; } diff --git a/sys/dev/qlxgbe/ql_os.c b/sys/dev/qlxgbe/ql_os.c index ecc6cce..5190ff5 100644 --- a/sys/dev/qlxgbe/ql_os.c +++ b/sys/dev/qlxgbe/ql_os.c @@ -289,8 +289,6 @@ qla_pci_attach(device_t dev) int i; uint32_t num_rcvq = 0; - QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); - if ((ha = device_get_softc(dev)) == NULL) { device_printf(dev, "cannot get softc\n"); return (ENOMEM); diff --git a/sys/dev/qlxgbe/ql_ver.h b/sys/dev/qlxgbe/ql_ver.h index 061e368..0d86db9 100644 --- a/sys/dev/qlxgbe/ql_ver.h +++ b/sys/dev/qlxgbe/ql_ver.h @@ -36,6 +36,6 @@ #define QLA_VERSION_MAJOR 3 #define QLA_VERSION_MINOR 10 -#define QLA_VERSION_BUILD 24 +#define QLA_VERSION_BUILD 25 #endif /* #ifndef _QL_VER_H_ */ diff --git a/sys/dev/re/if_re.c b/sys/dev/re/if_re.c index 20d47e2..3812962 100644 --- a/sys/dev/re/if_re.c +++ b/sys/dev/re/if_re.c @@ -147,7 +147,7 @@ __FBSDID("$FreeBSD$"); #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> -#include <pci/if_rlreg.h> +#include <dev/rl/if_rlreg.h> MODULE_DEPEND(re, pci, 1, 1, 1); MODULE_DEPEND(re, ether, 1, 1, 1); @@ -237,6 +237,7 @@ static const struct rl_hwrev re_hwrevs[] = { { RL_HWREV_8168F, RL_8169, "8168F/8111F", RL_JUMBO_MTU_9K}, { RL_HWREV_8168G, RL_8169, "8168G/8111G", RL_JUMBO_MTU_9K}, { RL_HWREV_8168GU, RL_8169, "8168GU/8111GU", RL_JUMBO_MTU_9K}, + { RL_HWREV_8168H, RL_8169, "8168H/8111H", RL_JUMBO_MTU_9K}, { RL_HWREV_8411, RL_8169, "8411", RL_JUMBO_MTU_9K}, { RL_HWREV_8411B, RL_8169, "8411B", RL_JUMBO_MTU_9K}, { 0, 0, NULL, 0 } @@ -633,9 +634,8 @@ re_miibus_statchg(device_t dev) } } /* - * RealTek controllers does not provide any interface to - * Tx/Rx MACs for resolved speed, duplex and flow-control - * parameters. + * RealTek controllers do not provide any interface to the RX/TX + * MACs for resolved speed, duplex and flow-control parameters. */ } @@ -657,7 +657,7 @@ re_set_rxmode(struct rl_softc *sc) rxfilt = RL_RXCFG_CONFIG | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_BROAD; if ((sc->rl_flags & RL_FLAG_EARLYOFF) != 0) rxfilt |= RL_RXCFG_EARLYOFF; - else if ((sc->rl_flags & RL_FLAG_EARLYOFFV2) != 0) + else if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) rxfilt |= RL_RXCFG_EARLYOFFV2; if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { @@ -1204,11 +1204,10 @@ re_attach(device_t dev) struct rl_softc *sc; struct ifnet *ifp; const struct rl_hwrev *hw_rev; + int capmask, error = 0, hwrev, i, msic, msixc, + phy, reg, rid; u_int32_t cap, ctl; - int hwrev; u_int16_t devid, re_did = 0; - int error = 0, i, phy, rid; - int msic, msixc, reg; uint8_t cfg; sc = device_get_softc(dev); @@ -1488,11 +1487,12 @@ re_attach(device_t dev) RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2 | RL_FLAG_CMDSTOP_WAIT_TXQ | RL_FLAG_WOL_MANLINK | - RL_FLAG_EARLYOFFV2 | RL_FLAG_RXDV_GATED; + RL_FLAG_8168G_PLUS; break; case RL_HWREV_8168GU: + case RL_HWREV_8168H: if (pci_get_device(dev) == RT_DEVICEID_8101E) { - /* RTL8106EUS */ + /* RTL8106E(US), RTL8107E */ sc->rl_flags |= RL_FLAG_FASTETHER; } else sc->rl_flags |= RL_FLAG_JUMBOV2 | RL_FLAG_WOL_MANLINK; @@ -1500,7 +1500,7 @@ re_attach(device_t dev) sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_CMDSTOP_WAIT_TXQ | - RL_FLAG_EARLYOFFV2 | RL_FLAG_RXDV_GATED; + RL_FLAG_8168G_PLUS; break; case RL_HWREV_8169_8110SB: case RL_HWREV_8169_8110SBL: @@ -1650,8 +1650,11 @@ re_attach(device_t dev) phy = RE_PHYAD_INTERNAL; if (sc->rl_type == RL_8169) phy = 1; + capmask = BMSR_DEFCAPMASK; + if ((sc->rl_flags & RL_FLAG_FASTETHER) != 0) + capmask &= ~BMSR_EXTSTAT; error = mii_attach(dev, &sc->rl_miibus, ifp, re_ifmedia_upd, - re_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, MIIF_DOPAUSE); + re_ifmedia_sts, capmask, phy, MII_OFFSET_ANY, MIIF_DOPAUSE); if (error != 0) { device_printf(dev, "attaching PHYs failed\n"); goto fail; @@ -1691,13 +1694,13 @@ re_attach(device_t dev) #ifdef DEV_NETMAP re_netmap_attach(sc); #endif /* DEV_NETMAP */ + #ifdef RE_DIAG /* * Perform hardware diagnostic on the original RTL8169. * Some 32-bit cards were incorrectly wired and would * malfunction if plugged into a 64-bit slot. */ - if (hwrev == RL_HWREV_8169) { error = re_diag(sc); if (error) { @@ -1729,7 +1732,6 @@ re_attach(device_t dev) } fail: - if (error) re_detach(dev); @@ -2935,6 +2937,7 @@ re_start_locked(struct ifnet *ifp) return; } #endif /* DEV_NETMAP */ + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING || (sc->rl_flags & RL_FLAG_LINK) == 0) return; @@ -3190,9 +3193,18 @@ re_init_locked(struct rl_softc *sc) CSR_WRITE_4(sc, RL_TXLIST_ADDR_LO, RL_ADDR_LO(sc->rl_ldata.rl_tx_list_addr)); - if ((sc->rl_flags & RL_FLAG_RXDV_GATED) != 0) + if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) { + /* Disable RXDV gate. */ CSR_WRITE_4(sc, RL_MISC, CSR_READ_4(sc, RL_MISC) & ~0x00080000); + } + + /* + * Enable transmit and receive for pre-RTL8168G controllers. + * RX/TX MACs should be enabled before RX/TX configuration. + */ + if ((sc->rl_flags & RL_FLAG_8168G_PLUS) == 0) + CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB | RL_CMD_RX_ENB); /* * Set the initial TX configuration. @@ -3221,9 +3233,11 @@ re_init_locked(struct rl_softc *sc) } /* - * Enable transmit and receive. + * Enable transmit and receive for RTL8168G and later controllers. + * RX/TX MACs should be enabled after RX/TX configuration. */ - CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB | RL_CMD_RX_ENB); + if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) + CSR_WRITE_1(sc, RL_COMMAND, RL_CMD_TX_ENB | RL_CMD_RX_ENB); #ifdef DEVICE_POLLING /* @@ -3579,6 +3593,12 @@ re_stop(struct rl_softc *sc) ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_INDIV | RL_RXCFG_RX_MULTI | RL_RXCFG_RX_BROAD)); + if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) { + /* Enable RXDV gate. */ + CSR_WRITE_4(sc, RL_MISC, CSR_READ_4(sc, RL_MISC) | + 0x00080000); + } + if ((sc->rl_flags & RL_FLAG_WAIT_TXPOLL) != 0) { for (i = RL_TIMEOUT; i > 0; i--) { if ((CSR_READ_1(sc, sc->rl_txstart) & @@ -3830,6 +3850,11 @@ re_setwol(struct rl_softc *sc) CSR_READ_1(sc, RL_GPIO) & ~0x01); } if ((ifp->if_capenable & IFCAP_WOL) != 0) { + if ((sc->rl_flags & RL_FLAG_8168G_PLUS) != 0) { + /* Disable RXDV gate. */ + CSR_WRITE_4(sc, RL_MISC, CSR_READ_4(sc, RL_MISC) & + ~0x00080000); + } re_set_rxmode(sc); if ((sc->rl_flags & RL_FLAG_WOL_MANLINK) != 0) re_set_linkspeed(sc); @@ -3942,7 +3967,6 @@ re_add_sysctls(struct rl_softc *sc) sc->rl_int_rx_mod = RL_TIMER_DEFAULT; } } - } static int diff --git a/sys/pci/if_rl.c b/sys/dev/rl/if_rl.c index 4f91d1f..2ff1310 100644 --- a/sys/pci/if_rl.c +++ b/sys/dev/rl/if_rl.c @@ -126,7 +126,7 @@ MODULE_DEPEND(rl, miibus, 1, 1, 1); /* "device miibus" required. See GENERIC if you get errors here. */ #include "miibus_if.h" -#include <pci/if_rlreg.h> +#include <dev/rl/if_rlreg.h> /* * Various supported device vendors/types and their names. diff --git a/sys/pci/if_rlreg.h b/sys/dev/rl/if_rlreg.h index b0de60f..5a5c5f5 100644 --- a/sys/pci/if_rlreg.h +++ b/sys/dev/rl/if_rlreg.h @@ -195,6 +195,7 @@ #define RL_HWREV_8168G 0x4C000000 #define RL_HWREV_8168EP 0x50000000 #define RL_HWREV_8168GU 0x50800000 +#define RL_HWREV_8168H 0x54000000 #define RL_HWREV_8411B 0x5C800000 #define RL_HWREV_8139 0x60000000 #define RL_HWREV_8139A 0x70000000 @@ -930,8 +931,7 @@ struct rl_softc { #define RL_FLAG_CMDSTOP_WAIT_TXQ 0x00008000 #define RL_FLAG_WOL_MANLINK 0x00010000 #define RL_FLAG_EARLYOFF 0x00020000 -#define RL_FLAG_EARLYOFFV2 0x00040000 -#define RL_FLAG_RXDV_GATED 0x00080000 +#define RL_FLAG_8168G_PLUS 0x00040000 #define RL_FLAG_PCIE 0x40000000 #define RL_FLAG_LINK 0x80000000 }; diff --git a/sys/dev/usb/net/if_urndis.c b/sys/dev/usb/net/if_urndis.c index 6509e78..5d2a637 100644 --- a/sys/dev/usb/net/if_urndis.c +++ b/sys/dev/usb/net/if_urndis.c @@ -78,12 +78,20 @@ static uether_fn_t urndis_start; static uether_fn_t urndis_setmulti; static uether_fn_t urndis_setpromisc; -static uint32_t urndis_ctrl_query(struct urndis_softc *, uint32_t, const void **, uint16_t *); -static uint32_t urndis_ctrl_set(struct urndis_softc *, uint32_t, struct urndis_set_req *, uint16_t); -static uint32_t urndis_ctrl_handle_init(struct urndis_softc *, const struct urndis_comp_hdr *); -static uint32_t urndis_ctrl_handle_query(struct urndis_softc *, const struct urndis_comp_hdr *, const void **, uint16_t *); -static uint32_t urndis_ctrl_handle_reset(struct urndis_softc *, const struct urndis_comp_hdr *); -static uint32_t urndis_ctrl_init(struct urndis_softc *); +static uint32_t urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid, + struct urndis_query_req *msg, uint16_t len, + const void **rbuf, uint16_t *rbufsz); +static uint32_t urndis_ctrl_set(struct urndis_softc *sc, uint32_t oid, + struct urndis_set_req *msg, uint16_t len); +static uint32_t urndis_ctrl_handle_init(struct urndis_softc *sc, + const struct urndis_comp_hdr *hdr); +static uint32_t urndis_ctrl_handle_query(struct urndis_softc *sc, + const struct urndis_comp_hdr *hdr, const void **buf, + uint16_t *bufsz); +static uint32_t urndis_ctrl_handle_reset(struct urndis_softc *sc, + const struct urndis_comp_hdr *hdr); +static uint32_t urndis_ctrl_init(struct urndis_softc *sc); +static uint32_t urndis_ctrl_halt(struct urndis_softc *sc); #ifdef USB_DEBUG static int urndis_debug = 0; @@ -93,7 +101,6 @@ SYSCTL_INT(_hw_usb_urndis, OID_AUTO, debug, CTLFLAG_RW, &urndis_debug, 0, #endif static const struct usb_config urndis_config[URNDIS_N_TRANSFER] = { - [URNDIS_BULK_RX] = { .type = UE_BULK, .endpoint = UE_ADDR_ANY, @@ -154,7 +161,7 @@ static driver_t urndis_driver = { static devclass_t urndis_devclass; -DRIVER_MODULE(urndis, uhub, urndis_driver, urndis_devclass, NULL, 0); +DRIVER_MODULE(urndis, uhub, urndis_driver, urndis_devclass, NULL, NULL); MODULE_VERSION(urndis, 1); MODULE_DEPEND(urndis, uether, 1, 1, 1); MODULE_DEPEND(urndis, usb, 1, 1, 1); @@ -171,6 +178,9 @@ static const struct usb_ether_methods urndis_ue_methods = { static const STRUCT_USB_HOST_ID urndis_host_devs[] = { /* Generic RNDIS class match */ + {USB_IFACE_CLASS(UICLASS_CDC), + USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), + USB_IFACE_PROTOCOL(0xff)}, {USB_IFACE_CLASS(UICLASS_WIRELESS), USB_IFACE_SUBCLASS(UISUBCLASS_RF), USB_IFACE_PROTOCOL(UIPROTO_RNDIS)}, {USB_IFACE_CLASS(UICLASS_IAD), USB_IFACE_SUBCLASS(UISUBCLASS_SYNC), @@ -192,21 +202,27 @@ urndis_probe(device_t dev) static void urndis_attach_post(struct usb_ether *ue) { + /* no-op */ - return; } static int urndis_attach(device_t dev) { + static struct { + union { + struct urndis_query_req query; + struct urndis_set_req set; + } hdr; + union { + uint8_t eaddr[ETHER_ADDR_LEN]; + uint32_t filter; + } ibuf; + } msg; struct urndis_softc *sc = device_get_softc(dev); struct usb_ether *ue = &sc->sc_ue; struct usb_attach_arg *uaa = device_get_ivars(dev); struct usb_cdc_cm_descriptor *cmd; - struct { - struct urndis_set_req hdr; - uint32_t filter; - } msg_filter; const void *buf; uint16_t bufsz; uint8_t iface_index[2] = { uaa->info.bIfaceIndex + 1, uaa->info.bIfaceIndex }; @@ -228,9 +244,7 @@ urndis_attach(device_t dev) mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); /* scan the alternate settings looking for a valid one */ - for (i = 0; i != 32; i++) { - error = usbd_set_alt_interface_index(uaa->device, iface_index[0], i); @@ -244,16 +258,27 @@ urndis_attach(device_t dev) if (error == 0) break; } - if ((error != 0) || (i == 32)) { - device_printf(dev, "No valid alternate " - "setting found\n"); + device_printf(dev, "No valid alternate setting found\n"); goto detach; } + + /* Initialize device - must be done before even querying it */ URNDIS_LOCK(sc); - error = urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS, &buf, &bufsz); + error = urndis_ctrl_init(sc); URNDIS_UNLOCK(sc); + if (error != (int)RNDIS_STATUS_SUCCESS) { + device_printf(dev, "Unable to initialize hardware\n"); + goto detach; + } + /* Determine MAC address */ + memset(msg.ibuf.eaddr, 0, sizeof(msg.ibuf.eaddr)); + URNDIS_LOCK(sc); + error = urndis_ctrl_query(sc, OID_802_3_PERMANENT_ADDRESS, + &msg.hdr.query, sizeof(msg.hdr.query) + sizeof(msg.ibuf.eaddr), + &buf, &bufsz); + URNDIS_UNLOCK(sc); if (error != (int)RNDIS_STATUS_SUCCESS) { device_printf(dev, "Unable to get hardware address\n"); goto detach; @@ -267,17 +292,16 @@ urndis_attach(device_t dev) /* Initialize packet filter */ sc->sc_filter = RNDIS_PACKET_TYPE_BROADCAST | RNDIS_PACKET_TYPE_ALL_MULTICAST; - msg_filter.filter = htole32(sc->sc_filter); - + msg.ibuf.filter = htole32(sc->sc_filter); URNDIS_LOCK(sc); error = urndis_ctrl_set(sc, OID_GEN_CURRENT_PACKET_FILTER, - &msg_filter.hdr, sizeof(msg_filter)); + &msg.hdr.set, sizeof(msg.hdr.set) + sizeof(msg.ibuf.filter)); URNDIS_UNLOCK(sc); - if (error != (int)RNDIS_STATUS_SUCCESS) { device_printf(dev, "Unable to set data filters\n"); goto detach; } + ue->ue_sc = sc; ue->ue_dev = dev; ue->ue_udev = uaa->device; @@ -298,7 +322,7 @@ urndis_attach(device_t dev) return (0); /* success */ detach: - urndis_detach(dev); + (void)urndis_detach(dev); return (ENXIO); /* failure */ } @@ -313,6 +337,10 @@ urndis_detach(device_t dev) uether_ifdetach(ue); + URNDIS_LOCK(sc); + (void)urndis_ctrl_halt(sc); + URNDIS_UNLOCK(sc); + mtx_destroy(&sc->sc_mtx); return (0); @@ -340,8 +368,6 @@ urndis_init(struct usb_ether *ue) ifp->if_drv_flags |= IFF_DRV_RUNNING; - urndis_ctrl_init(sc); - /* stall data write direction, which depends on USB mode */ usbd_xfer_set_stall(sc->sc_xfer[URNDIS_BULK_TX]); @@ -369,20 +395,21 @@ urndis_stop(struct usb_ether *ue) static void urndis_setmulti(struct usb_ether *ue) { + /* no-op */ - return; } static void urndis_setpromisc(struct usb_ether *ue) { + /* no-op */ - return; } static int urndis_suspend(device_t dev) { + device_printf(dev, "Suspending\n"); return (0); } @@ -390,6 +417,7 @@ urndis_suspend(device_t dev) static int urndis_resume(device_t dev) { + device_printf(dev, "Resuming\n"); return (0); } @@ -416,8 +444,8 @@ urndis_ctrl_send(struct urndis_softc *sc, void *buf, uint16_t len) { usb_error_t err; - err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS, - sc->sc_ifaceno_ctl, 0, buf, len); + err = urndis_ctrl_msg(sc, UT_WRITE_CLASS_INTERFACE, + UCDC_SEND_ENCAPSULATED_COMMAND, sc->sc_ifaceno_ctl, 0, buf, len); DPRINTF("%s\n", usbd_errstr(err)); @@ -430,8 +458,9 @@ urndis_ctrl_recv(struct urndis_softc *sc) struct urndis_comp_hdr *hdr; usb_error_t err; - err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE, - sc->sc_ifaceno_ctl, 0, sc->sc_response_buf, RNDIS_RESPONSE_LEN); + err = urndis_ctrl_msg(sc, UT_READ_CLASS_INTERFACE, + UCDC_GET_ENCAPSULATED_RESPONSE, sc->sc_ifaceno_ctl, 0, + sc->sc_response_buf, RNDIS_RESPONSE_LEN); if (err != USB_ERR_NORMAL_COMPLETION) return (NULL); @@ -480,7 +509,8 @@ urndis_ctrl_handle(struct urndis_softc *sc, struct urndis_comp_hdr *hdr, break; default: - DPRINTF("ctrl message error: unknown event 0x%x\n", + device_printf(sc->sc_ue.ue_dev, + "ctrl message error: unknown event 0x%x\n", le32toh(hdr->rm_type)); rval = RNDIS_STATUS_FAILURE; break; @@ -548,10 +578,8 @@ urndis_ctrl_handle_query(struct urndis_softc *sc, le32toh(msg->rm_infobuflen), le32toh(msg->rm_infobufoffset)); - if (buf != NULL && bufsz != NULL) { - *buf = NULL; - *bufsz = 0; - } + *buf = NULL; + *bufsz = 0; if (le32toh(msg->rm_status) != RNDIS_STATUS_SUCCESS) { DPRINTF("query failed 0x%x\n", le32toh(msg->rm_status)); return (le32toh(msg->rm_status)); @@ -571,10 +599,10 @@ urndis_ctrl_handle_query(struct urndis_softc *sc, le32toh(msg->rm_len)); return (RNDIS_STATUS_FAILURE); } - if (buf != NULL && bufsz != NULL) { - *buf = ((const uint8_t *)msg) + RNDIS_HEADER_OFFSET + le32toh(msg->rm_infobufoffset); - *bufsz = le32toh(msg->rm_infobuflen); - } + *buf = ((const uint8_t *)msg) + RNDIS_HEADER_OFFSET + + le32toh(msg->rm_infobufoffset); + *bufsz = le32toh(msg->rm_infobuflen); + return (le32toh(msg->rm_status)); } @@ -627,7 +655,7 @@ urndis_ctrl_init(struct urndis_softc *sc) msg.rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG); msg.rm_len = htole32(sizeof(msg)); - msg.rm_rid = htole32(0); + msg.rm_rid = 0; msg.rm_ver_major = htole32(1); msg.rm_ver_minor = htole32(1); msg.rm_max_xfersz = htole32(RNDIS_RX_MAXLEN); @@ -656,7 +684,6 @@ urndis_ctrl_init(struct urndis_softc *sc) return (rval); } -#if 0 static uint32_t urndis_ctrl_halt(struct urndis_softc *sc) { @@ -675,39 +702,48 @@ urndis_ctrl_halt(struct urndis_softc *sc) rval = urndis_ctrl_send(sc, &msg, sizeof(msg)); if (rval != RNDIS_STATUS_SUCCESS) - printf("halt failed\n"); + DPRINTF("halt failed\n"); return (rval); } -#endif - +/* + * NB: Querying a device has the requirment of using an input buffer the size + * of the expected reply or larger, except for variably sized replies. + */ static uint32_t -urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid, const void **rbuf, uint16_t *rbufsz) +urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid, + struct urndis_query_req *msg, uint16_t len, const void **rbuf, + uint16_t *rbufsz) { - struct urndis_query_req msg; - uint32_t rval; struct urndis_comp_hdr *hdr; + uint32_t datalen, rval; - msg.rm_type = htole32(REMOTE_NDIS_QUERY_MSG); - msg.rm_len = htole32(sizeof(msg)); - msg.rm_rid = 0; /* XXX */ - msg.rm_oid = htole32(oid); - msg.rm_infobuflen = htole32(0); - msg.rm_infobufoffset = 0; - msg.rm_devicevchdl = 0; + msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG); + msg->rm_len = htole32(len); + msg->rm_rid = 0; /* XXX */ + msg->rm_oid = htole32(oid); + datalen = len - sizeof(*msg); + msg->rm_infobuflen = htole32(datalen); + if (datalen != 0) { + msg->rm_infobufoffset = htole32(sizeof(*msg) - + RNDIS_HEADER_OFFSET); + } else { + msg->rm_infobufoffset = 0; + } + msg->rm_devicevchdl = 0; DPRINTF("type %u len %u rid %u oid 0x%x " "infobuflen %u infobufoffset %u devicevchdl %u\n", - le32toh(msg.rm_type), - le32toh(msg.rm_len), - le32toh(msg.rm_rid), - le32toh(msg.rm_oid), - le32toh(msg.rm_infobuflen), - le32toh(msg.rm_infobufoffset), - le32toh(msg.rm_devicevchdl)); + le32toh(msg->rm_type), + le32toh(msg->rm_len), + le32toh(msg->rm_rid), + le32toh(msg->rm_oid), + le32toh(msg->rm_infobuflen), + le32toh(msg->rm_infobufoffset), + le32toh(msg->rm_devicevchdl)); - rval = urndis_ctrl_send(sc, &msg, sizeof(msg)); + rval = urndis_ctrl_send(sc, msg, len); if (rval != RNDIS_STATUS_SUCCESS) { DPRINTF("query failed\n"); @@ -723,19 +759,21 @@ urndis_ctrl_query(struct urndis_softc *sc, uint32_t oid, const void **rbuf, uint } static uint32_t -urndis_ctrl_set(struct urndis_softc *sc, uint32_t oid, struct urndis_set_req *msg, uint16_t len) +urndis_ctrl_set(struct urndis_softc *sc, uint32_t oid, + struct urndis_set_req *msg, uint16_t len) { struct urndis_comp_hdr *hdr; - uint32_t rval; - uint32_t datalen = len - sizeof(*msg); + uint32_t datalen, rval; msg->rm_type = htole32(REMOTE_NDIS_SET_MSG); msg->rm_len = htole32(len); msg->rm_rid = 0; /* XXX */ msg->rm_oid = htole32(oid); + datalen = len - sizeof(*msg); msg->rm_infobuflen = htole32(datalen); if (datalen != 0) { - msg->rm_infobufoffset = htole32(sizeof(*msg) - RNDIS_HEADER_OFFSET); + msg->rm_infobufoffset = htole32(sizeof(*msg) - + RNDIS_HEADER_OFFSET); } else { msg->rm_infobufoffset = 0; } @@ -782,13 +820,11 @@ urndis_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(1, "received %u bytes in %u frames\n", actlen, aframes); for (offset = 0; actlen >= (uint32_t)sizeof(msg);) { - /* copy out header */ usbd_copy_out(pc, offset, &msg, sizeof(msg)); @@ -930,7 +966,7 @@ tr_setup: usbd_xfer_set_frame_offset(xfer, x * RNDIS_TX_MAXLEN, x); - next_pkt: +next_pkt: IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) diff --git a/sys/dev/vt/colors/vt_termcolors.c b/sys/dev/vt/colors/vt_termcolors.c index d8a5909..5075619 100644 --- a/sys/dev/vt/colors/vt_termcolors.c +++ b/sys/dev/vt/colors/vt_termcolors.c @@ -25,15 +25,16 @@ * 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 <dev/vt/colors/vt_termcolors.h> -static struct { +static const struct { unsigned char r; /* Red percentage value. */ unsigned char g; /* Green percentage value. */ unsigned char b; /* Blue percentage value. */ @@ -68,8 +69,8 @@ static const int cons_to_vga_colors[16] = { }; int -vt_generate_cons_palette(uint32_t *palette, int format, uint32_t rmax, int roffset, - uint32_t gmax, int goffset, uint32_t bmax, int boffset) +vt_generate_cons_palette(uint32_t *palette, int format, uint32_t rmax, + int roffset, uint32_t gmax, int goffset, uint32_t bmax, int boffset) { int i; diff --git a/sys/modules/hyperv/netvsc/Makefile b/sys/modules/hyperv/netvsc/Makefile index 472be16..857df82 100644 --- a/sys/modules/hyperv/netvsc/Makefile +++ b/sys/modules/hyperv/netvsc/Makefile @@ -6,7 +6,7 @@ KMOD= hv_netvsc SRCS= hv_net_vsc.c \ hv_netvsc_drv_freebsd.c \ hv_rndis_filter.c -SRCS+= bus_if.h device_if.h +SRCS+= bus_if.h device_if.h opt_inet.h opt_inet6.h CFLAGS+= -I${.CURDIR}/../../../dev/hyperv/netvsc diff --git a/sys/modules/rl/Makefile b/sys/modules/rl/Makefile index e846579..16046ad 100644 --- a/sys/modules/rl/Makefile +++ b/sys/modules/rl/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../pci +.PATH: ${.CURDIR}/../../dev/rl KMOD= if_rl SRCS= if_rl.c device_if.h bus_if.h pci_if.h diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c index e681bcd..693b3ac 100644 --- a/sys/netgraph/ng_base.c +++ b/sys/netgraph/ng_base.c @@ -2971,7 +2971,7 @@ uma_zone_t ng_qzone; uma_zone_t ng_qdzone; static int numthreads = 0; /* number of queue threads */ static int maxalloc = 4096;/* limit the damage of a leak */ -static int maxdata = 512; /* limit the damage of a DoS */ +static int maxdata = 4096; /* limit the damage of a DoS */ TUNABLE_INT("net.graph.threads", &numthreads); SYSCTL_INT(_net_graph, OID_AUTO, threads, CTLFLAG_RDTUN, &numthreads, diff --git a/sys/netinet/tcp.h b/sys/netinet/tcp.h index fb2f810..7e3a1a3 100644 --- a/sys/netinet/tcp.h +++ b/sys/netinet/tcp.h @@ -97,6 +97,10 @@ struct tcphdr { #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_SIGNATURE 19 /* Keyed MD5: RFC 2385 */ #define TCPOLEN_SIGNATURE 18 +#define TCPOPT_FAST_OPEN 34 +#define TCPOLEN_FAST_OPEN_EMPTY 2 +#define TCPOLEN_FAST_OPEN_MIN 6 +#define TCPOLEN_FAST_OPEN_MAX 18 /* Miscellaneous constants */ #define MAX_SACK_BLKS 6 /* Max # SACK blocks stored at receiver side */ @@ -165,6 +169,7 @@ struct tcphdr { #define TCP_KEEPIDLE 256 /* L,N,X start keeplives after this period */ #define TCP_KEEPINTVL 512 /* L,N interval between keepalives */ #define TCP_KEEPCNT 1024 /* L,N number of keepalives before close */ +#define TCP_FASTOPEN 1025 /* enable TFO / was created via TFO */ /* Start of reserved space for third-party user-settable options. */ #define TCP_VENDOR SO_VENDOR diff --git a/sys/netinet/tcp_fastopen.c b/sys/netinet/tcp_fastopen.c new file mode 100644 index 0000000..482320e --- /dev/null +++ b/sys/netinet/tcp_fastopen.c @@ -0,0 +1,442 @@ +/*- + * Copyright (c) 2015 Patrick Kelsey + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is a server-side implementation of TCP Fast Open (TFO) [RFC7413]. + * + * This implementation is currently considered to be experimental and is not + * included in kernel builds by default. To include this code, add the + * following line to your kernel config: + * + * options TCP_RFC7413 + * + * The generated TFO cookies are the 64-bit output of + * SipHash24(<16-byte-key><client-ip>). Multiple concurrent valid keys are + * supported so that time-based rolling cookie invalidation policies can be + * implemented in the system. The default number of concurrent keys is 2. + * This can be adjusted in the kernel config as follows: + * + * options TCP_RFC7413_MAX_KEYS=<num-keys> + * + * + * The following TFO-specific sysctls are defined: + * + * net.inet.tcp.fastopen.acceptany (RW, default 0) + * When non-zero, all client-supplied TFO cookies will be considered to + * be valid. + * + * net.inet.tcp.fastopen.autokey (RW, default 120) + * When this and net.inet.tcp.fastopen.enabled are non-zero, a new key + * will be automatically generated after this many seconds. + * + * net.inet.tcp.fastopen.enabled (RW, default 0) + * When zero, no new TFO connections can be created. On the transition + * from enabled to disabled, all installed keys are removed. On the + * transition from disabled to enabled, if net.inet.tcp.fastopen.autokey + * is non-zero and there are no keys installed, a new key will be + * generated immediately. The transition from enabled to disabled does + * not affect any TFO connections in progress; it only prevents new ones + * from being made. + * + * net.inet.tcp.fastopen.keylen (RO) + * The key length in bytes. + * + * net.inet.tcp.fastopen.maxkeys (RO) + * The maximum number of keys supported. + * + * net.inet.tcp.fastopen.numkeys (RO) + * The current number of keys installed. + * + * net.inet.tcp.fastopen.setkey (WO) + * Install a new key by writing net.inet.tcp.fastopen.keylen bytes to this + * sysctl. + * + * + * In order for TFO connections to be created via a listen socket, that + * socket must have the TCP_FASTOPEN socket option set on it. This option + * can be set on the socket either before or after the listen() is invoked. + * Clearing this option on a listen socket after it has been set has no + * effect on existing TFO connections or TFO connections in progress; it + * only prevents new TFO connections from being made. + * + * For passively-created sockets, the TCP_FASTOPEN socket option can be + * queried to determine whether the connection was established using TFO. + * Note that connections that are established via a TFO SYN, but that fall + * back to using a non-TFO SYN|ACK will have the TCP_FASTOPEN socket option + * set. + * + * Per the RFC, this implementation limits the number of TFO connections + * that can be in the SYN_RECEIVED state on a per listen-socket basis. + * Whenever this limit is exceeded, requests for new TFO connections are + * serviced as non-TFO requests. Without such a limit, given a valid TFO + * cookie, an attacker could keep the listen queue in an overflow condition + * using a TFO SYN flood. This implementation sets the limit at half the + * configured listen backlog. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_inet.h" + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/limits.h> +#include <sys/lock.h> +#include <sys/rmlock.h> +#include <sys/socketvar.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +#include <crypto/siphash/siphash.h> + +#include <net/vnet.h> + +#include <netinet/in.h> +#include <netinet/in_pcb.h> +#include <netinet/tcp_fastopen.h> +#include <netinet/tcp_var.h> + + +#define TCP_FASTOPEN_KEY_LEN SIPHASH_KEY_LENGTH + +#if !defined(TCP_RFC7413_MAX_KEYS) || (TCP_RFC7413_MAX_KEYS < 1) +#define TCP_FASTOPEN_MAX_KEYS 2 +#else +#define TCP_FASTOPEN_MAX_KEYS TCP_RFC7413_MAX_KEYS +#endif + +struct tcp_fastopen_keylist { + unsigned int newest; + uint8_t key[TCP_FASTOPEN_MAX_KEYS][TCP_FASTOPEN_KEY_LEN]; +}; + +struct tcp_fastopen_callout { + struct callout c; + struct vnet *v; +}; + +SYSCTL_NODE(_net_inet_tcp, OID_AUTO, fastopen, CTLFLAG_RW, 0, "TCP Fast Open"); + +static VNET_DEFINE(int, tcp_fastopen_acceptany) = 0; +#define V_tcp_fastopen_acceptany VNET(tcp_fastopen_acceptany) +SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, acceptany, + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_fastopen_acceptany), 0, + "Accept any non-empty cookie"); + +static VNET_DEFINE(unsigned int, tcp_fastopen_autokey) = 120; +#define V_tcp_fastopen_autokey VNET(tcp_fastopen_autokey) +static int sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, autokey, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0, + &sysctl_net_inet_tcp_fastopen_autokey, "IU", + "Number of seconds between auto-generation of a new key; zero disables"); + +VNET_DEFINE(unsigned int, tcp_fastopen_enabled) = 0; +static int sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, enabled, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0, + &sysctl_net_inet_tcp_fastopen_enabled, "IU", + "Enable/disable TCP Fast Open processing"); + +SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, keylen, + CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_KEY_LEN, + "Key length in bytes"); + +SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, maxkeys, + CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_KEYS, + "Maximum number of keys supported"); + +static VNET_DEFINE(unsigned int, tcp_fastopen_numkeys) = 0; +#define V_tcp_fastopen_numkeys VNET(tcp_fastopen_numkeys) +SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numkeys, + CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numkeys), 0, + "Number of keys installed"); + +static int sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setkey, + CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0, + &sysctl_net_inet_tcp_fastopen_setkey, "", + "Install a new key"); + +static VNET_DEFINE(struct rmlock, tcp_fastopen_keylock); +#define V_tcp_fastopen_keylock VNET(tcp_fastopen_keylock) + +#define TCP_FASTOPEN_KEYS_RLOCK(t) rm_rlock(&V_tcp_fastopen_keylock, (t)) +#define TCP_FASTOPEN_KEYS_RUNLOCK(t) rm_runlock(&V_tcp_fastopen_keylock, (t)) +#define TCP_FASTOPEN_KEYS_WLOCK() rm_wlock(&V_tcp_fastopen_keylock) +#define TCP_FASTOPEN_KEYS_WUNLOCK() rm_wunlock(&V_tcp_fastopen_keylock) + +static VNET_DEFINE(struct tcp_fastopen_keylist, tcp_fastopen_keys); +#define V_tcp_fastopen_keys VNET(tcp_fastopen_keys) + +static VNET_DEFINE(struct tcp_fastopen_callout, tcp_fastopen_autokey_ctx); +#define V_tcp_fastopen_autokey_ctx VNET(tcp_fastopen_autokey_ctx) + +static VNET_DEFINE(uma_zone_t, counter_zone); +#define V_counter_zone VNET(counter_zone) + +void +tcp_fastopen_init(void) +{ + V_counter_zone = uma_zcreate("tfo", sizeof(unsigned int), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); + rm_init(&V_tcp_fastopen_keylock, "tfo_keylock"); + callout_init_rm(&V_tcp_fastopen_autokey_ctx.c, + &V_tcp_fastopen_keylock, 0); + V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1; +} + +void +tcp_fastopen_destroy(void) +{ + callout_drain(&V_tcp_fastopen_autokey_ctx.c); + rm_destroy(&V_tcp_fastopen_keylock); + uma_zdestroy(V_counter_zone); +} + +unsigned int * +tcp_fastopen_alloc_counter(void) +{ + unsigned int *counter; + counter = uma_zalloc(V_counter_zone, M_NOWAIT); + if (counter) + *counter = 1; + return (counter); +} + +void +tcp_fastopen_decrement_counter(unsigned int *counter) +{ + if (*counter == 1) + uma_zfree(V_counter_zone, counter); + else + atomic_subtract_int(counter, 1); +} + +static void +tcp_fastopen_addkey_locked(uint8_t *key) +{ + + V_tcp_fastopen_keys.newest++; + if (V_tcp_fastopen_keys.newest == TCP_FASTOPEN_MAX_KEYS) + V_tcp_fastopen_keys.newest = 0; + memcpy(V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest], key, + TCP_FASTOPEN_KEY_LEN); + if (V_tcp_fastopen_numkeys < TCP_FASTOPEN_MAX_KEYS) + V_tcp_fastopen_numkeys++; +} + +static void +tcp_fastopen_autokey_locked(void) +{ + uint8_t newkey[TCP_FASTOPEN_KEY_LEN]; + + arc4rand(newkey, TCP_FASTOPEN_KEY_LEN, 0); + tcp_fastopen_addkey_locked(newkey); +} + +static void +tcp_fastopen_autokey_callout(void *arg) +{ + struct tcp_fastopen_callout *ctx = arg; + + CURVNET_SET(ctx->v); + tcp_fastopen_autokey_locked(); + callout_reset(&ctx->c, V_tcp_fastopen_autokey * hz, + tcp_fastopen_autokey_callout, ctx); + CURVNET_RESTORE(); +} + + +static uint64_t +tcp_fastopen_make_cookie(uint8_t key[SIPHASH_KEY_LENGTH], struct in_conninfo *inc) +{ + SIPHASH_CTX ctx; + uint64_t siphash; + + SipHash24_Init(&ctx); + SipHash_SetKey(&ctx, key); + switch (inc->inc_flags & INC_ISIPV6) { +#ifdef INET + case 0: + SipHash_Update(&ctx, &inc->inc_faddr, sizeof(inc->inc_faddr)); + break; +#endif +#ifdef INET6 + case INC_ISIPV6: + SipHash_Update(&ctx, &inc->inc6_faddr, sizeof(inc->inc6_faddr)); + break; +#endif + } + SipHash_Final((u_int8_t *)&siphash, &ctx); + + return (siphash); +} + + +/* + * Return values: + * -1 the cookie is invalid and no valid cookie is available + * 0 the cookie is invalid and the latest cookie has been returned + * 1 the cookie is valid and the latest cookie has been returned + */ +int +tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie, + unsigned int len, uint64_t *latest_cookie) +{ + struct rm_priotracker tracker; + unsigned int i, key_index; + uint64_t cur_cookie; + + if (V_tcp_fastopen_acceptany) { + *latest_cookie = 0; + return (1); + } + + if (len != TCP_FASTOPEN_COOKIE_LEN) { + if (V_tcp_fastopen_numkeys > 0) { + *latest_cookie = + tcp_fastopen_make_cookie( + V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest], + inc); + return (0); + } + return (-1); + } + + /* + * Check against each available key, from newest to oldest. + */ + TCP_FASTOPEN_KEYS_RLOCK(&tracker); + key_index = V_tcp_fastopen_keys.newest; + for (i = 0; i < V_tcp_fastopen_numkeys; i++) { + cur_cookie = + tcp_fastopen_make_cookie(V_tcp_fastopen_keys.key[key_index], + inc); + if (i == 0) + *latest_cookie = cur_cookie; + if (memcmp(cookie, &cur_cookie, TCP_FASTOPEN_COOKIE_LEN) == 0) { + TCP_FASTOPEN_KEYS_RUNLOCK(&tracker); + return (1); + } + if (key_index == 0) + key_index = TCP_FASTOPEN_MAX_KEYS - 1; + else + key_index--; + } + TCP_FASTOPEN_KEYS_RUNLOCK(&tracker); + + return (0); +} + +static int +sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS) +{ + int error; + unsigned int new; + + new = V_tcp_fastopen_autokey; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error == 0 && req->newptr) { + if (new > (INT_MAX / hz)) + return (EINVAL); + + TCP_FASTOPEN_KEYS_WLOCK(); + if (V_tcp_fastopen_enabled) { + if (V_tcp_fastopen_autokey && !new) + callout_stop(&V_tcp_fastopen_autokey_ctx.c); + else if (new) + callout_reset(&V_tcp_fastopen_autokey_ctx.c, + new * hz, tcp_fastopen_autokey_callout, + &V_tcp_fastopen_autokey_ctx); + } + V_tcp_fastopen_autokey = new; + TCP_FASTOPEN_KEYS_WUNLOCK(); + } + + return (error); +} + +static int +sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS) +{ + int error; + unsigned int new; + + new = V_tcp_fastopen_enabled; + error = sysctl_handle_int(oidp, &new, 0, req); + if (error == 0 && req->newptr) { + if (V_tcp_fastopen_enabled && !new) { + /* enabled -> disabled */ + TCP_FASTOPEN_KEYS_WLOCK(); + V_tcp_fastopen_numkeys = 0; + V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1; + if (V_tcp_fastopen_autokey) + callout_stop(&V_tcp_fastopen_autokey_ctx.c); + V_tcp_fastopen_enabled = 0; + TCP_FASTOPEN_KEYS_WUNLOCK(); + } else if (!V_tcp_fastopen_enabled && new) { + /* disabled -> enabled */ + TCP_FASTOPEN_KEYS_WLOCK(); + if (V_tcp_fastopen_autokey && + (V_tcp_fastopen_numkeys == 0)) { + tcp_fastopen_autokey_locked(); + callout_reset(&V_tcp_fastopen_autokey_ctx.c, + V_tcp_fastopen_autokey * hz, + tcp_fastopen_autokey_callout, + &V_tcp_fastopen_autokey_ctx); + } + V_tcp_fastopen_enabled = 1; + TCP_FASTOPEN_KEYS_WUNLOCK(); + } + } + return (error); +} + +static int +sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS) +{ + int error; + uint8_t newkey[TCP_FASTOPEN_KEY_LEN]; + + if (req->oldptr != NULL || req->oldlen != 0) + return (EINVAL); + if (req->newptr == NULL) + return (EPERM); + if (req->newlen != sizeof(newkey)) + return (EINVAL); + error = SYSCTL_IN(req, newkey, sizeof(newkey)); + if (error) + return (error); + + TCP_FASTOPEN_KEYS_WLOCK(); + tcp_fastopen_addkey_locked(newkey); + TCP_FASTOPEN_KEYS_WUNLOCK(); + + return (0); +} diff --git a/sys/netinet/tcp_fastopen.h b/sys/netinet/tcp_fastopen.h new file mode 100644 index 0000000..c64ba2c --- /dev/null +++ b/sys/netinet/tcp_fastopen.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2015 Patrick Kelsey + * 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 _TCP_FASTOPEN_H_ +#define _TCP_FASTOPEN_H_ + +#ifdef _KERNEL + +#define TCP_FASTOPEN_COOKIE_LEN 8 /* tied to SipHash24 64-bit output */ + +VNET_DECLARE(unsigned int, tcp_fastopen_enabled); +#define V_tcp_fastopen_enabled VNET(tcp_fastopen_enabled) + +void tcp_fastopen_init(void); +void tcp_fastopen_destroy(void); +unsigned int *tcp_fastopen_alloc_counter(void); +void tcp_fastopen_decrement_counter(unsigned int *counter); +int tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie, + unsigned int len, uint64_t *latest_cookie); +#endif /* _KERNEL */ + +#endif /* _TCP_FASTOPEN_H_ */ diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 631cd2e..a59874e 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -98,6 +98,9 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_pcb.h> #include <netinet6/ip6_var.h> #include <netinet6/nd6.h> +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #include <netinet/tcp_timer.h> @@ -1070,6 +1073,9 @@ relocked: rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; } +#ifdef TCP_RFC7413 +new_tfo_socket: +#endif if (so == NULL) { /* * We completed the 3-way handshake @@ -1327,7 +1333,12 @@ relocked: (void *)tcp_saveipgen, &tcp_savetcp, 0); #endif tcp_dooptions(&to, optp, optlen, TO_SYN); +#ifdef TCP_RFC7413 + if (syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL)) + goto new_tfo_socket; +#else syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL); +#endif /* * Entry added to syncache and mbuf consumed. * Everything already unlocked by syncache_add(). @@ -1437,6 +1448,7 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, struct in_conninfo *inc; struct mbuf *mfree; struct tcpopt to; + int tfo_syn; #ifdef TCPDEBUG /* @@ -1876,6 +1888,28 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, rstreason = BANDLIM_RST_OPENPORT; goto dropwithreset; } +#ifdef TCP_RFC7413 + if (tp->t_flags & TF_FASTOPEN) { + /* + * When a TFO connection is in SYN_RECEIVED, the + * only valid packets are the initial SYN, a + * retransmit/copy of the initial SYN (possibly with + * a subset of the original data), a valid ACK, a + * FIN, or a RST. + */ + if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) { + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } else if (thflags & TH_SYN) { + /* non-initial SYN is ignored */ + if ((tcp_timer_active(tp, TT_DELACK) || + tcp_timer_active(tp, TT_REXMT))) + goto drop; + } else if (!(thflags & (TH_ACK|TH_FIN|TH_RST))) { + goto drop; + } + } +#endif break; /* @@ -2316,9 +2350,16 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, */ if ((thflags & TH_ACK) == 0) { if (tp->t_state == TCPS_SYN_RECEIVED || - (tp->t_flags & TF_NEEDSYN)) + (tp->t_flags & TF_NEEDSYN)) { +#ifdef TCP_RFC7413 + if (tp->t_state == TCPS_SYN_RECEIVED && + tp->t_flags & TF_FASTOPEN) { + tp->snd_wnd = tiwin; + cc_conn_init(tp); + } +#endif goto step6; - else if (tp->t_flags & TF_ACKNOW) + } else if (tp->t_flags & TF_ACKNOW) goto dropafterack; else goto drop; @@ -2357,7 +2398,27 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, tcp_state_change(tp, TCPS_ESTABLISHED); TCP_PROBE5(accept__established, NULL, tp, mtod(m, const char *), tp, th); - cc_conn_init(tp); +#ifdef TCP_RFC7413 + if (tp->t_tfo_pending) { + tcp_fastopen_decrement_counter(tp->t_tfo_pending); + tp->t_tfo_pending = NULL; + + /* + * Account for the ACK of our SYN prior to + * regular ACK processing below. + */ + tp->snd_una++; + } + /* + * TFO connections call cc_conn_init() during SYN + * processing. Calling it again here for such + * connections is not harmless as it would undo the + * snd_cwnd reduction that occurs when a TFO SYN|ACK + * is retransmitted. + */ + if (!(tp->t_flags & TF_FASTOPEN)) +#endif + cc_conn_init(tp); tcp_timer_activate(tp, TT_KEEP, TP_KEEPIDLE(tp)); } /* @@ -2888,9 +2949,12 @@ dodata: /* XXX */ * case PRU_RCVD). If a FIN has already been received on this * connection then we just ignore the text. */ - if ((tlen || (thflags & TH_FIN)) && + tfo_syn = ((tp->t_state == TCPS_SYN_RECEIVED) && + (tp->t_flags & TF_FASTOPEN)); + if ((tlen || (thflags & TH_FIN) || tfo_syn) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { tcp_seq save_start = th->th_seq; + m_adj(m, drop_hdrlen); /* delayed header drop */ /* * Insert segment which includes th into TCP reassembly queue @@ -2906,8 +2970,9 @@ dodata: /* XXX */ */ if (th->th_seq == tp->rcv_nxt && LIST_EMPTY(&tp->t_segq) && - TCPS_HAVEESTABLISHED(tp->t_state)) { - if (DELAY_ACK(tp, tlen)) + (TCPS_HAVEESTABLISHED(tp->t_state) || + tfo_syn)) { + if (DELAY_ACK(tp, tlen) || tfo_syn) tp->t_flags |= TF_DELACK; else tp->t_flags |= TF_ACKNOW; @@ -3260,6 +3325,21 @@ tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) to->to_sacks = cp + 2; TCPSTAT_INC(tcps_sack_rcv_blocks); break; +#ifdef TCP_RFC7413 + case TCPOPT_FAST_OPEN: + if ((optlen != TCPOLEN_FAST_OPEN_EMPTY) && + (optlen < TCPOLEN_FAST_OPEN_MIN) && + (optlen > TCPOLEN_FAST_OPEN_MAX)) + continue; + if (!(flags & TO_SYN)) + continue; + if (!V_tcp_fastopen_enabled) + continue; + to->to_flags |= TOF_FASTOPEN; + to->to_tfo_len = optlen - 2; + to->to_tfo_cookie = to->to_tfo_len ? cp + 2 : NULL; + break; +#endif default: continue; } diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index f1196e1..c7dc547 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -69,6 +69,9 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #endif +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #define TCPOUTFLAGS #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> @@ -202,6 +205,17 @@ tcp_output(struct tcpcb *tp) return (tcp_offload_output(tp)); #endif +#ifdef TCP_RFC7413 + /* + * For TFO connections in SYN_RECEIVED, only allow the initial + * SYN|ACK and those sent by the retransmit timer. + */ + if ((tp->t_flags & TF_FASTOPEN) && + (tp->t_state == TCPS_SYN_RECEIVED) && + SEQ_GT(tp->snd_max, tp->snd_una) && /* inital SYN|ACK sent */ + (tp->snd_nxt != tp->snd_una)) /* not a retransmit */ + return (0); +#endif /* * Determine length of data that should be transmitted, * and flags that will be used. @@ -387,6 +401,15 @@ after_sack_rexmit: if ((flags & TH_SYN) && SEQ_GT(tp->snd_nxt, tp->snd_una)) { if (tp->t_state != TCPS_SYN_RECEIVED) flags &= ~TH_SYN; +#ifdef TCP_RFC7413 + /* + * When sending additional segments following a TFO SYN|ACK, + * do not include the SYN bit. + */ + if ((tp->t_flags & TF_FASTOPEN) && + (tp->t_state == TCPS_SYN_RECEIVED)) + flags &= ~TH_SYN; +#endif off--, len++; } @@ -400,6 +423,17 @@ after_sack_rexmit: flags &= ~TH_FIN; } +#ifdef TCP_RFC7413 + /* + * When retransmitting SYN|ACK on a passively-created TFO socket, + * don't include data, as the presence of data may have caused the + * original SYN|ACK to have been dropped by a middlebox. + */ + if ((tp->t_flags & TF_FASTOPEN) && + (((tp->t_state == TCPS_SYN_RECEIVED) && (tp->t_rxtshift > 0)) || + (flags & TH_RST))) + len = 0; +#endif if (len <= 0) { /* * If FIN has been sent but not acked, @@ -718,6 +752,22 @@ send: tp->snd_nxt = tp->iss; to.to_mss = tcp_mssopt(&tp->t_inpcb->inp_inc); to.to_flags |= TOF_MSS; +#ifdef TCP_RFC7413 + /* + * Only include the TFO option on the first + * transmission of the SYN|ACK on a + * passively-created TFO socket, as the presence of + * the TFO option may have caused the original + * SYN|ACK to have been dropped by a middlebox. + */ + if ((tp->t_flags & TF_FASTOPEN) && + (tp->t_state == TCPS_SYN_RECEIVED) && + (tp->t_rxtshift == 0)) { + to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; + to.to_tfo_cookie = (u_char *)&tp->t_tfo_cookie; + to.to_flags |= TOF_FASTOPEN; + } +#endif } /* Window scaling. */ if ((flags & TH_SYN) && (tp->t_flags & TF_REQ_SCALE)) { @@ -997,7 +1047,7 @@ send: * give data to the user when a buffer fills or * a PUSH comes in.) */ - if (off + len == so->so_snd.sb_cc) + if ((off + len == so->so_snd.sb_cc) && !(flags & TH_SYN)) flags |= TH_PUSH; SOCKBUF_UNLOCK(&so->so_snd); } else { @@ -1694,6 +1744,25 @@ tcp_addoptions(struct tcpopt *to, u_char *optp) TCPSTAT_INC(tcps_sack_send_blocks); break; } +#ifdef TCP_RFC7413 + case TOF_FASTOPEN: + { + int total_len; + + /* XXX is there any point to aligning this option? */ + total_len = TCPOLEN_FAST_OPEN_EMPTY + to->to_tfo_len; + if (TCP_MAXOLEN - optlen < total_len) + continue; + *optp++ = TCPOPT_FAST_OPEN; + *optp++ = total_len; + if (to->to_tfo_len > 0) { + bcopy(to->to_tfo_cookie, optp, to->to_tfo_len); + optp += to->to_tfo_len; + } + optlen += total_len; + break; + } +#endif default: panic("%s: unknown TCP option type", __func__); break; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 7bdd573..3ce21a9 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -83,6 +83,9 @@ __FBSDID("$FreeBSD$"); #include <netinet6/nd6.h> #endif +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #include <netinet/tcp_timer.h> @@ -427,6 +430,10 @@ tcp_init(void) SHUTDOWN_PRI_DEFAULT); EVENTHANDLER_REGISTER(maxsockets_change, tcp_zone_change, NULL, EVENTHANDLER_PRI_ANY); + +#ifdef TCP_RFC7413 + tcp_fastopen_init(); +#endif } #ifdef VIMAGE @@ -434,6 +441,9 @@ void tcp_destroy(void) { +#ifdef TCP_RFC7413 + tcp_fastopen_destroy(); +#endif tcp_hc_destroy(); syncache_destroy(); tcp_tw_destroy(); @@ -1102,6 +1112,17 @@ tcp_close(struct tcpcb *tp) if (tp->t_state == TCPS_LISTEN) tcp_offload_listen_stop(tp); #endif +#ifdef TCP_RFC7413 + /* + * This releases the TFO pending counter resource for TFO listen + * sockets as well as passively-created TFO sockets that transition + * from SYN_RECEIVED to CLOSED. + */ + if (tp->t_tfo_pending) { + tcp_fastopen_decrement_counter(tp->t_tfo_pending); + tp->t_tfo_pending = NULL; + } +#endif in_pcbdrop(inp); TCPSTAT_INC(tcps_closed); KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL")); diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c index 9896788..8d2cc98 100644 --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -78,6 +78,9 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_pcb.h> #endif #include <netinet/tcp.h> +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #include <netinet/tcp_timer.h> @@ -1089,6 +1092,39 @@ failed: return (0); } +#ifdef TCP_RFC7413 +static void +syncache_tfo_expand(struct syncache *sc, struct socket **lsop, struct mbuf *m, + uint64_t response_cookie) +{ + struct inpcb *inp; + struct tcpcb *tp; + unsigned int *pending_counter; + + /* + * Global TCP locks are held because we manipulate the PCB lists + * and create a new socket. + */ + INP_INFO_RLOCK_ASSERT(&V_tcbinfo); + + pending_counter = intotcpcb(sotoinpcb(*lsop))->t_tfo_pending; + *lsop = syncache_socket(sc, *lsop, m); + if (*lsop == NULL) { + TCPSTAT_INC(tcps_sc_aborted); + atomic_subtract_int(pending_counter, 1); + } else { + inp = sotoinpcb(*lsop); + tp = intotcpcb(inp); + tp->t_flags |= TF_FASTOPEN; + tp->t_tfo_cookie = response_cookie; + tp->snd_max = tp->iss; + tp->snd_nxt = tp->iss; + tp->t_tfo_pending = pending_counter; + TCPSTAT_INC(tcps_sc_completed); + } +} +#endif /* TCP_RFC7413 */ + /* * Given a LISTEN socket and an inbound SYN request, add * this to the syn cache, and send back a segment: @@ -1101,8 +1137,15 @@ failed: * DoS attack, an attacker could send data which would eventually * consume all available buffer space if it were ACKed. By not ACKing * the data, we avoid this DoS scenario. + * + * The exception to the above is when a SYN with a valid TCP Fast Open (TFO) + * cookie is processed, V_tcp_fastopen_enabled set to true, and the + * TCP_FASTOPEN socket option is set. In this case, a new socket is created + * and returned via lsop, the mbuf is not freed so that tcp_input() can + * queue its data to the socket, and 1 is returned to indicate the + * TFO-socket-creation path was taken. */ -void +int syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, struct inpcb *inp, struct socket **lsop, struct mbuf *m, void *tod, void *todctx) @@ -1115,6 +1158,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, u_int ltflags; int win, sb_hiwat, ip_ttl, ip_tos; char *s; + int rv = 0; #ifdef INET6 int autoflowlabel = 0; #endif @@ -1123,6 +1167,11 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, #endif struct syncache scs; struct ucred *cred; +#ifdef TCP_RFC7413 + uint64_t tfo_response_cookie; + int tfo_cookie_valid = 0; + int tfo_response_cookie_valid = 0; +#endif INP_INFO_WLOCK_ASSERT(&V_tcbinfo); INP_WLOCK_ASSERT(inp); /* listen socket */ @@ -1148,6 +1197,29 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, sb_hiwat = so->so_rcv.sb_hiwat; ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE)); +#ifdef TCP_RFC7413 + if (V_tcp_fastopen_enabled && (tp->t_flags & TF_FASTOPEN) && + (tp->t_tfo_pending != NULL) && (to->to_flags & TOF_FASTOPEN)) { + /* + * Limit the number of pending TFO connections to + * approximately half of the queue limit. This prevents TFO + * SYN floods from starving the service by filling the + * listen queue with bogus TFO connections. + */ + if (atomic_fetchadd_int(tp->t_tfo_pending, 1) <= + (so->so_qlimit / 2)) { + int result; + + result = tcp_fastopen_check_cookie(inc, + to->to_tfo_cookie, to->to_tfo_len, + &tfo_response_cookie); + tfo_cookie_valid = (result > 0); + tfo_response_cookie_valid = (result >= 0); + } else + atomic_subtract_int(tp->t_tfo_pending, 1); + } +#endif + /* By the time we drop the lock these should no longer be used. */ so = NULL; tp = NULL; @@ -1160,9 +1232,16 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, } else mac_syncache_create(maclabel, inp); #endif +#ifdef TCP_RFC7413 + if (!tfo_cookie_valid) { + INP_WUNLOCK(inp); + INP_INFO_WUNLOCK(&V_tcbinfo); + } +#else INP_WUNLOCK(inp); INP_INFO_WUNLOCK(&V_tcbinfo); - +#endif + /* * Remember the IP options, if any. */ @@ -1190,6 +1269,12 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, sc = syncache_lookup(inc, &sch); /* returns locked entry */ SCH_LOCK_ASSERT(sch); if (sc != NULL) { +#ifdef TCP_RFC7413 + if (tfo_cookie_valid) { + INP_WUNLOCK(inp); + INP_INFO_WUNLOCK(&V_tcbinfo); + } +#endif TCPSTAT_INC(tcps_sc_dupsyn); if (ipopts) { /* @@ -1232,6 +1317,14 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, goto done; } +#ifdef TCP_RFC7413 + if (tfo_cookie_valid) { + bzero(&scs, sizeof(scs)); + sc = &scs; + goto skip_alloc; + } +#endif + sc = uma_zalloc(V_tcp_syncache.zone, M_NOWAIT | M_ZERO); if (sc == NULL) { /* @@ -1255,7 +1348,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, } } } - + +#ifdef TCP_RFC7413 +skip_alloc: + if (!tfo_cookie_valid && tfo_response_cookie_valid) + sc->sc_tfo_cookie = &tfo_response_cookie; +#endif + /* * Fill in the syncache values. */ @@ -1365,6 +1464,15 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, #endif SCH_UNLOCK(sch); +#ifdef TCP_RFC7413 + if (tfo_cookie_valid) { + syncache_tfo_expand(sc, lsop, m, tfo_response_cookie); + /* INP_WUNLOCK(inp) will be performed by the called */ + rv = 1; + goto tfo_done; + } +#endif + /* * Do a standard 3-way handshake. */ @@ -1382,17 +1490,20 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th, } done: + if (m) { + *lsop = NULL; + m_freem(m); + } +#ifdef TCP_RFC7413 +tfo_done: +#endif if (cred != NULL) crfree(cred); #ifdef MAC if (sc == &scs) mac_syncache_destroy(&maclabel); #endif - if (m) { - - *lsop = NULL; - m_freem(m); - } + return (rv); } static int @@ -1520,6 +1631,16 @@ syncache_respond(struct syncache *sc) if (sc->sc_flags & SCF_SIGNATURE) to.to_flags |= TOF_SIGNATURE; #endif + +#ifdef TCP_RFC7413 + if (sc->sc_tfo_cookie) { + to.to_flags |= TOF_FASTOPEN; + to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN; + to.to_tfo_cookie = sc->sc_tfo_cookie; + /* don't send cookie again when retransmitting response */ + sc->sc_tfo_cookie = NULL; + } +#endif optlen = tcp_addoptions(&to, (u_char *)(th + 1)); /* Adjust headers by option size. */ diff --git a/sys/netinet/tcp_syncache.h b/sys/netinet/tcp_syncache.h index fb9a6c6..d56afb6 100644 --- a/sys/netinet/tcp_syncache.h +++ b/sys/netinet/tcp_syncache.h @@ -41,7 +41,7 @@ void syncache_destroy(void); void syncache_unreach(struct in_conninfo *, struct tcphdr *); int syncache_expand(struct in_conninfo *, struct tcpopt *, struct tcphdr *, struct socket **, struct mbuf *); -void syncache_add(struct in_conninfo *, struct tcpopt *, +int syncache_add(struct in_conninfo *, struct tcpopt *, struct tcphdr *, struct inpcb *, struct socket **, struct mbuf *, void *, void *); void syncache_chkrst(struct in_conninfo *, struct tcphdr *); @@ -74,7 +74,9 @@ struct syncache { #endif struct label *sc_label; /* MAC label reference */ struct ucred *sc_cred; /* cred cache for jail checks */ - +#ifdef TCP_RFC7413 + void *sc_tfo_cookie; /* for TCP Fast Open response */ +#endif void *sc_pspare; /* TCP_SIGNATURE */ u_int32_t sc_spare[2]; /* UTO */ }; diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 3dc3a81..c66cb76 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -596,7 +596,8 @@ tcp_timer_rexmt(void * xtp) } else tp->t_flags &= ~TF_PREVVALID; TCPSTAT_INC(tcps_rexmttimeo); - if (tp->t_state == TCPS_SYN_SENT) + if ((tp->t_state == TCPS_SYN_SENT) || + (tp->t_state == TCPS_SYN_RECEIVED)) rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; else rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index c848306..1ccbf9a 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -79,6 +79,9 @@ __FBSDID("$FreeBSD$"); #include <netinet6/ip6_var.h> #include <netinet6/scope6_var.h> #endif +#ifdef TCP_RFC7413 +#include <netinet/tcp_fastopen.h> +#endif #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #include <netinet/tcp_timer.h> @@ -391,6 +394,10 @@ tcp_usr_listen(struct socket *so, int backlog, struct thread *td) } SOCK_UNLOCK(so); +#ifdef TCP_RFC7413 + if (tp->t_flags & TF_FASTOPEN) + tp->t_tfo_pending = tcp_fastopen_alloc_counter(); +#endif out: TCPDEBUG2(PRU_LISTEN); INP_WUNLOCK(inp); @@ -436,6 +443,10 @@ tcp6_usr_listen(struct socket *so, int backlog, struct thread *td) } SOCK_UNLOCK(so); +#ifdef TCP_RFC7413 + if (tp->t_flags & TF_FASTOPEN) + tp->t_tfo_pending = tcp_fastopen_alloc_counter(); +#endif out: TCPDEBUG2(PRU_LISTEN); INP_WUNLOCK(inp); @@ -791,6 +802,18 @@ tcp_usr_rcvd(struct socket *so, int flags) } tp = intotcpcb(inp); TCPDEBUG1(); +#ifdef TCP_RFC7413 + /* + * For passively-created TFO connections, don't attempt a window + * update while still in SYN_RECEIVED as this may trigger an early + * SYN|ACK. It is preferable to have the SYN|ACK be sent along with + * application response data, or failing that, when the DELACK timer + * expires. + */ + if ((tp->t_flags & TF_FASTOPEN) && + (tp->t_state == TCPS_SYN_RECEIVED)) + goto out; +#endif #ifdef TCP_OFFLOAD if (tp->t_flags & TF_TOE) tcp_offload_rcvd(tp); @@ -1558,6 +1581,29 @@ unlock_and_done: TP_MAXIDLE(tp)); goto unlock_and_done; +#ifdef TCP_RFC7413 + case TCP_FASTOPEN: + INP_WUNLOCK(inp); + if (!V_tcp_fastopen_enabled) + return (EPERM); + + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + return (error); + + INP_WLOCK_RECHECK(inp); + if (optval) { + tp->t_flags |= TF_FASTOPEN; + if ((tp->t_state == TCPS_LISTEN) && + (tp->t_tfo_pending == NULL)) + tp->t_tfo_pending = + tcp_fastopen_alloc_counter(); + } else + tp->t_flags &= ~TF_FASTOPEN; + goto unlock_and_done; +#endif + default: INP_WUNLOCK(inp); error = ENOPROTOOPT; @@ -1628,6 +1674,13 @@ unlock_and_done: INP_WUNLOCK(inp); error = sooptcopyout(sopt, &ui, sizeof(ui)); break; +#ifdef TCP_RFC7413 + case TCP_FASTOPEN: + optval = tp->t_flags & TF_FASTOPEN; + INP_WUNLOCK(inp); + error = sooptcopyout(sopt, &optval, sizeof optval); + break; +#endif default: INP_WUNLOCK(inp); error = ENOPROTOOPT; @@ -1951,6 +2004,10 @@ db_print_tflags(u_int t_flags) db_printf("%sTF_ECN_PERMIT", comma ? ", " : ""); comma = 1; } + if (t_flags & TF_FASTOPEN) { + db_printf("%sTF_FASTOPEN", comma ? ", " : ""); + comma = 1; + } } static void diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 758f2c5..cff81c5 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -213,8 +213,18 @@ struct tcpcb { u_int t_flags2; /* More tcpcb flags storage */ uint32_t t_ispare[6]; /* 5 UTO, 1 TBD */ +#if defined(_KERNEL) && defined(TCP_RFC7413) + void *t_pspare2[3]; /* 1 TCP_SIGNATURE, 2 TBD */ + unsigned int *t_tfo_pending; /* TCP Fast Open pending counter */ +#else void *t_pspare2[4]; /* 1 TCP_SIGNATURE, 3 TBD */ +#endif +#if defined(_KERNEL) && defined(TCP_RFC7413) + uint64_t _pad[4]; /* 4 TBD (1-2 CC/RTT?) */ + uint64_t t_tfo_cookie; /* TCP Fast Open cookie */ +#else uint64_t _pad[5]; /* 5 TBD (1-2 CC/RTT?) */ +#endif uint32_t t_tsomaxsegcount; /* TSO maximum segment count */ uint32_t t_tsomaxsegsize; /* TSO maximum segment size in bytes */ }; @@ -251,6 +261,7 @@ struct tcpcb { #define TF_ECN_SND_ECE 0x10000000 /* ECN ECE in queue */ #define TF_CONGRECOVERY 0x20000000 /* congestion recovery mode */ #define TF_WASCRECOVERY 0x40000000 /* was in congestion recovery */ +#define TF_FASTOPEN 0x80000000 /* TCP Fast Open indication */ #define IN_FASTRECOVERY(t_flags) (t_flags & TF_FASTRECOVERY) #define ENTER_FASTRECOVERY(t_flags) t_flags |= TF_FASTRECOVERY @@ -310,14 +321,17 @@ struct tcpopt { #define TOF_TS 0x0010 /* timestamp */ #define TOF_SIGNATURE 0x0040 /* TCP-MD5 signature option (RFC2385) */ #define TOF_SACK 0x0080 /* Peer sent SACK option */ -#define TOF_MAXOPT 0x0100 +#define TOF_FASTOPEN 0x0100 /* TCP Fast Open (TFO) cookie */ +#define TOF_MAXOPT 0x0200 u_int32_t to_tsval; /* new timestamp */ u_int32_t to_tsecr; /* reflected timestamp */ u_char *to_sacks; /* pointer to the first SACK blocks */ u_char *to_signature; /* pointer to the TCP-MD5 signature */ + u_char *to_tfo_cookie; /* pointer to the TFO cookie */ u_int16_t to_mss; /* maximum segment size */ u_int8_t to_wscale; /* window scaling */ u_int8_t to_nsacks; /* number of SACK blocks */ + u_int8_t to_tfo_len; /* TFO cookie length */ u_int32_t to_spare; /* UTO */ }; diff --git a/sys/sparc64/ebus/ebus.c b/sys/sparc64/ebus/ebus.c index 93ad342..0967c5d 100644 --- a/sys/sparc64/ebus/ebus.c +++ b/sys/sparc64/ebus/ebus.c @@ -69,7 +69,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> - #include <sys/rman.h> #include <dev/ofw/ofw_bus.h> @@ -294,7 +293,7 @@ ebus_nexus_attach(device_t dev) sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(struct ebus_nexus_ranges), &sc->sc_range); if (sc->sc_nrange == -1) { - printf("%s: could not get ranges property\n", __func__); + device_printf(dev, "could not get ranges property\n"); return (ENXIO); } return (ebus_attach(dev, sc, node)); @@ -306,6 +305,7 @@ ebus_pci_attach(device_t dev) struct ebus_softc *sc; struct ebus_rinfo *eri; struct resource *res; + struct isa_ranges *range; phandle_t node; int i, rnum, rid; @@ -322,7 +322,7 @@ ebus_pci_attach(device_t dev) sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(struct isa_ranges), &sc->sc_range); if (sc->sc_nrange == -1) { - printf("%s: could not get ranges property\n", __func__); + device_printf(dev, "could not get ranges property\n"); return (ENXIO); } @@ -332,21 +332,34 @@ ebus_pci_attach(device_t dev) /* For every range, there must be a matching resource. */ for (rnum = 0; rnum < sc->sc_nrange; rnum++) { eri = &sc->sc_rinfo[rnum]; - eri->eri_rtype = ofw_isa_range_restype( - &((struct isa_ranges *)sc->sc_range)[rnum]); + range = &((struct isa_ranges *)sc->sc_range)[rnum]; + eri->eri_rtype = ofw_isa_range_restype(range); rid = PCIR_BAR(rnum); res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid, RF_ACTIVE); if (res == NULL) { - printf("%s: failed to allocate range resource!\n", - __func__); + device_printf(dev, + "could not allocate range resource %d\n", rnum); + goto fail; + } + if (rman_get_start(res) != ISA_RANGE_PHYS(range)) { + device_printf(dev, + "mismatch in start of range %d (0x%lx/0x%lx)\n", + rnum, rman_get_start(res), ISA_RANGE_PHYS(range)); + goto fail; + } + if (rman_get_size(res) != range->size) { + device_printf(dev, + "mismatch in size of range %d (0x%lx/0x%x)\n", + rnum, rman_get_size(res), range->size); goto fail; } eri->eri_res = res; eri->eri_rman.rm_type = RMAN_ARRAY; eri->eri_rman.rm_descr = "EBus range"; if (rman_init_from_resource(&eri->eri_rman, res) != 0) { - printf("%s: failed to initialize rman!", __func__); + device_printf(dev, + "could not initialize rman for range %d", rnum); goto fail; } } @@ -452,7 +465,7 @@ ebus_alloc_resource(device_t bus, device_t child, int type, int *rid, * Map EBus ranges to PCI ranges. This may include * changing the allocation type. */ - (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange, + type = ofw_isa_range_map(sc->sc_range, sc->sc_nrange, &start, &end, &ridx); eri = &sc->sc_rinfo[ridx]; res = rman_reserve_resource(&eri->eri_rman, start, @@ -507,7 +520,7 @@ ebus_activate_resource(device_t bus, device_t child, int type, int rid, int i, rv; sc = device_get_softc(bus); - if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { + if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) { for (i = 0; i < sc->sc_nrange; i++) { eri = &sc->sc_rinfo[i]; if (rman_is_region_manager(res, &eri->eri_rman) != 0) { @@ -550,7 +563,7 @@ ebus_release_resource(device_t bus, device_t child, int type, int rid, passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); sc = device_get_softc(bus); - if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { + if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) { if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ rv = bus_deactivate_resource(child, type, rid, res); if (rv != 0) diff --git a/sys/sparc64/include/md_var.h b/sys/sparc64/include/md_var.h index 6a0a2f6..d3dbf99 100644 --- a/sys/sparc64/include/md_var.h +++ b/sys/sparc64/include/md_var.h @@ -47,9 +47,9 @@ extern vm_paddr_t kstack0_phys; struct pcpu; struct md_utrap; -const char *cpu_cpuid_prop(u_int cpu_impl); uint32_t cpu_get_mid(u_int cpu_impl); void cpu_identify(u_long vers, u_int clock, u_int id); +const char *cpu_portid_prop(u_int cpu_impl); void cpu_setregs(struct pcpu *pc); int is_physical_memory(vm_paddr_t addr); struct md_utrap *utrap_alloc(void); diff --git a/sys/sparc64/include/smp.h b/sys/sparc64/include/smp.h index c46c4f8..266187e 100644 --- a/sys/sparc64/include/smp.h +++ b/sys/sparc64/include/smp.h @@ -47,6 +47,7 @@ #include <sys/sched.h> #include <sys/smp.h> +#include <machine/atomic.h> #include <machine/intr_machdep.h> #include <machine/tte.h> @@ -143,7 +144,7 @@ ipi_all_but_self(u_int ipi) { cpuset_t cpus; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return; cpus = all_cpus; sched_pin(); @@ -158,7 +159,8 @@ static __inline void ipi_selected(cpuset_t cpus, u_int ipi) { - if (__predict_false(smp_started == 0 || CPU_EMPTY(&cpus))) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0 || + CPU_EMPTY(&cpus))) return; mtx_lock_spin(&ipi_mtx); cpu_ipi_selected(cpus, 0, (u_long)tl_ipi_level, ipi); @@ -169,7 +171,7 @@ static __inline void ipi_cpu(int cpu, u_int ipi) { - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return; mtx_lock_spin(&ipi_mtx); cpu_ipi_single(cpu, 0, (u_long)tl_ipi_level, ipi); @@ -183,7 +185,7 @@ ipi_dcache_page_inval(void *func, vm_paddr_t pa) { struct ipi_cache_args *ica; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); ica = &ipi_cache_args; @@ -200,7 +202,7 @@ ipi_icache_page_inval(void *func, vm_paddr_t pa) { struct ipi_cache_args *ica; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); ica = &ipi_cache_args; @@ -217,7 +219,7 @@ ipi_rd(u_int cpu, void *func, u_long *val) { struct ipi_rd_args *ira; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); ira = &ipi_rd_args; @@ -234,7 +236,7 @@ ipi_tlb_context_demap(struct pmap *pm) struct ipi_tlb_args *ita; cpuset_t cpus; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); cpus = pm->pm_active; @@ -259,7 +261,7 @@ ipi_tlb_page_demap(struct pmap *pm, vm_offset_t va) struct ipi_tlb_args *ita; cpuset_t cpus; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); cpus = pm->pm_active; @@ -284,7 +286,7 @@ ipi_tlb_range_demap(struct pmap *pm, vm_offset_t start, vm_offset_t end) struct ipi_tlb_args *ita; cpuset_t cpus; - if (__predict_false(smp_started == 0)) + if (__predict_false(atomic_load_acq_int(&smp_started) == 0)) return (NULL); sched_pin(); cpus = pm->pm_active; diff --git a/sys/sparc64/pci/fire.c b/sys/sparc64/pci/fire.c index 84526f0..be0c64b 100644 --- a/sys/sparc64/pci/fire.c +++ b/sys/sparc64/pci/fire.c @@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$"); #include <sys/timetc.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_pci.h> #include <dev/ofw/openfirm.h> #include <vm/vm.h> @@ -68,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/bus_common.h> #include <machine/bus_private.h> -#include <machine/fsr.h> #include <machine/iommureg.h> #include <machine/iommuvar.h> #include <machine/pmap.h> @@ -111,19 +109,14 @@ static driver_filter_t fire_xcb; /* * Methods */ -static bus_activate_resource_t fire_activate_resource; -static bus_adjust_resource_t fire_adjust_resource; static pcib_alloc_msi_t fire_alloc_msi; static pcib_alloc_msix_t fire_alloc_msix; static bus_alloc_resource_t fire_alloc_resource; static device_attach_t fire_attach; -static bus_get_dma_tag_t fire_get_dma_tag; -static ofw_bus_get_node_t fire_get_node; static pcib_map_msi_t fire_map_msi; static pcib_maxslots_t fire_maxslots; static device_probe_t fire_probe; static pcib_read_config_t fire_read_config; -static bus_read_ivar_t fire_read_ivar; static pcib_release_msi_t fire_release_msi; static pcib_release_msix_t fire_release_msix; static pcib_route_interrupt_t fire_route_interrupt; @@ -140,15 +133,15 @@ static device_method_t fire_methods[] = { DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, fire_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, fire_setup_intr), DEVMETHOD(bus_teardown_intr, fire_teardown_intr), DEVMETHOD(bus_alloc_resource, fire_alloc_resource), - DEVMETHOD(bus_activate_resource, fire_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, fire_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, fire_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, fire_maxslots), @@ -162,7 +155,7 @@ static device_method_t fire_methods[] = { DEVMETHOD(pcib_map_msi, fire_map_msi), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, fire_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), DEVMETHOD_END }; @@ -296,7 +289,7 @@ fire_attach(device_t dev) struct ofw_pci_msi_eq_to_devino msi_eq_to_devino; struct fire_msiqarg *fmqa; struct timecounter *tc; - struct ofw_pci_ranges *range; + bus_dma_tag_t dmat; uint64_t ino_bitmap, val; phandle_t node; uint32_t prop, prop_array[2]; @@ -310,7 +303,6 @@ fire_attach(device_t dev) mode = desc->fd_mode; sc->sc_dev = dev; - sc->sc_node = node; sc->sc_mode = mode; sc->sc_flags = 0; @@ -715,81 +707,21 @@ fire_attach(device_t dev) sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[FIRE_PCI]); sc->sc_is.is_iommu = FO_PCI_MMU; val = FIRE_PCI_READ_8(sc, FO_PCI_MMU + IMR_CTL); - iommu_init(device_get_nameunit(sc->sc_dev), &sc->sc_is, 7, -1, 0); + iommu_init(device_get_nameunit(dev), &sc->sc_is, 7, -1, 0); #ifdef FIRE_DEBUG device_printf(dev, "FO_PCI_MMU + IMR_CTL 0x%016llx -> 0x%016llx\n", (long long unsigned)val, (long long unsigned)sc->sc_is.is_cr); #endif - - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Fire PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, FO_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Fire PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, FO_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != FIRE_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < FIRE_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res[FIRE_PCI]), PCI_IO_BUS_SPACE, NULL); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res[FIRE_PCI]), PCI_CONFIG_BUS_SPACE, NULL); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0x100000000, sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, - 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = &sc->sc_is; - sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods; - - /* - * Get the bus range from the firmware. - * NB: Neither Fire nor Oberon support PCI bus reenumeration. - */ - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose != 0) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + dmat->dt_cookie = &sc->sc_is; + dmat->dt_mt = &sc->sc_dma_methods; - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + if (ofw_pci_attach_common(dev, dmat, FO_IO_SIZE, FO_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); #define FIRE_SYSCTL_ADD_UINT(name, arg, desc) \ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \ @@ -1392,136 +1324,44 @@ static uint32_t fire_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint32_t r, wrd; - int i; - uint16_t shrt; - uint8_t byte; - - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return (-1); - - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - if (i) { -#ifdef FIRE_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, width)); } static void fire_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return; - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, slot, + func, reg), bus, slot, func, reg, val, width); } static int fire_route_interrupt(device_t bridge, device_t dev, int pin) { - struct fire_softc *sc; - struct ofw_pci_register reg; - ofw_pci_intr_t pintr, mintr; - - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL) != 0) - return (mintr); - - device_printf(bridge, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); -} - -static int -fire_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct fire_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_pci_secbus; - return (0); - } - return (ENOENT); + ofw_pci_intr_t mintr; + + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (!PCI_INTERRUPT_VALID(mintr)) + device_printf(bridge, + "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (mintr); } static void fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map, bus_dmasync_op_t op) { - static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); - register_t reg, s; if ((map->dm_flags & DMF_LOADED) == 0) return; - if ((op & BUS_DMASYNC_POSTREAD) != 0) { - s = intr_disable(); - reg = rd(fprs); - wr(fprs, reg | FPRS_FEF, 0); - __asm __volatile("stda %%f0, [%0] %1" - : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); - membar(Sync); - wr(fprs, reg, 0); - intr_restore(s); - } else if ((op & BUS_DMASYNC_PREWRITE) != 0) + if ((op & BUS_DMASYNC_POSTREAD) != 0) + ofw_pci_dmamap_sync_stst_order_common(); + else if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); } @@ -2015,122 +1855,13 @@ fire_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct fire_softc *sc; - struct resource *rv; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); - if (*rid == 0) - start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); - } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -fire_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct fire_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, rman_get_bustag( - sc->sc_mem_res[FIRE_PCI]), PCI_MEMORY_BUS_SPACE, NULL); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} -static int -fire_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct fire_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); + if (type == SYS_RES_IRQ && *rid == 0) { + sc = device_get_softc(bus); + start = end = INTMAP_VEC(sc->sc_ign, end); } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -fire_get_dma_tag(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -fire_get_node(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static u_int diff --git a/sys/sparc64/pci/firereg.h b/sys/sparc64/pci/firereg.h index 247a3f7..715d3b7 100644 --- a/sys/sparc64/pci/firereg.h +++ b/sys/sparc64/pci/firereg.h @@ -30,7 +30,6 @@ #define _SPARC64_PCI_FIREREG_H_ #define FIRE_NINTR 3 /* 2 OFW + 1 MSIq */ -#define FIRE_NRANGE 4 #define FIRE_NREG 2 #define FIRE_PCI 0 diff --git a/sys/sparc64/pci/firevar.h b/sys/sparc64/pci/firevar.h index d414c1a..36fd8ea 100644 --- a/sys/sparc64/pci/firevar.h +++ b/sys/sparc64/pci/firevar.h @@ -32,6 +32,12 @@ #define _SPARC64_PCI_FIREVAR_H_ struct fire_softc { + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; + struct iommu_state sc_is; struct bus_dma_methods sc_dma_methods; @@ -42,13 +48,6 @@ struct fire_softc { struct resource *sc_irq_res[FIRE_NINTR]; void *sc_ihand[FIRE_NINTR]; - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - bus_space_handle_t sc_pci_bh[FIRE_NRANGE]; - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - device_t sc_dev; uint64_t *sc_msiq; @@ -66,8 +65,6 @@ struct fire_softc { uint32_t sc_msiq_first; uint32_t sc_msiq_ino_first; - phandle_t sc_node; - u_int sc_mode; #define FIRE_MODE_FIRE 0 #define FIRE_MODE_OBERON 1 @@ -87,11 +84,6 @@ struct fire_softc { uint32_t sc_stats_tlu_oe_rx_err; uint32_t sc_stats_tlu_oe_tx_err; uint32_t sc_stats_ubc_dmardue; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - struct ofw_bus_iinfo sc_pci_iinfo; }; #endif /* !_SPARC64_PCI_FIREVAR_H_ */ diff --git a/sys/sparc64/pci/ofw_pci.c b/sys/sparc64/pci/ofw_pci.c new file mode 100644 index 0000000..ae03ed3 --- /dev/null +++ b/sys/sparc64/pci/ofw_pci.c @@ -0,0 +1,412 @@ +/*- + * Copyright (c) 1999, 2000 Matthew R. Green + * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org> + * Copyright (c) 2005 - 2015 by Marius Strobl <marius@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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ofw_pci.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/rman.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_pci.h> +#include <dev/ofw/openfirm.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <machine/asi.h> +#include <machine/bus.h> +#include <machine/bus_private.h> +#include <machine/cpufunc.h> +#include <machine/fsr.h> +#include <machine/resource.h> + +#include <sparc64/pci/ofw_pci.h> + +/* XXX */ +extern struct bus_space_tag nexus_bustag; + +int +ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_ranges *range; + phandle_t node; + uint32_t prop_array[2]; + u_int i, j, nrange; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + sc->sc_node = node; + sc->sc_pci_dmat = dmat; + + /* Initialize memory and I/O rmans. */ + sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports"; + if (rman_init(&sc->sc_pci_io_rman) != 0 || + rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) { + device_printf(dev, "failed to set up I/O rman\n"); + return (ENXIO); + } + sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_mem_rman.rm_descr = "PCI Memory"; + if (rman_init(&sc->sc_pci_mem_rman) != 0 || + rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) { + device_printf(dev, "failed to set up memory rman\n"); + return (ENXIO); + } + + /* + * Find the addresses of the various bus spaces. The physical + * start addresses of the ranges are the configuration, I/O and + * memory handles. There should not be multiple ones of one kind. + */ + nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), + (void **)&range); + for (i = 0; i < nrange; i++) { + j = OFW_PCI_RANGE_CS(&range[i]); + if (sc->sc_pci_bh[j] != 0) { + device_printf(dev, "duplicate range for space %d\n", + j); + free(range, M_OFWPROP); + return (EINVAL); + } + sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); + } + free(range, M_OFWPROP); + + /* + * Make sure that the expected ranges are actually present. + * The OFW_PCI_CS_MEM64 one is not currently used. + */ + if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) { + device_printf(dev, "missing CONFIG range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) { + device_printf(dev, "missing IO range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) { + device_printf(dev, "missing MEM32 range\n"); + return (ENXIO); + } + + /* Allocate our tags. */ + sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, &nexus_bustag, + PCI_IO_BUS_SPACE, NULL); + if (sc->sc_pci_iot == NULL) { + device_printf(dev, "could not allocate PCI I/O tag\n"); + return (ENXIO); + } + sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, &nexus_bustag, + PCI_CONFIG_BUS_SPACE, NULL); + if (sc->sc_pci_cfgt == NULL) { + device_printf(dev, + "could not allocate PCI configuration space tag\n"); + return (ENXIO); + } + + /* + * Get the bus range from the firmware. + */ + i = OF_getprop(node, "bus-range", (void *)prop_array, + sizeof(prop_array)); + if (i == -1) { + device_printf(dev, "could not get bus-range\n"); + return (ENXIO); + } + if (i != sizeof(prop_array)) { + device_printf(dev, "broken bus-range (%d)", i); + return (EINVAL); + } + sc->sc_pci_secbus = prop_array[0]; + sc->sc_pci_subbus = prop_array[1]; + if (bootverbose != 0) + device_printf(dev, "bus range %u to %u; PCI bus %d\n", + sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + + return (0); +} + +uint32_t +ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + uint32_t r, wrd; + int i; + uint16_t shrt; + uint8_t byte; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return (-1); + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); + r = byte; + break; + case 2: + i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); + r = shrt; + break; + case 4: + i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); + r = wrd; + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } + + if (i) { +#ifdef OFW_PCI_DEBUG + printf("%s: read data error reading: %d.%d.%d: 0x%x\n", + __func__, bus, slot, func, reg); +#endif + r = -1; + } + return (r); +} + +void +ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return; + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); + break; + case 2: + bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); + break; + case 4: + bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } +} + +ofw_pci_intr_t +ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_register reg; + ofw_pci_intr_t pintr, mintr; + + sc = device_get_softc(bridge); + pintr = pin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, + ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), + NULL) != 0) + return (mintr); + return (PCI_INVALID_IRQ); +} + +void +ofw_pci_dmamap_sync_stst_order_common(void) +{ + static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); + register_t reg, s; + + s = intr_disable(); + reg = rd(fprs); + wr(fprs, reg | FPRS_FEF, 0); + __asm __volatile("stda %%f0, [%0] %1" + : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); + membar(Sync); + wr(fprs, reg, 0); + intr_restore(s); +} + +int +ofw_pci_read_ivar(device_t dev, device_t child __unused, int which, + uintptr_t *result) +{ + struct ofw_pci_softc *sc; + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = device_get_unit(dev); + return (0); + case PCIB_IVAR_BUS: + sc = device_get_softc(dev); + *result = sc->sc_pci_secbus; + return (0); + } + return (ENOENT); +} + +struct resource * +ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct ofw_pci_softc *sc; + struct resource *rv; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + /* + * XXX: Don't accept blank ranges for now, only single + * interrupts. The other case should not happen with + * the MI PCI code ... + * XXX: This may return a resource that is out of the + * range that was specified. Is this correct ...? + */ + if (start != end) + panic("%s: XXX: interrupt range", __func__); + return (bus_generic_alloc_resource(bus, child, type, rid, + start, end, count, flags)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (NULL); + } + + rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, + child); + if (rv == NULL) + return (NULL); + rman_set_rid(rv, *rid); + + if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, + *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); + } + return (rv); +} + +int +ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct ofw_pci_softc *sc; + struct bus_space_tag *tag; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_activate_resource(bus, child, type, rid, + r)); + case SYS_RES_MEMORY: + tag = sparc64_alloc_bus_tag(r, &nexus_bustag, + PCI_MEMORY_BUS_SPACE, NULL); + if (tag == NULL) + return (ENOMEM); + rman_set_bustag(r, tag); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + + rman_get_start(r)); + break; + case SYS_RES_IOPORT: + rman_set_bustag(r, sc->sc_pci_iot); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + + rman_get_start(r)); + break; + } + return (rman_activate_resource(r)); +} + +int +ofw_pci_adjust_resource(device_t bus, device_t child, int type, + struct resource *r, u_long start, u_long end) +{ + struct ofw_pci_softc *sc; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_adjust_resource(bus, child, type, r, + start, end)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (EINVAL); + } + if (rman_is_region_manager(r, rm) == 0) + return (EINVAL); + return (rman_adjust_resource(r, start, end)); +} + +bus_dma_tag_t +ofw_pci_get_dma_tag(device_t bus, device_t child __unused) +{ + struct ofw_pci_softc *sc; + + sc = device_get_softc(bus); + return (sc->sc_pci_dmat); +} + +phandle_t +ofw_pci_get_node(device_t bus, device_t child __unused) +{ + 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); +} diff --git a/sys/sparc64/pci/ofw_pci.h b/sys/sparc64/pci/ofw_pci.h index 3915fa7..6d1e5d9 100644 --- a/sys/sparc64/pci/ofw_pci.h +++ b/sys/sparc64/pci/ofw_pci.h @@ -62,6 +62,8 @@ #ifndef _SPARC64_PCI_OFW_PCI_H_ #define _SPARC64_PCI_OFW_PCI_H_ +#include <sys/rman.h> + #include <dev/ofw/ofw_bus_subr.h> #include "ofw_pci_if.h" @@ -73,6 +75,7 @@ typedef uint32_t ofw_pci_intr_t; #define OFW_PCI_CS_IO 0x01 #define OFW_PCI_CS_MEM32 0x02 #define OFW_PCI_CS_MEM64 0x03 +#define OFW_PCI_NUM_CS 4 /* OFW device types */ #define OFW_TYPE_PCI "pci" @@ -124,4 +127,44 @@ struct ofw_pci_ranges { /* default values */ #define OFW_PCI_LATENCY 64 +/* + * Common and generic parts of host-PCI-bridge support + */ + +struct ofw_pci_softc { + struct rman sc_pci_mem_rman; + struct rman sc_pci_io_rman; + + bus_space_handle_t sc_pci_bh[OFW_PCI_NUM_CS]; + bus_space_tag_t sc_pci_cfgt; + bus_space_tag_t sc_pci_iot; + bus_dma_tag_t sc_pci_dmat; + + struct ofw_bus_iinfo sc_pci_iinfo; + + phandle_t sc_node; + + uint8_t sc_pci_secbus; + uint8_t sc_pci_subbus; +}; + +int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize); +uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width); +void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width); +ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev, + int pin); + +void ofw_pci_dmamap_sync_stst_order_common(void); + +bus_activate_resource_t ofw_pci_activate_resource; +bus_adjust_resource_t ofw_pci_adjust_resource; +bus_alloc_resource_t ofw_pci_alloc_resource; +bus_get_dma_tag_t ofw_pci_get_dma_tag; +bus_read_ivar_t ofw_pci_read_ivar; + +ofw_bus_get_node_t ofw_pci_get_node; + #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */ diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index 4881d1f..f688df6 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_pci.h> #include <dev/ofw/openfirm.h> #include <machine/bus.h> @@ -110,17 +109,12 @@ static void psycho_iommu_init(struct psycho_softc *, int, uint32_t); */ static device_probe_t psycho_probe; static device_attach_t psycho_attach; -static bus_read_ivar_t psycho_read_ivar; static bus_setup_intr_t psycho_setup_intr; static bus_alloc_resource_t psycho_alloc_resource; -static bus_activate_resource_t psycho_activate_resource; -static bus_adjust_resource_t psycho_adjust_resource; -static bus_get_dma_tag_t psycho_get_dma_tag; static pcib_maxslots_t psycho_maxslots; static pcib_read_config_t psycho_read_config; static pcib_write_config_t psycho_write_config; static pcib_route_interrupt_t psycho_route_interrupt; -static ofw_bus_get_node_t psycho_get_node; static ofw_pci_setup_device_t psycho_setup_device; static device_method_t psycho_methods[] = { @@ -132,15 +126,15 @@ static device_method_t psycho_methods[] = { DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, psycho_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, psycho_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, psycho_alloc_resource), - DEVMETHOD(bus_activate_resource, psycho_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, psycho_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, psycho_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, psycho_maxslots), @@ -149,7 +143,7 @@ static device_method_t psycho_methods[] = { DEVMETHOD(pcib_route_interrupt, psycho_route_interrupt), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, psycho_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), /* ofw_pci interface */ DEVMETHOD(ofw_pci_setup_device, psycho_setup_device), @@ -288,12 +282,12 @@ psycho_attach(device_t dev) { struct psycho_icarg *pica; struct psycho_softc *asc, *sc, *osc; - struct ofw_pci_ranges *range; const struct psycho_desc *desc; bus_addr_t intrclr, intrmap; + bus_dma_tag_t dmat; uint64_t csr, dr; phandle_t node; - uint32_t dvmabase, prop, prop_array[2]; + uint32_t dvmabase, prop; u_int rerun, ver; int i, j; @@ -301,7 +295,6 @@ psycho_attach(device_t dev) sc = device_get_softc(dev); desc = psycho_get_desc(dev); - sc->sc_node = node; sc->sc_dev = dev; sc->sc_mode = desc->pd_mode; @@ -367,6 +360,7 @@ psycho_attach(device_t dev) panic("%s: mutex not initialized", __func__); sc->sc_mtx = osc->sc_mtx; } + SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link); csr = PSYCHO_READ8(sc, PSR_CS); ver = PSYCHO_GCSR_VERS(csr); @@ -435,43 +429,6 @@ psycho_attach(device_t dev) } else dvmabase = -1; - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Psycho PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, PSYCHO_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Psycho PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, PSYCHO_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != PSYCHO_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < PSYCHO_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Register the softc, this is needed for paired Psychos. */ - SLIST_INSERT_HEAD(&psycho_softcs, sc, sc_link); - /* * If we're a Hummingbird/Sabre or the first of a pair of Psychos * to arrive here, do the interrupt setup and start up the IOMMU. @@ -572,39 +529,21 @@ psycho_attach(device_t dev) iommu_reset(sc->sc_is); } - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res), PCI_IO_BUS_SPACE, NULL); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res), PCI_CONFIG_BUS_SPACE, NULL); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is->is_pmaxaddr, ~0, NULL, NULL, sc->sc_is->is_pmaxaddr, - 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = sc->sc_is; - sc->sc_pci_dmat->dt_mt = sc->sc_dma_methods; - - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + dmat->dt_cookie = sc->sc_is; + dmat->dt_mt = sc->sc_dma_methods; + + if (ofw_pci_attach_common(dev, dmat, PSYCHO_IO_SIZE, + PSYCHO_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); /* Clear any pending PCI error bits. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, - PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus, + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, + PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_STATUS, 2), 2); PCICTL_WRITE8(sc, PCR_CS, PCICTL_READ8(sc, PCR_CS)); PCICTL_WRITE8(sc, PCR_AFS, PCICTL_READ8(sc, PCR_AFS)); @@ -667,20 +606,20 @@ psycho_attach(device_t dev) * Set the latency timer register as this isn't always done by the * firmware. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_LATTIMER, OFW_PCI_LATENCY, 1); for (i = PCIR_VENDOR; i < PCIR_STATUS; i += sizeof(uint16_t)) - le16enc(&sc->sc_pci_hpbcfg[i], bus_space_read_2( - sc->sc_pci_cfgt, sc->sc_pci_bh[OFW_PCI_CS_CONFIG], - PSYCHO_CONF_OFF(sc->sc_pci_secbus, PCS_DEVICE, + le16enc(&sc->sc_pci_hpbcfg[i], + bus_space_read_2(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], + PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i))); for (i = PCIR_REVID; i <= PCIR_BIST; i += sizeof(uint8_t)) - sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_pci_cfgt, - sc->sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF( - sc->sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i)); + sc->sc_pci_hpbcfg[i] = bus_space_read_1(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], PSYCHO_CONF_OFF( + sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, i)); - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); /* * On E250 the interrupt map entry for the EBus bridge is wrong, * causing incorrect interrupts to be assigned to some devices on @@ -691,9 +630,9 @@ psycho_attach(device_t dev) * EBus devices will be used directly instead. */ if (strcmp(sparc64_model, "SUNW,Ultra-250") == 0 && - sc->sc_pci_iinfo.opi_imapmsk != NULL) - *(ofw_pci_intr_t *)(&sc->sc_pci_iinfo.opi_imapmsk[ - sc->sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK; + sc->sc_ops.sc_pci_iinfo.opi_imapmsk != NULL) + *(ofw_pci_intr_t *)(&sc->sc_ops.sc_pci_iinfo.opi_imapmsk[ + sc->sc_ops.sc_pci_iinfo.opi_addrc]) = INTMAP_INO_MASK; device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); @@ -927,20 +866,8 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { struct psycho_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint8_t byte; - uint16_t shrt; - uint32_t r, wrd; - int i; sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return (-1); - - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - /* * The Hummingbird and Sabre bridges are picky in that they * only allow their config space to be accessed using the @@ -956,9 +883,9 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, * The Psycho bridges contain a dupe of their header at 0x80 * which we nullify that way also. */ - if (bus == sc->sc_pci_secbus && slot == PCS_DEVICE && + if (bus == sc->sc_ops.sc_pci_secbus && slot == PCS_DEVICE && func == PCS_FUNC) { - if (offset % width != 0) + if (reg % width != 0) return (-1); if (reg >= sizeof(sc->sc_pci_hpbcfg)) @@ -967,8 +894,9 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, if ((reg < PCIR_STATUS && reg + width > PCIR_STATUS) || reg == PCIR_STATUS || reg == PCIR_STATUS + 1) le16enc(&sc->sc_pci_hpbcfg[PCIR_STATUS], - bus_space_read_2(sc->sc_pci_cfgt, bh, - PSYCHO_CONF_OFF(sc->sc_pci_secbus, + bus_space_read_2(sc->sc_ops.sc_pci_cfgt, + sc->sc_ops.sc_pci_bh[OFW_PCI_CS_CONFIG], + PSYCHO_CONF_OFF(sc->sc_ops.sc_pci_secbus, PCS_DEVICE, PCS_FUNC, PCIR_STATUS))); switch (width) { @@ -981,79 +909,29 @@ psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, } } - offset = PSYCHO_CONF_OFF(bus, slot, func, reg); - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - - if (i) { -#ifdef PSYCHO_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCI_REGMAX, + PSYCHO_CONF_OFF(bus, slot, func, reg), bus, slot, func, reg, + width)); } static void psycho_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct psycho_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return; - - offset = PSYCHO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCI_REGMAX, PSYCHO_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, val, width); } static int psycho_route_interrupt(device_t bridge, device_t dev, int pin) { struct psycho_softc *sc; - struct ofw_pci_register reg; bus_addr_t intrmap; - ofw_pci_intr_t pintr, mintr; + ofw_pci_intr_t mintr; - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL)) + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (PCI_INTERRUPT_VALID(mintr)) return (mintr); /* * If this is outside of the range for an intpin, it's likely a full @@ -1072,6 +950,7 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin) * for bus A are one-based, while those for bus B seemingly have an * offset of 2 (hence the factor of 3 below). */ + sc = device_get_softc(dev); intrmap = PSR_PCIA0_INT_MAP + 8 * (pci_get_slot(dev) - 1 + 3 * sc->sc_half); mintr = INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1; @@ -1081,23 +960,6 @@ psycho_route_interrupt(device_t bridge, device_t dev, int pin) return (mintr); } -static int -psycho_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct psycho_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_pci_secbus; - return (0); - } - return (ENOENT); -} - static void sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) { @@ -1180,121 +1042,13 @@ psycho_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct psycho_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); + if (type == SYS_RES_IRQ) { + sc = device_get_softc(bus); start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); - } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -psycho_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct psycho_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, rman_get_bustag( - sc->sc_mem_res), PCI_MEMORY_BUS_SPACE, NULL); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -psycho_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct psycho_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -psycho_get_dma_tag(device_t bus, device_t child __unused) -{ - struct psycho_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -psycho_get_node(device_t bus, device_t child __unused) -{ - struct psycho_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static void diff --git a/sys/sparc64/pci/psychoreg.h b/sys/sparc64/pci/psychoreg.h index ede593a..6e4ea39 100644 --- a/sys/sparc64/pci/psychoreg.h +++ b/sys/sparc64/pci/psychoreg.h @@ -73,7 +73,6 @@ */ #define PSYCHO_NINTR 6 -#define PSYCHO_NRANGE 4 /* * Psycho register offsets @@ -121,7 +120,7 @@ #define PSR_PWRMGT_INT_MAP 0x1090 /* power mgmt wake interrupt map reg */ #define PSR_FFB0_INT_MAP 0x1098 /* FFB0 graphics interrupt map reg */ #define PSR_FFB1_INT_MAP 0x10a0 /* FFB1 graphics interrupt map reg */ -/* Note: clear interrupt 0 registers are not really used */ +/* Note: Clear interrupt 0 registers are not really used. */ #define PSR_PCIA0_INT_CLR 0x1400 /* PCI a slot 0 clear int regs 0..3 */ #define PSR_PCIA1_INT_CLR 0x1420 /* PCI a slot 1 clear int regs 0..3 */ #define PSR_PCIA2_INT_CLR 0x1440 /* PCI a slot 2 clear int regs 0..3 */ @@ -165,6 +164,7 @@ #define PSR_PCI_INT_DIAG 0xa800 /* PCI int state diag reg */ #define PSR_OBIO_INT_DIAG 0xa808 /* OBIO and misc int state diag reg */ #define PSR_STRBUF_DIAG 0xb000 /* Streaming buffer diag regs */ + /* * Here is the rest of the map, which we're not specifying: * @@ -176,7 +176,7 @@ * 1ff.0000.0000 - 1ff.7fff.ffff PCI A memory space * 1ff.8000.0000 - 1ff.ffff.ffff PCI B memory space * - * NB: config and I/O space can use 1-4 byte accesses, not 8 byte + * NB: Config and I/O space can use 1-4 byte accesses, not 8 byte * accesses. Memory space can use any sized accesses. * * Note that the SUNW,sabre/SUNW,simba combinations found on the diff --git a/sys/sparc64/pci/psychovar.h b/sys/sparc64/pci/psychovar.h index 5532d16..0f828ee 100644 --- a/sys/sparc64/pci/psychovar.h +++ b/sys/sparc64/pci/psychovar.h @@ -36,49 +36,38 @@ * per pair of psychos. */ struct psycho_softc { - struct bus_dma_methods *sc_dma_methods; + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; - device_t sc_dev; + struct iommu_state *sc_is; + struct bus_dma_methods *sc_dma_methods; struct mtx *sc_mtx; - /* Interrupt Group Number for this device */ - uint32_t sc_ign; - - bus_addr_t sc_pcictl; - - phandle_t sc_node; /* Firmware node */ - u_int sc_mode; -#define PSYCHO_MODE_SABRE 0 -#define PSYCHO_MODE_PSYCHO 1 - - /* Bus A or B of a psycho pair? */ - u_int sc_half; - - struct iommu_state *sc_is; - struct resource *sc_mem_res; struct resource *sc_irq_res[PSYCHO_NINTR]; void *sc_ihand[PSYCHO_NINTR]; - struct ofw_bus_iinfo sc_pci_iinfo; + uint8_t sc_pci_hpbcfg[16]; - /* Tags for PCI access */ - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; + SLIST_ENTRY(psycho_softc) sc_link; - bus_space_handle_t sc_pci_bh[PSYCHO_NRANGE]; + device_t sc_dev; - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; + bus_addr_t sc_pcictl; - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; + u_int sc_mode; +#define PSYCHO_MODE_SABRE 0 +#define PSYCHO_MODE_PSYCHO 1 - uint8_t sc_pci_hpbcfg[16]; + /* Bus A or B of a psycho pair? */ + u_int sc_half; - SLIST_ENTRY(psycho_softc) sc_link; + /* Interrupt Group Number for this device */ + uint32_t sc_ign; }; #endif /* !_SPARC64_PCI_PSYCHOVAR_H_ */ diff --git a/sys/sparc64/pci/schizo.c b/sys/sparc64/pci/schizo.c index b89c7c0..ed1cccd 100644 --- a/sys/sparc64/pci/schizo.c +++ b/sys/sparc64/pci/schizo.c @@ -57,13 +57,11 @@ __FBSDID("$FreeBSD$"); #include <sys/timetc.h> #include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_pci.h> #include <dev/ofw/openfirm.h> #include <machine/bus.h> #include <machine/bus_common.h> #include <machine/bus_private.h> -#include <machine/fsr.h> #include <machine/iommureg.h> #include <machine/iommuvar.h> #include <machine/resource.h> @@ -108,17 +106,12 @@ static void schizo_iommu_init(struct schizo_softc *, int, uint32_t); */ static device_probe_t schizo_probe; static device_attach_t schizo_attach; -static bus_read_ivar_t schizo_read_ivar; static bus_setup_intr_t schizo_setup_intr; static bus_alloc_resource_t schizo_alloc_resource; -static bus_activate_resource_t schizo_activate_resource; -static bus_adjust_resource_t schizo_adjust_resource; -static bus_get_dma_tag_t schizo_get_dma_tag; static pcib_maxslots_t schizo_maxslots; static pcib_read_config_t schizo_read_config; static pcib_write_config_t schizo_write_config; static pcib_route_interrupt_t schizo_route_interrupt; -static ofw_bus_get_node_t schizo_get_node; static ofw_pci_setup_device_t schizo_setup_device; static device_method_t schizo_methods[] = { @@ -130,15 +123,15 @@ static device_method_t schizo_methods[] = { DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, schizo_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, schizo_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, schizo_alloc_resource), - DEVMETHOD(bus_activate_resource, schizo_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, schizo_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, schizo_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, schizo_maxslots), @@ -147,7 +140,7 @@ static device_method_t schizo_methods[] = { DEVMETHOD(pcib_route_interrupt, schizo_route_interrupt), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, schizo_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), /* ofw_pci interface */ DEVMETHOD(ofw_pci_setup_device, schizo_setup_device), @@ -270,10 +263,10 @@ schizo_probe(device_t dev) static int schizo_attach(device_t dev) { - struct ofw_pci_ranges *range; const struct schizo_desc *desc; struct schizo_softc *asc, *sc, *osc; struct timecounter *tc; + bus_dma_tag_t dmat; uint64_t ino_bitmap, reg; phandle_t node; uint32_t prop, prop_array[2]; @@ -285,7 +278,6 @@ schizo_attach(device_t dev) mode = desc->sd_mode; sc->sc_dev = dev; - sc->sc_node = node; sc->sc_mode = mode; sc->sc_flags = 0; @@ -347,6 +339,7 @@ schizo_attach(device_t dev) panic("%s: mutex not initialized", __func__); sc->sc_mtx = osc->sc_mtx; } + SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link); if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) panic("%s: could not determine IGN", __func__); @@ -542,82 +535,23 @@ schizo_attach(device_t dev) #undef TSBCASE - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Schizo PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, STX_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Schizo PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, STX_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != STX_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < STX_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Register the softc, this is needed for paired Schizos. */ - SLIST_INSERT_HEAD(&schizo_softcs, sc, sc_link); - - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res[STX_PCI]), PCI_IO_BUS_SPACE, NULL); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, rman_get_bustag( - sc->sc_mem_res[STX_PCI]), PCI_CONFIG_BUS_SPACE, NULL); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is.sis_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.sis_is.is_pmaxaddr, 0xff, 0xffffffff, 0, NULL, NULL, - &sc->sc_pci_dmat) != 0) + &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = &sc->sc_is; - sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods; + dmat->dt_cookie = &sc->sc_is; + dmat->dt_mt = &sc->sc_dma_methods; - /* - * Get the bus range from the firmware. - * NB: Tomatillos don't support PCI bus reenumeration. - */ - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + if (ofw_pci_attach_common(dev, dmat, STX_IO_SIZE, STX_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); /* Clear any pending PCI error bits. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, - PCIR_STATUS, PCIB_READ_CONFIG(dev, sc->sc_pci_secbus, - STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2), 2); + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, + STX_CS_FUNC, PCIR_STATUS, PCIB_READ_CONFIG(dev, + sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, + 2), 2); SCHIZO_PCI_SET(sc, STX_PCI_CTRL, SCHIZO_PCI_READ_8(sc, STX_PCI_CTRL)); SCHIZO_PCI_SET(sc, STX_PCI_AFSR, SCHIZO_PCI_READ_8(sc, STX_PCI_AFSR)); @@ -745,10 +679,8 @@ schizo_attach(device_t dev) * Set the latency timer register as this isn't always done by the * firmware. */ - PCIB_WRITE_CONFIG(dev, sc->sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, - PCIR_LATTIMER, OFW_PCI_LATENCY, 1); - - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + PCIB_WRITE_CONFIG(dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, + STX_CS_FUNC, PCIR_LATTIMER, OFW_PCI_LATENCY, 1); #define SCHIZO_SYSCTL_ADD_UINT(name, arg, desc) \ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \ @@ -872,7 +804,7 @@ schizo_pci_bus(void *arg) xstat = SCHIZO_PCI_READ_8(sc, XMS_PCI_X_ERR_STAT); else xstat = 0; - status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_pci_secbus, + status = PCIB_READ_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, 2); /* @@ -913,7 +845,7 @@ schizo_pci_bus(void *arg) (unsigned long long)iommu, (unsigned long long)xstat, status); /* Clear the error bits that we caught. */ - PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_pci_secbus, STX_CS_DEVICE, + PCIB_WRITE_CONFIG(sc->sc_dev, sc->sc_ops.sc_pci_secbus, STX_CS_DEVICE, STX_CS_FUNC, PCIR_STATUS, status, 2); SCHIZO_PCI_WRITE_8(sc, STX_PCI_CTRL, csr); SCHIZO_PCI_WRITE_8(sc, STX_PCI_AFSR, afsr); @@ -1034,121 +966,40 @@ schizo_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { struct schizo_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint32_t r, wrd; - int i; - uint16_t shrt; - uint8_t byte; sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return (-1); - /* * The Schizo bridges contain a dupe of their header at 0x80. */ - if (sc->sc_mode == SCHIZO_MODE_SCZ && bus == sc->sc_pci_secbus && - slot == STX_CS_DEVICE && func == STX_CS_FUNC && - reg + width > 0x80) + if (sc->sc_mode == SCHIZO_MODE_SCZ && + bus == sc->sc_ops.sc_pci_secbus && slot == STX_CS_DEVICE && + func == STX_CS_FUNC && reg + width > 0x80) return (0); - offset = STX_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - - if (i) { -#ifdef SCHIZO_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, width)); } static void schizo_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct schizo_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCI_REGMAX) - return; - offset = STX_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCI_REGMAX, STX_CONF_OFF(bus, slot, + func, reg), bus, slot, func, reg, val, width); } static int schizo_route_interrupt(device_t bridge, device_t dev, int pin) { - struct schizo_softc *sc; - struct ofw_pci_register reg; - ofw_pci_intr_t pintr, mintr; - - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL)) - return (mintr); - - device_printf(bridge, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); -} - -static int -schizo_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct schizo_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_pci_secbus; - return (0); - } - return (ENOENT); + ofw_pci_intr_t mintr; + + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (!PCI_INTERRUPT_VALID(mintr)) + device_printf(bridge, + "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (mintr); } static void @@ -1216,11 +1067,10 @@ schizo_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) static void ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) { - static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); struct timeval cur, end; struct schizo_iommu_state *sis = dt->dt_cookie; struct schizo_softc *sc = sis->sis_sc; - register_t reg, s; + uint64_t reg; if ((map->dm_flags & DMF_STREAMED) != 0) { iommu_dma_methods.dm_dmamap_sync(dt, map, op); @@ -1248,14 +1098,7 @@ ichip_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, bus_dmasync_op_t op) if (sc->sc_mode == SCHIZO_MODE_XMS) mtx_unlock_spin(&sc->sc_sync_mtx); else if ((sc->sc_flags & SCHIZO_FLAGS_BSWAR) != 0) { - s = intr_disable(); - reg = rd(fprs); - wr(fprs, reg | FPRS_FEF, 0); - __asm __volatile("stda %%f0, [%0] %1" - : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); - membar(Sync); - wr(fprs, reg, 0); - intr_restore(s); + ofw_pci_dmamap_sync_stst_order_common(); return; } } @@ -1356,121 +1199,13 @@ schizo_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct schizo_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); + if (type == SYS_RES_IRQ) { + sc = device_get_softc(bus); start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); - } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - return (rv); -} - -static int -schizo_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct schizo_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, rman_get_bustag( - sc->sc_mem_res[STX_PCI]), PCI_MEMORY_BUS_SPACE, NULL); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -schizo_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct schizo_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -schizo_get_dma_tag(device_t bus, device_t child __unused) -{ - struct schizo_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -schizo_get_node(device_t bus, device_t child __unused) -{ - struct schizo_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static void diff --git a/sys/sparc64/pci/schizoreg.h b/sys/sparc64/pci/schizoreg.h index cd816b5..59c00b6 100644 --- a/sys/sparc64/pci/schizoreg.h +++ b/sys/sparc64/pci/schizoreg.h @@ -32,7 +32,6 @@ #define _SPARC64_PCI_SCHIZOREG_H_ #define STX_NINTR 5 /* 4 via OFW + 1 CDMA */ -#define STX_NRANGE 4 #define SCZ_NREG 3 #define TOM_NREG 4 @@ -279,7 +278,7 @@ /* * Safari/JBus performance control register - * NB: for Tomatillo only events 0x00 through 0x08 are documented as + * NB: For Tomatillo only events 0x00 through 0x08 are documented as * implemented. */ #define SCZ_CTRL_PERF_ZDATA_OUT 0x0000000000000016ULL @@ -345,7 +344,7 @@ /* Non-Standard registers in the configration space */ /* - * NB: for Tomatillo the secondary and subordinate bus number registers + * NB: For Tomatillo the secondary and subordinate bus number registers * apparently are read-only although documented otherwise; writing to * them just triggers a PCI bus error interrupt or has no effect at best. */ diff --git a/sys/sparc64/pci/schizovar.h b/sys/sparc64/pci/schizovar.h index ab339c8..1b58cf4 100644 --- a/sys/sparc64/pci/schizovar.h +++ b/sys/sparc64/pci/schizovar.h @@ -39,16 +39,27 @@ struct schizo_iommu_state { }; struct schizo_softc { - struct bus_dma_methods sc_dma_methods; + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; - device_t sc_dev; + struct schizo_iommu_state sc_is; + struct bus_dma_methods sc_dma_methods; struct mtx sc_sync_mtx; uint64_t sc_sync_val; struct mtx *sc_mtx; - phandle_t sc_node; + struct resource *sc_mem_res[TOM_NREG]; + struct resource *sc_irq_res[STX_NINTR]; + void *sc_ihand[STX_NINTR]; + + SLIST_ENTRY(schizo_softc) sc_link; + + device_t sc_dev; u_int sc_mode; #define SCHIZO_MODE_SCZ 0 @@ -72,28 +83,8 @@ struct schizo_softc { uint32_t sc_ver; uint32_t sc_mrev; - struct resource *sc_mem_res[TOM_NREG]; - struct resource *sc_irq_res[STX_NINTR]; - void *sc_ihand[STX_NINTR]; - - struct schizo_iommu_state sc_is; - - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - bus_space_handle_t sc_pci_bh[STX_NRANGE]; - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - uint32_t sc_stats_dma_ce; uint32_t sc_stats_pci_non_fatal; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - struct ofw_bus_iinfo sc_pci_iinfo; - - SLIST_ENTRY(schizo_softc) sc_link; }; #endif /* !_SPARC64_PCI_SCHIZOVAR_H_ */ diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index f016eaa..07be1c8 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -249,7 +249,7 @@ find_bsp(phandle_t node, uint32_t bspid, u_int cpu_impl) { char type[sizeof("cpu")]; phandle_t child; - uint32_t cpuid; + uint32_t portid; for (; node != 0; node = OF_peer(node)) { child = OF_child(node); @@ -263,10 +263,10 @@ find_bsp(phandle_t node, uint32_t bspid, u_int cpu_impl) continue; if (strcmp(type, "cpu") != 0) continue; - if (OF_getprop(node, cpu_cpuid_prop(cpu_impl), &cpuid, - sizeof(cpuid)) <= 0) + if (OF_getprop(node, cpu_portid_prop(cpu_impl), + &portid, sizeof(portid)) <= 0) continue; - if (cpuid == bspid) + if (portid == bspid) return (node); } } @@ -274,7 +274,7 @@ find_bsp(phandle_t node, uint32_t bspid, u_int cpu_impl) } const char * -cpu_cpuid_prop(u_int cpu_impl) +cpu_portid_prop(u_int cpu_impl) { switch (cpu_impl) { diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c index c2c4e3e..52322a2 100644 --- a/sys/sparc64/sparc64/mp_machdep.c +++ b/sys/sparc64/sparc64/mp_machdep.c @@ -119,9 +119,11 @@ struct mtx ipi_mtx; cpu_ipi_selected_t *cpu_ipi_selected; cpu_ipi_single_t *cpu_ipi_single; -static vm_offset_t mp_tramp; static u_int cpuid_to_mid[MAXCPU]; +static u_int cpuids = 1; static volatile cpuset_t shutdown_cpus; +static char ipi_pbuf[CPUSETBUFSIZ]; +static vm_offset_t mp_tramp; static void ap_count(phandle_t node, u_int mid, u_int cpu_impl); static void ap_start(phandle_t node, u_int mid, u_int cpu_impl); @@ -165,13 +167,12 @@ static void foreach_ap(phandle_t node, void (*func)(phandle_t node, u_int mid, u_int cpu_impl)) { - char type[sizeof("cpu")]; + static char type[sizeof("cpu")]; phandle_t child; - u_int cpuid; - uint32_t cpu_impl; + uint32_t cpu_impl, portid; /* There's no need to traverse the whole OFW tree twice. */ - if (mp_maxid > 0 && mp_ncpus >= mp_maxid + 1) + if (mp_maxid > 0 && cpuids > mp_maxid) return; for (; node != 0; node = OF_peer(node)) { @@ -188,13 +189,13 @@ foreach_ap(phandle_t node, void (*func)(phandle_t node, u_int mid, sizeof(cpu_impl)) <= 0) panic("%s: couldn't determine CPU " "implementation", __func__); - if (OF_getprop(node, cpu_cpuid_prop(cpu_impl), &cpuid, - sizeof(cpuid)) <= 0) - panic("%s: couldn't determine CPU module ID", + if (OF_getprop(node, cpu_portid_prop(cpu_impl), + &portid, sizeof(portid)) <= 0) + panic("%s: couldn't determine CPU port ID", __func__); - if (cpuid == PCPU_GET(mid)) + if (portid == PCPU_GET(mid)) continue; - (*func)(node, cpuid, cpu_impl); + (*func)(node, portid, cpu_impl); } } } @@ -208,16 +209,17 @@ cpu_mp_setmaxid(void) CPU_SETOF(curcpu, &all_cpus); mp_ncpus = 1; - mp_maxid = 0; foreach_ap(OF_child(OF_peer(0)), ap_count); + mp_ncpus = MIN(mp_ncpus, MAXCPU); + mp_maxid = mp_ncpus - 1; } static void ap_count(phandle_t node __unused, u_int mid __unused, u_int cpu_impl __unused) { - mp_maxid++; + mp_ncpus++; } int @@ -306,7 +308,7 @@ ap_start(phandle_t node, u_int mid, u_int cpu_impl) u_int cpuid; uint32_t clock; - if (mp_ncpus > MAXCPU) + if (cpuids > mp_maxid) return; if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) <= 0) @@ -334,7 +336,7 @@ ap_start(phandle_t node, u_int mid, u_int cpu_impl) csa->csa_tick = csa->csa_stick = 0; intr_restore(s); - cpuid = mp_ncpus++; + cpuid = cpuids++; cpuid_to_mid[cpuid] = mid; cpu_identify(csa->csa_ver, clock, cpuid); @@ -659,7 +661,6 @@ cheetah_ipi_single(u_int cpu, u_long d0, u_long d1, u_long d2) static void cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) { - char pbuf[CPUSETBUFSIZ]; register_t s; u_long ids; u_int bnp; @@ -675,14 +676,14 @@ cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) ("%s: outstanding dispatch", __func__)); ids = 0; - for (i = 0; i < IPI_RETRIES * mp_ncpus; i++) { + for (i = 0; i < IPI_RETRIES * smp_cpus; i++) { s = intr_disable(); stxa(AA_SDB_INTR_D0, ASI_SDB_INTR_W, d0); stxa(AA_SDB_INTR_D1, ASI_SDB_INTR_W, d1); stxa(AA_SDB_INTR_D2, ASI_SDB_INTR_W, d2); membar(Sync); bnp = 0; - for (cpu = 0; cpu < mp_ncpus; cpu++) { + for (cpu = 0; cpu < smp_cpus; cpu++) { if (CPU_ISSET(cpu, &cpus)) { stxa(AA_INTR_SEND | (cpuid_to_mid[cpu] << IDC_ITID_SHIFT) | bnp << IDC_BN_SHIFT, @@ -698,7 +699,7 @@ cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) ; intr_restore(s); bnp = 0; - for (cpu = 0; cpu < mp_ncpus; cpu++) { + for (cpu = 0; cpu < smp_cpus; cpu++) { if (CPU_ISSET(cpu, &cpus)) { if ((ids & (IDR_NACK << (2 * bnp))) == 0) CPU_CLR(cpu, &cpus); @@ -710,10 +711,10 @@ cheetah_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) } if (kdb_active != 0 || panicstr != NULL) printf("%s: couldn't send IPI (cpus=%s ids=0x%lu)\n", - __func__, cpusetobj_strprint(pbuf, &cpus), ids); + __func__, cpusetobj_strprint(ipi_pbuf, &cpus), ids); else panic("%s: couldn't send IPI (cpus=%s ids=0x%lu)", - __func__, cpusetobj_strprint(pbuf, &cpus), ids); + __func__, cpusetobj_strprint(ipi_pbuf, &cpus), ids); } static void @@ -760,7 +761,6 @@ jalapeno_ipi_single(u_int cpu, u_long d0, u_long d1, u_long d2) static void jalapeno_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) { - char pbuf[CPUSETBUFSIZ]; register_t s; u_long ids; u_int cpu; @@ -775,13 +775,13 @@ jalapeno_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) ("%s: outstanding dispatch", __func__)); ids = 0; - for (i = 0; i < IPI_RETRIES * mp_ncpus; i++) { + for (i = 0; i < IPI_RETRIES * smp_cpus; i++) { s = intr_disable(); stxa(AA_SDB_INTR_D0, ASI_SDB_INTR_W, d0); stxa(AA_SDB_INTR_D1, ASI_SDB_INTR_W, d1); stxa(AA_SDB_INTR_D2, ASI_SDB_INTR_W, d2); membar(Sync); - for (cpu = 0; cpu < mp_ncpus; cpu++) { + for (cpu = 0; cpu < smp_cpus; cpu++) { if (CPU_ISSET(cpu, &cpus)) { stxa(AA_INTR_SEND | (cpuid_to_mid[cpu] << IDC_ITID_SHIFT), ASI_SDB_INTR_W, 0); @@ -795,7 +795,7 @@ jalapeno_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) if ((ids & (IDR_CHEETAH_ALL_BUSY | IDR_CHEETAH_ALL_NACK)) == 0) return; - for (cpu = 0; cpu < mp_ncpus; cpu++) + for (cpu = 0; cpu < smp_cpus; cpu++) if (CPU_ISSET(cpu, &cpus)) if ((ids & (IDR_NACK << (2 * cpuid_to_mid[cpu]))) == 0) @@ -803,8 +803,8 @@ jalapeno_ipi_selected(cpuset_t cpus, u_long d0, u_long d1, u_long d2) } if (kdb_active != 0 || panicstr != NULL) printf("%s: couldn't send IPI (cpus=%s ids=0x%lu)\n", - __func__, cpusetobj_strprint(pbuf, &cpus), ids); + __func__, cpusetobj_strprint(ipi_pbuf, &cpus), ids); else panic("%s: couldn't send IPI (cpus=%s ids=0x%lu)", - __func__, cpusetobj_strprint(pbuf, &cpus), ids); + __func__, cpusetobj_strprint(ipi_pbuf, &cpus), ids); } diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 4e2c9ea..1b5ce2d 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -13300,43 +13300,43 @@ softdep_ast_cleanup_proc(void) bool req; td = curthread; - mp = td->td_su; - if (mp == NULL) - return; - td->td_su = NULL; - error = vfs_busy(mp, MBF_NOWAIT); - vfs_rel(mp); - if (error != 0) - return; - if (ffs_own_mount(mp) && MOUNTEDSOFTDEP(mp)) { - ump = VFSTOUFS(mp); - for (;;) { - req = false; - ACQUIRE_LOCK(ump); - if (softdep_excess_items(ump, D_INODEDEP)) { - req = true; - request_cleanup(mp, FLUSH_INODES); - } - if (softdep_excess_items(ump, D_DIRREM)) { - req = true; - request_cleanup(mp, FLUSH_BLOCKS); - } - FREE_LOCK(ump); - if (softdep_excess_items(ump, D_NEWBLK) || - softdep_excess_items(ump, D_ALLOCDIRECT) || - softdep_excess_items(ump, D_ALLOCINDIR)) { - error = vn_start_write(NULL, &mp, V_WAIT); - if (error == 0) { + while ((mp = td->td_su) != NULL) { + td->td_su = NULL; + error = vfs_busy(mp, MBF_NOWAIT); + vfs_rel(mp); + if (error != 0) + return; + if (ffs_own_mount(mp) && MOUNTEDSOFTDEP(mp)) { + ump = VFSTOUFS(mp); + for (;;) { + req = false; + ACQUIRE_LOCK(ump); + if (softdep_excess_items(ump, D_INODEDEP)) { + req = true; + request_cleanup(mp, FLUSH_INODES); + } + if (softdep_excess_items(ump, D_DIRREM)) { req = true; - VFS_SYNC(mp, MNT_WAIT); - vn_finished_write(mp); + request_cleanup(mp, FLUSH_BLOCKS); } + FREE_LOCK(ump); + if (softdep_excess_items(ump, D_NEWBLK) || + softdep_excess_items(ump, D_ALLOCDIRECT) || + softdep_excess_items(ump, D_ALLOCINDIR)) { + error = vn_start_write(NULL, &mp, + V_WAIT); + if (error == 0) { + req = true; + VFS_SYNC(mp, MNT_WAIT); + vn_finished_write(mp); + } + } + if ((td->td_pflags & TDP_KTHREAD) != 0 || !req) + break; } - if ((td->td_pflags & TDP_KTHREAD) != 0 || !req) - break; } + vfs_unbusy(mp); } - vfs_unbusy(mp); } /* diff --git a/sys/x86/x86/busdma_bounce.c b/sys/x86/x86/busdma_bounce.c index f5c1b92..38c9f1e 100644 --- a/sys/x86/x86/busdma_bounce.c +++ b/sys/x86/x86/busdma_bounce.c @@ -751,6 +751,9 @@ bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) { struct bounce_page *bpage; + if (map == NULL) + return; + while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { STAILQ_REMOVE_HEAD(&map->bpages, links); free_bounce_page(dmat, bpage); @@ -763,47 +766,43 @@ bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, { struct bounce_page *bpage; - if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { - /* - * Handle data bouncing. We might also - * want to add support for invalidating - * the caches on broken hardware - */ - CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " - "performing bounce", __func__, dmat, - dmat->common.flags, op); - - if ((op & BUS_DMASYNC_PREWRITE) != 0) { - while (bpage != NULL) { - if (bpage->datavaddr != 0) { - bcopy((void *)bpage->datavaddr, - (void *)bpage->vaddr, - bpage->datacount); - } else { - physcopyout(bpage->dataaddr, - (void *)bpage->vaddr, - bpage->datacount); - } - bpage = STAILQ_NEXT(bpage, links); + if (map == NULL || (bpage = STAILQ_FIRST(&map->bpages)) == NULL) + return; + + /* + * Handle data bouncing. We might also want to add support for + * invalidating the caches on broken hardware. + */ + CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " + "performing bounce", __func__, dmat, dmat->common.flags, op); + + if ((op & BUS_DMASYNC_PREWRITE) != 0) { + while (bpage != NULL) { + if (bpage->datavaddr != 0) { + bcopy((void *)bpage->datavaddr, + (void *)bpage->vaddr, bpage->datacount); + } else { + physcopyout(bpage->dataaddr, + (void *)bpage->vaddr, bpage->datacount); } - dmat->bounce_zone->total_bounced++; + bpage = STAILQ_NEXT(bpage, links); } + dmat->bounce_zone->total_bounced++; + } - if ((op & BUS_DMASYNC_POSTREAD) != 0) { - while (bpage != NULL) { - if (bpage->datavaddr != 0) { - bcopy((void *)bpage->vaddr, - (void *)bpage->datavaddr, - bpage->datacount); - } else { - physcopyin((void *)bpage->vaddr, - bpage->dataaddr, - bpage->datacount); - } - bpage = STAILQ_NEXT(bpage, links); + if ((op & BUS_DMASYNC_POSTREAD) != 0) { + while (bpage != NULL) { + if (bpage->datavaddr != 0) { + bcopy((void *)bpage->vaddr, + (void *)bpage->datavaddr, + bpage->datacount); + } else { + physcopyin((void *)bpage->vaddr, + bpage->dataaddr, bpage->datacount); } - dmat->bounce_zone->total_bounced++; + bpage = STAILQ_NEXT(bpage, links); } + dmat->bounce_zone->total_bounced++; } } @@ -822,12 +821,14 @@ SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL); static struct sysctl_ctx_list * busdma_sysctl_tree(struct bounce_zone *bz) { + return (&bz->sysctl_tree); } static struct sysctl_oid * busdma_sysctl_tree_top(struct bounce_zone *bz) { + return (bz->sysctl_tree_top); } |