Index: conf/Makefile.i386-xen =================================================================== RCS file: conf/Makefile.i386-xen diff -N conf/Makefile.i386-xen --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ conf/Makefile.i386-xen 23 Dec 2005 03:02:35 -0000 @@ -0,0 +1,50 @@ +# Makefile.i386 -- with config changes. +# Copyright 1990 W. Jolitz +# from: @(#)Makefile.i386 7.1 5/10/91 +# $FreeBSD: src/sys/conf/Makefile.i386,v 1.268 2005/11/04 04:14:49 imp Exp $ +# +# Makefile for FreeBSD +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/i386/conf/``machineid'' +# after which you should do +# config machineid +# Generic makefile changes should be made in +# /sys/conf/Makefile.i386 +# after which config should be rerun for all machines. +# + +# Which version of config(8) is required. +%VERSREQ= 600004 + +STD8X16FONT?= iso + +.if !defined(S) +.if exists(./@/.) +S= ./@ +.else +S= ../../.. +.endif +.endif +.include "$S/conf/kern.pre.mk" + +M= i386-xen +MKMODULESENV+= MACHINE=i386-xen + +%BEFORE_DEPEND + +%OBJS + +%FILES.c + +%FILES.s + +%FILES.m + +%CLEAN + +%RULES + +.include "$S/conf/kern.post.mk" Index: conf/files =================================================================== RCS file: /usr/home/kmacy/ncvs/src/sys/conf/files,v retrieving revision 1.1080 diff -a -u -r1.1080 files --- conf/files 29 Dec 2005 01:43:46 -0000 1.1080 +++ conf/files 2 Jan 2006 11:38:11 -0000 @@ -1399,6 +1399,7 @@ libkern/strncpy.c standard libkern/strsep.c standard libkern/strspn.c standard +libkern/strcspn.c standard libkern/strtol.c standard libkern/strtoq.c standard libkern/strtoul.c standard Index: conf/files.i386-xen =================================================================== RCS file: conf/files.i386-xen diff -N conf/files.i386-xen --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ conf/files.i386-xen 1 Jan 2006 03:13:14 -0000 @@ -0,0 +1,468 @@ +# This file tells config what files go into building a kernel, +# files marked standard are always included. +# +# $FreeBSD: src/sys/conf/files.i386,v 1.544 2005/11/11 09:57:30 ru Exp $ +# +# The long compile-with and dependency lines are required because of +# limitations in config: backslash-newline doesn't work in strings, and +# dependency lines other than the first are silently ignored. +# +linux_genassym.o optional compat_linux \ + dependency "$S/i386/linux/linux_genassym.c" \ + compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \ + no-obj no-implicit-rule \ + clean "linux_genassym.o" +# +linux_assym.h optional compat_linux \ + dependency "$S/kern/genassym.sh linux_genassym.o" \ + compile-with "sh $S/kern/genassym.sh linux_genassym.o > ${.TARGET}" \ + no-obj no-implicit-rule before-depend \ + clean "linux_assym.h" +# +svr4_genassym.o optional compat_svr4 \ + dependency "$S/i386/svr4/svr4_genassym.c" \ + compile-with "${CC} ${CFLAGS:N-fno-common} -c ${.IMPSRC}" \ + no-obj no-implicit-rule \ + clean "svr4_genassym.o" +# +svr4_assym.h optional compat_svr4 \ + dependency "$S/kern/genassym.sh svr4_genassym.o" \ + compile-with "sh $S/kern/genassym.sh svr4_genassym.o > ${.TARGET}" \ + no-obj no-implicit-rule before-depend \ + clean "svr4_assym.h" +# +font.h optional sc_dflt_font \ + compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'static u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'static u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'static u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ + no-obj no-implicit-rule before-depend \ + clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" +# +atkbdmap.h optional atkbd_dflt_keymap \ + compile-with "/usr/sbin/kbdcontrol -L ${ATKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > atkbdmap.h" \ + no-obj no-implicit-rule before-depend \ + clean "atkbdmap.h" +# +ukbdmap.h optional ukbd_dflt_keymap \ + compile-with "/usr/sbin/kbdcontrol -L ${UKBD_DFLT_KEYMAP} | sed -e 's/^static keymap_t.* = /static keymap_t key_map = /' -e 's/^static accentmap_t.* = /static accentmap_t accent_map = /' > ukbdmap.h" \ + no-obj no-implicit-rule before-depend \ + clean "ukbdmap.h" +# +trlld.o optional oltr \ + dependency "$S/contrib/dev/oltr/i386-elf.trlld.o.uu" \ + compile-with "uudecode < $S/contrib/dev/oltr/i386-elf.trlld.o.uu" \ + no-implicit-rule +# +hal.o optional ath_hal \ + dependency "$S/contrib/dev/ath/public/i386-elf.hal.o.uu" \ + compile-with "uudecode < $S/contrib/dev/ath/public/i386-elf.hal.o.uu" \ + no-implicit-rule +opt_ah.h optional ath_hal \ + dependency "$S/contrib/dev/ath/public/i386-elf.opt_ah.h" \ + compile-with "cp $S/contrib/dev/ath/public/i386-elf.opt_ah.h opt_ah.h" \ + no-obj no-implicit-rule before-depend \ + clean "opt_ah.h" +# +nvenetlib.o optional nve pci \ + dependency "$S/contrib/dev/nve/i386/nvenetlib.o.bz2.uu" \ + compile-with "uudecode $S/contrib/dev/nve/i386/nvenetlib.o.bz2.uu ; bzip2 -df nvenetlib.o.bz2" \ + no-implicit-rule +# +os+%DIKED-nve.h optional nve pci \ + dependency "$S/contrib/dev/nve/os.h" \ + compile-with "sed -e 's/^.*#include.*phy\.h.*$$//' $S/contrib/dev/nve/os.h > os+%DIKED-nve.h" \ + no-implicit-rule no-obj before-depend \ + clean "os+%DIKED-nve.h" +# +hptmvraid.o optional hptmv \ + dependency "$S/dev/hptmv/i386-elf.raid.o.uu" \ + compile-with "uudecode < $S/dev/hptmv/i386-elf.raid.o.uu" \ + no-implicit-rule +# +# +compat/linux/linux_file.c optional compat_linux +compat/linux/linux_getcwd.c optional compat_linux +compat/linux/linux_ioctl.c optional compat_linux +compat/linux/linux_ipc.c optional compat_linux +compat/linux/linux_mib.c optional compat_linux +compat/linux/linux_misc.c optional compat_linux +compat/linux/linux_signal.c optional compat_linux +compat/linux/linux_socket.c optional compat_linux +compat/linux/linux_stats.c optional compat_linux +compat/linux/linux_sysctl.c optional compat_linux +compat/linux/linux_uid16.c optional compat_linux +compat/linux/linux_util.c optional compat_linux +compat/ndis/kern_ndis.c optional ndisapi pci +compat/ndis/kern_windrv.c optional ndisapi pci +compat/ndis/subr_hal.c optional ndisapi pci +compat/ndis/subr_ndis.c optional ndisapi pci +compat/ndis/subr_ntoskrnl.c optional ndisapi pci +compat/ndis/subr_pe.c optional ndisapi pci +compat/ndis/subr_usbd.c optional ndisapi pci +compat/ndis/winx32_wrap.S optional ndisapi pci +compat/pecoff/imgact_pecoff.c optional pecoff_support +compat/svr4/imgact_svr4.c optional compat_svr4 +compat/svr4/svr4_fcntl.c optional compat_svr4 +compat/svr4/svr4_filio.c optional compat_svr4 +compat/svr4/svr4_ioctl.c optional compat_svr4 +compat/svr4/svr4_ipc.c optional compat_svr4 +compat/svr4/svr4_misc.c optional compat_svr4 +compat/svr4/svr4_resource.c optional compat_svr4 +compat/svr4/svr4_signal.c optional compat_svr4 +compat/svr4/svr4_socket.c optional compat_svr4 +compat/svr4/svr4_sockio.c optional compat_svr4 +compat/svr4/svr4_stat.c optional compat_svr4 +compat/svr4/svr4_stream.c optional compat_svr4 +compat/svr4/svr4_syscallnames.c optional compat_svr4 +compat/svr4/svr4_sysent.c optional compat_svr4 +compat/svr4/svr4_sysvec.c optional compat_svr4 +compat/svr4/svr4_termios.c optional compat_svr4 +compat/svr4/svr4_ttold.c optional compat_svr4 +contrib/dev/oltr/if_oltr.c optional oltr +contrib/dev/oltr/if_oltr_isa.c optional oltr isa +contrib/dev/oltr/if_oltr_pci.c optional oltr pci +contrib/dev/oltr/trlldbm.c optional oltr +contrib/dev/oltr/trlldhm.c optional oltr +contrib/dev/oltr/trlldmac.c optional oltr +bf_enc.o optional crypto | ipsec ipsec_esp \ + dependency "$S/crypto/blowfish/arch/i386/bf_enc.S $S/crypto/blowfish/arch/i386/bf_enc_586.S $S/crypto/blowfish/arch/i386/bf_enc_686.S" \ + compile-with "${CC} -c -I$S/crypto/blowfish/arch/i386 ${ASM_CFLAGS} ${WERROR} ${.IMPSRC}" \ + no-implicit-rule +crypto/des/arch/i386/des_enc.S optional crypto | ipsec ipsec_esp | netsmbcrypto +crypto/via/padlock.c optional padlock +dev/advansys/adv_isa.c optional adv isa +dev/aic/aic_isa.c optional aic isa +dev/arcmsr/arcmsr.c optional arcmsr pci +dev/ar/if_ar.c optional ar +dev/ar/if_ar_isa.c optional ar isa +dev/ar/if_ar_pci.c optional ar pci +dev/arl/if_arl.c optional arl +dev/arl/if_arl_isa.c optional arl isa +dev/atkbdc/atkbd.c optional atkbd atkbdc +dev/atkbdc/atkbd_atkbdc.c optional atkbd atkbdc +dev/atkbdc/atkbdc.c optional atkbdc +dev/atkbdc/atkbdc_isa.c optional atkbdc isa +dev/atkbdc/atkbdc_subr.c optional atkbdc +dev/atkbdc/psm.c optional psm atkbdc +dev/cm/if_cm_isa.c optional cm isa +dev/cp/cpddk.c optional cp +dev/cp/if_cp.c optional cp +dev/ctau/ctau.c optional ctau +dev/ctau/ctddk.c optional ctau +dev/ctau/if_ct.c optional ctau +dev/cx/csigma.c optional cx +dev/cx/cxddk.c optional cx +dev/cx/if_cx.c optional cx +dev/ed/if_ed_3c503.c optional ed isa ed_3c503 +dev/ed/if_ed_isa.c optional ed isa +dev/ed/if_ed_wd80x3.c optional ed isa +dev/ed/if_ed_hpp.c optional ed isa ed_hpp +dev/ed/if_ed_sic.c optional ed isa ed_sic +dev/fb/fb.c optional fb | vga +dev/fb/splash.c optional splash +dev/fb/vga.c optional vga +dev/fdc/fdc.c optional fdc +dev/fdc/fdc_acpi.c optional fdc +dev/fdc/fdc_isa.c optional fdc isa +dev/fdc/fdc_pccard.c optional fdc pccard +dev/fe/if_fe_isa.c optional fe isa +dev/hptmv/entry.c optional hptmv +dev/hptmv/mv.c optional hptmv +dev/hptmv/gui_lib.c optional hptmv +dev/hptmv/hptproc.c optional hptmv +dev/hptmv/ioctl.c optional hptmv +dev/hwpmc/hwpmc_amd.c optional hwpmc +dev/hwpmc/hwpmc_pentium.c optional hwpmc +dev/hwpmc/hwpmc_piv.c optional hwpmc +dev/hwpmc/hwpmc_ppro.c optional hwpmc +dev/hwpmc/hwpmc_x86.c optional hwpmc +dev/ichwd/ichwd.c optional ichwd +dev/if_ndis/if_ndis.c optional ndis +dev/if_ndis/if_ndis_pccard.c optional ndis pccard +dev/if_ndis/if_ndis_pci.c optional ndis cardbus | ndis pci +dev/if_ndis/if_ndis_usb.c optional ndis usb +dev/io/iodev.c optional io +dev/kbd/kbd.c optional atkbd | sc | ukbd | vt +dev/lnc/if_lnc_isa.c optional lnc isa +dev/mem/memutil.c optional mem +dev/mse/mse.c optional mse +dev/mse/mse_isa.c optional mse isa +dev/nve/if_nve.c optional nve pci +dev/pcf/pcf_isa.c optional pcf +dev/ppc/ppc.c optional ppc +dev/ppc/ppc_puc.c optional ppc puc pci +dev/random/nehemiah.c optional random +dev/sbni/if_sbni.c optional sbni +dev/sbni/if_sbni_isa.c optional sbni isa +dev/sbni/if_sbni_pci.c optional sbni pci +dev/sio/sio.c optional sio +dev/sio/sio_isa.c optional sio isa +dev/speaker/spkr.c optional speaker +dev/sr/if_sr_isa.c optional sr isa +dev/syscons/apm/apm_saver.c optional apm_saver apm +dev/syscons/schistory.c optional sc +dev/syscons/scmouse.c optional sc +dev/syscons/scterm.c optional sc +dev/syscons/scterm-dumb.c optional sc +dev/syscons/scterm-sc.c optional sc +dev/syscons/scvesactl.c optional sc vga vesa +dev/syscons/scvgarndr.c optional sc vga +dev/syscons/scvidctl.c optional sc +dev/syscons/scvtb.c optional sc +dev/syscons/syscons.c optional sc +dev/syscons/sysmouse.c optional sc +dev/uart/uart_cpu_i386.c optional uart +geom/geom_bsd.c standard +geom/geom_bsd_enc.c standard +geom/geom_mbr.c standard +geom/geom_mbr_enc.c standard +dev/acpica/acpi_if.m standard +i386/acpica/OsdEnvironment.c optional acpi +i386/acpica/acpi_machdep.c optional acpi +i386/acpica/acpi_wakeup.c optional acpi +acpi_wakecode.h optional acpi \ + dependency "$S/i386/acpica/acpi_wakecode.S assym.s" \ + compile-with "${MAKE} -f $S/i386/acpica/Makefile MAKESRCPATH=$S/i386/acpica" \ + no-obj no-implicit-rule before-depend \ + clean "acpi_wakecode.h acpi_wakecode.o acpi_wakecode.bin" +# +i386/acpica/madt.c optional acpi apic +i386/bios/apm.c optional apm +i386/bios/mca_machdep.c optional mca +i386/bios/smapi.c optional smapi +i386/bios/smapi_bios.S optional smapi +i386/bios/smbios.c optional smbios +i386/bios/vpd.c optional vpd +i386/cpufreq/est.c optional cpufreq +i386/cpufreq/p4tcc.c optional cpufreq +i386/cpufreq/powernow.c optional cpufreq +i386/cpufreq/smist.c optional cpufreq +#i386/i386/apic_vector.s optional apic +i386/i386/atomic.c standard \ + compile-with "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}" +i386/i386/autoconf.c standard +i386/i386/bios.c standard +i386/i386/bioscall.s standard +i386/i386/bpf_jit_machdep.c optional bpf_jitter +i386/i386/busdma_machdep.c standard +i386/i386/db_disasm.c optional ddb +i386/i386/db_interface.c optional ddb +i386/i386/db_trace.c optional ddb +i386/i386/dump_machdep.c standard +i386/i386/elan-mmcr.c optional cpu_elan | cpu_soekris +i386/i386/elf_machdep.c standard +i386-xen/i386-xen/exception.s standard +i386/i386/gdb_machdep.c optional gdb +i386/i386/geode.c optional cpu_geode +i386/i386/i686_mem.c optional mem +i386/i386/identcpu.c standard +i386/i386/in_cksum.c optional inet +i386/i386/initcpu.c standard +i386/i386/intr_machdep.c standard +i386/i386/io.c optional io +i386/i386/io_apic.c optional apic +i386/i386/k6_mem.c optional mem +i386/i386/legacy.c standard +i386/i386/local_apic.c optional apic +i386/i386/locore.s standard no-obj +i386/i386/longrun.c optional cpu_enable_longrun +i386-xen/i386-xen/machdep.c standard +i386/i386/mem.c optional mem +i386/i386/mp_clock.c optional smp +i386/i386/mp_machdep.c optional smp +i386/i386/mp_watchdog.c optional mp_watchdog smp +i386/i386/mpboot.s optional smp +i386/i386/mptable.c optional apic +i386/i386/mptable_pci.c optional apic pci +i386/i386/nexus.c standard +i386/i386/perfmon.c optional perfmon +i386-xen/i386-xen/pmap.c standard +i386/i386/ptrace_machdep.c standard +i386/i386/support.s standard +i386/i386/swtch.s standard +i386/i386/sys_machdep.c standard +i386/i386/trap.c standard +i386/i386/tsc.c standard +i386/i386/uio_machdep.c standard +i386/i386/vm86.c standard +i386/i386/vm_machdep.c standard +i386/ibcs2/ibcs2_errno.c optional ibcs2 +i386/ibcs2/ibcs2_fcntl.c optional ibcs2 +i386/ibcs2/ibcs2_ioctl.c optional ibcs2 +i386/ibcs2/ibcs2_ipc.c optional ibcs2 +i386/ibcs2/ibcs2_isc.c optional ibcs2 +i386/ibcs2/ibcs2_isc_sysent.c optional ibcs2 +i386/ibcs2/ibcs2_misc.c optional ibcs2 +i386/ibcs2/ibcs2_msg.c optional ibcs2 +i386/ibcs2/ibcs2_other.c optional ibcs2 +i386/ibcs2/ibcs2_signal.c optional ibcs2 +i386/ibcs2/ibcs2_socksys.c optional ibcs2 +i386/ibcs2/ibcs2_stat.c optional ibcs2 +i386/ibcs2/ibcs2_sysent.c optional ibcs2 +i386/ibcs2/ibcs2_sysi86.c optional ibcs2 +i386/ibcs2/ibcs2_sysvec.c optional ibcs2 +i386/ibcs2/ibcs2_util.c optional ibcs2 +i386/ibcs2/ibcs2_xenix.c optional ibcs2 +i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2 +i386/ibcs2/imgact_coff.c optional ibcs2 +#i386/isa/atpic.c standard +#i386/isa/atpic_vector.s standard +i386/isa/elcr.c standard +i386/isa/elink.c optional ep | ie +i386/isa/isa.c optional isa +i386/isa/isa_dma.c optional isa +i386/isa/nmi.c standard +i386/isa/npx.c optional npx +i386/isa/pcvt/pcvt_drv.c optional vt +i386/isa/pcvt/pcvt_ext.c optional vt +i386/isa/pcvt/pcvt_kbd.c optional vt +i386/isa/pcvt/pcvt_out.c optional vt +i386/isa/pcvt/pcvt_sup.c optional vt +i386/isa/pcvt/pcvt_vtf.c optional vt +i386/isa/pmtimer.c optional pmtimer +i386/isa/prof_machdep.c optional profiling-routine +i386/isa/spic.c optional spic +i386/isa/vesa.c optional vga vesa +i386/linux/imgact_linux.c optional compat_linux +i386/linux/linux_dummy.c optional compat_linux +i386/linux/linux_locore.s optional compat_linux \ + dependency "linux_assym.h" +i386/linux/linux_machdep.c optional compat_linux +i386/linux/linux_ptrace.c optional compat_linux +i386/linux/linux_sysent.c optional compat_linux +i386/linux/linux_sysvec.c optional compat_linux +i386/pci/pci_bus.c optional pci +i386/pci/pci_cfgreg.c optional pci +i386/pci/pci_pir.c optional pci +i386/svr4/svr4_locore.s optional compat_svr4 \ + dependency "svr4_assym.h" \ + warning "COMPAT_SVR4 is broken and should be avoided" +i386/svr4/svr4_machdep.c optional compat_svr4 +# +# isdn4bsd, needed for isic | iwic | ifpi | ifpi2 | ihfc | ifpnp | itjc +# +i4b/layer1/i4b_hdlc.c optional itjc +i4b/layer1/i4b_hdlc.c optional ihfc +i4b/layer1/i4b_l1dmux.c optional isic +i4b/layer1/i4b_l1lib.c optional isic +i4b/layer1/i4b_l1dmux.c optional iwic +i4b/layer1/i4b_l1lib.c optional iwic +i4b/layer1/i4b_l1dmux.c optional ifpi +i4b/layer1/i4b_l1lib.c optional ifpi +i4b/layer1/i4b_l1dmux.c optional ifpi2 +i4b/layer1/i4b_l1lib.c optional ifpi2 +i4b/layer1/i4b_l1dmux.c optional ihfc +i4b/layer1/i4b_l1lib.c optional ihfc +i4b/layer1/i4b_l1dmux.c optional ifpnp +i4b/layer1/i4b_l1lib.c optional ifpnp +i4b/layer1/i4b_l1dmux.c optional itjc +i4b/layer1/i4b_l1lib.c optional itjc +# +# isdn4bsd, isic +# +i4b/layer1/isic/i4b_asuscom_ipac.c optional isic +i4b/layer1/isic/i4b_avm_a1.c optional isic +i4b/layer1/isic/i4b_bchan.c optional isic +i4b/layer1/isic/i4b_ctx_s0P.c optional isic +i4b/layer1/isic/i4b_drn_ngo.c optional isic +i4b/layer1/isic/i4b_dynalink.c optional isic +i4b/layer1/isic/i4b_elsa_qs1i.c optional isic +i4b/layer1/isic/i4b_elsa_qs1p.c optional isic pci +i4b/layer1/isic/i4b_elsa_pcc16.c optional isic +i4b/layer1/isic/i4b_hscx.c optional isic +i4b/layer1/isic/i4b_isac.c optional isic +i4b/layer1/isic/i4b_isic.c optional isic +i4b/layer1/isic/i4b_isic_isa.c optional isic +i4b/layer1/isic/i4b_isic_pnp.c optional isic +i4b/layer1/isic/i4b_itk_ix1.c optional isic +i4b/layer1/isic/i4b_l1.c optional isic +i4b/layer1/isic/i4b_l1fsm.c optional isic +i4b/layer1/isic/i4b_siemens_isurf.c optional isic +i4b/layer1/isic/i4b_sws.c optional isic +i4b/layer1/isic/i4b_tel_s016.c optional isic +i4b/layer1/isic/i4b_tel_s0163.c optional isic +i4b/layer1/isic/i4b_tel_s08.c optional isic +i4b/layer1/isic/i4b_usr_sti.c optional isic +i4b/layer1/isic/i4b_diva.c optional isic +# +# isdn4bsd, iwic +# +i4b/layer1/iwic/i4b_iwic_pci.c optional iwic pci +i4b/layer1/iwic/i4b_iwic_dchan.c optional iwic pci +i4b/layer1/iwic/i4b_iwic_bchan.c optional iwic pci +i4b/layer1/iwic/i4b_iwic_fsm.c optional iwic pci +i4b/layer1/iwic/i4b_iwic_l1if.c optional iwic pci +# +# isdn4bsd, ifpi +# +i4b/layer1/ifpi/i4b_ifpi_pci.c optional ifpi pci +i4b/layer1/ifpi/i4b_ifpi_isac.c optional ifpi pci +i4b/layer1/ifpi/i4b_ifpi_l1.c optional ifpi pci +i4b/layer1/ifpi/i4b_ifpi_l1fsm.c optional ifpi pci +# +# isdn4bsd, ifpi2 +# +i4b/layer1/ifpi2/i4b_ifpi2_pci.c optional ifpi2 pci +i4b/layer1/ifpi2/i4b_ifpi2_isacsx.c optional ifpi2 pci +i4b/layer1/ifpi2/i4b_ifpi2_l1.c optional ifpi2 pci +i4b/layer1/ifpi2/i4b_ifpi2_l1fsm.c optional ifpi2 pci +# +# isdn4bsd, ifpnp +# +i4b/layer1/ifpnp/i4b_ifpnp_avm.c optional ifpnp +i4b/layer1/ifpnp/i4b_ifpnp_isac.c optional ifpnp +i4b/layer1/ifpnp/i4b_ifpnp_l1.c optional ifpnp +i4b/layer1/ifpnp/i4b_ifpnp_l1fsm.c optional ifpnp +# +# isdn4bsd, ihfc +# +i4b/layer1/ihfc/i4b_ihfc_l1if.c optional ihfc +i4b/layer1/ihfc/i4b_ihfc_pnp.c optional ihfc +i4b/layer1/ihfc/i4b_ihfc_drv.c optional ihfc +# +# isdn4bsd, itjc +# +i4b/layer1/itjc/i4b_itjc_pci.c optional itjc +i4b/layer1/itjc/i4b_itjc_isac.c optional itjc +i4b/layer1/itjc/i4b_itjc_l1.c optional itjc +i4b/layer1/itjc/i4b_itjc_l1fsm.c optional itjc +# +isa/syscons_isa.c optional sc +isa/vga_isa.c optional vga +kern/imgact_aout.c optional compat_aout +kern/imgact_gzip.c optional gzip +libkern/divdi3.c standard +libkern/ffsl.c standard +libkern/flsl.c standard +libkern/moddi3.c standard +libkern/qdivrem.c standard +libkern/ucmpdi2.c standard +libkern/udivdi3.c standard +libkern/umoddi3.c standard +pci/agp_ali.c optional agp +pci/agp_amd.c optional agp +pci/agp_amd64.c optional agp +pci/agp_ati.c optional agp +pci/agp_i810.c optional agp +pci/agp_intel.c optional agp +pci/agp_nvidia.c optional agp +pci/agp_sis.c optional agp +pci/agp_via.c optional agp +i386/xbox/xbox.c optional xbox +i386/xbox/xboxfb.c optional xboxfb +dev/fb/boot_font.c optional xboxfb +i386/xbox/pic16l.s optional xbox + +i386-xen/i386-xen/clock.c standard +i386-xen/i386-xen/evtchn.c standard +i386-xen/i386-xen/gnttab.c standard +i386-xen/i386-xen/hypervisor.c standard +i386-xen/i386-xen/xen_machdep.c standard +dev/xen/evtchn/evtchn_dev.c standard +dev/xen/console/console.c standard +dev/xen/console/xencons_ring.c standard +dev/xen/xenbus/xenbus_client.c standard +dev/xen/xenbus/xenbus_comms.c standard +dev/xen/xenbus/xenbus_dev.c standard +dev/xen/xenbus/xenbus_probe.c standard +dev/xen/xenbus/xenbus_xs.c standard +dev/xen/blkfront/blkfront.c standard +dev/xen/netfront/netfront.c standard Index: conf/ldscript.i386-xen =================================================================== RCS file: conf/ldscript.i386-xen diff -N conf/ldscript.i386-xen --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ conf/ldscript.i386-xen 23 Dec 2005 03:01:09 -0000 @@ -0,0 +1,134 @@ +/* $FreeBSD: src/sys/conf/ldscript.i386,v 1.9 2003/12/03 07:40:03 phk Exp $ */ +OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd", "elf32-i386-freebsd") +OUTPUT_ARCH(i386) +ENTRY(btext) +SEARCH_DIR(/usr/lib); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = kernbase + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.text : + { *(.rel.text) *(.rel.gnu.linkonce.t*) } + .rela.text : + { *(.rela.text) *(.rela.gnu.linkonce.t*) } + .rel.data : + { *(.rel.data) *(.rel.gnu.linkonce.d*) } + .rela.data : + { *(.rela.data) *(.rela.gnu.linkonce.d*) } + .rel.rodata : + { *(.rel.rodata) *(.rel.gnu.linkonce.r*) } + .rela.rodata : + { *(.rela.rodata) *(.rela.gnu.linkonce.r*) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } =0x9090 + .plt : { *(.plt) } + .text : + { + *(.text) + *(.stub) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.gnu.linkonce.t*) + } =0x9090 + _etext = .; + PROVIDE (etext = .); + .fini : { *(.fini) } =0x9090 + .rodata : { *(.rodata) *(.gnu.linkonce.r*) } + .rodata1 : { *(.rodata1) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN(0x1000) + (. & (0x1000 - 1)) ; + .data : + { + *(.data) + *(.gnu.linkonce.d*) + CONSTRUCTORS + } + .data1 : { *(.data1) } + . = ALIGN(32 / 8); + _start_ctors = .; + PROVIDE (start_ctors = .); + .ctors : + { + *(.ctors) + } + _stop_ctors = .; + PROVIDE (stop_ctors = .); + .dtors : + { + *(.dtors) + } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + _edata = .; + PROVIDE (edata = .); + __bss_start = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + } + . = ALIGN(32 / 8); + _end = . ; + PROVIDE (end = .); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* These must appear regardless of . */ +} Index: conf/options.i386-xen =================================================================== RCS file: conf/options.i386-xen diff -N conf/options.i386-xen --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ conf/options.i386-xen 13 Dec 2005 01:22:36 -0000 @@ -0,0 +1,171 @@ +# $FreeBSD: src/sys/conf/options.i386,v 1.227 2005/11/09 03:55:39 imp Exp $ +# Options specific to the i386 platform kernels + +AUTO_EOI_1 opt_auto_eoi.h +AUTO_EOI_2 opt_auto_eoi.h +BROKEN_KEYBOARD_RESET opt_reset.h +COUNT_XINVLTLB_HITS opt_smp.h +COUNT_IPIS opt_smp.h +DISABLE_PG_G opt_pmap.h +DISABLE_PSE opt_pmap.h +I586_PMC_GUPROF opt_i586_guprof.h +MAXMEM +MPTABLE_FORCE_HTT +PERFMON +PMAP_SHPGPERPROC opt_pmap.h +POWERFAIL_NMI opt_trap.h +PPC_DEBUG opt_ppc.h +PPC_PROBE_CHIPSET opt_ppc.h +MP_WATCHDOG opt_mp_watchdog.h + +# Options for emulators. These should only be used at config time, so +# they are handled like options for static filesystems +# (see src/sys/conf/options), except for broken debugging options. +COMPAT_AOUT opt_dontuse.h +IBCS2 opt_dontuse.h +COMPAT_LINUX opt_dontuse.h +COMPAT_SVR4 opt_dontuse.h +DEBUG_SVR4 opt_svr4.h +NDISAPI opt_dontuse.h +PECOFF_DEBUG opt_pecoff.h +PECOFF_SUPPORT opt_dontuse.h + +# Change KVM size. Changes things all over the kernel. +KVA_PAGES opt_global.h +XEN opt_global.h + +# Physical address extensions and support for >4G ram. As above. +PAE opt_global.h + +CLK_CALIBRATION_LOOP opt_clock.h +CLK_USE_I8254_CALIBRATION opt_clock.h +TIMER_FREQ opt_clock.h + +CPU_ATHLON_SSE_HACK opt_cpu.h +CPU_BLUELIGHTNING_3X opt_cpu.h +CPU_BLUELIGHTNING_FPU_OP_CACHE opt_cpu.h +CPU_BTB_EN opt_cpu.h +CPU_CYRIX_NO_LOCK opt_cpu.h +CPU_DIRECT_MAPPED_CACHE opt_cpu.h +CPU_DISABLE_5X86_LSSER opt_cpu.h +CPU_DISABLE_CMPXCHG opt_global.h # XXX global, unlike other CPU_* +CPU_DISABLE_SSE opt_cpu.h +CPU_ELAN opt_cpu.h +CPU_ELAN_PPS opt_cpu.h +CPU_ELAN_XTAL opt_cpu.h +CPU_ENABLE_LONGRUN opt_cpu.h +CPU_FASTER_5X86_FPU opt_cpu.h +CPU_GEODE opt_cpu.h +CPU_I486_ON_386 opt_cpu.h +CPU_IORT opt_cpu.h +CPU_L2_LATENCY opt_cpu.h +CPU_LOOP_EN opt_cpu.h +CPU_PPRO2CELERON opt_cpu.h +CPU_RSTK_EN opt_cpu.h +CPU_SOEKRIS opt_cpu.h +CPU_SUSP_HLT opt_cpu.h +CPU_UPGRADE_HW_CACHE opt_cpu.h +CPU_WT_ALLOC opt_cpu.h +CYRIX_CACHE_REALLY_WORKS opt_cpu.h +CYRIX_CACHE_WORKS opt_cpu.h +NO_F00F_HACK opt_cpu.h +NO_MEMORY_HOLE opt_cpu.h + +# The CPU type affects the endian conversion functions all over the kernel. +I486_CPU opt_global.h +I586_CPU opt_global.h +I686_CPU opt_global.h + +VGA_ALT_SEQACCESS opt_vga.h +VGA_DEBUG opt_vga.h +VGA_NO_FONT_LOADING opt_vga.h +VGA_NO_MODE_CHANGE opt_vga.h +VGA_SLOW_IOACCESS opt_vga.h +VGA_WIDTH90 opt_vga.h + +VESA +VESA_DEBUG opt_vesa.h + +PSM_DEBUG opt_psm.h +PSM_HOOKRESUME opt_psm.h +PSM_RESETAFTERSUSPEND opt_psm.h + +ATKBD_DFLT_KEYMAP opt_atkbd.h + +# pcvt(4) has a bunch of options +FAT_CURSOR opt_pcvt.h +PCVT_123GENERIC opt_pcvt.h +PCVT_24LINESDEF opt_pcvt.h +PCVT_CTRL_ALT_DEL opt_pcvt.h +PCVT_GREENSAVER opt_pcvt.h +PCVT_INHIBIT_NUMLOCK opt_pcvt.h +PCVT_META_ESC opt_pcvt.h +PCVT_NO_LED_UPDATE opt_pcvt.h +PCVT_NSCREENS opt_pcvt.h +PCVT_NULLCHARS opt_pcvt.h +PCVT_PRETTYSCRNS opt_pcvt.h +PCVT_SCANSET opt_pcvt.h +PCVT_SCREENSAVER opt_pcvt.h +PCVT_SETCOLOR opt_pcvt.h +PCVT_SHOWKEYS opt_pcvt.h +PCVT_SLOW_INTERRUPT opt_pcvt.h +PCVT_SYSBEEPF opt_pcvt.h +PCVT_UPDATEFAST opt_pcvt.h +PCVT_UPDATESLOW opt_pcvt.h +PCVT_USEKBDSEC opt_pcvt.h +PCVT_VT220KEYB opt_pcvt.h +XSERVER opt_pcvt.h + +# Video spigot +SPIGOT_UNSECURE opt_spigot.h + +# Enables NETGRAPH support for Cronyx adapters +NETGRAPH_CRONYX opt_ng_cronyx.h + +# ------------------------------- +# isdn4bsd: passive ISA cards +# ------------------------------- +TEL_S0_8 opt_i4b.h +TEL_S0_16 opt_i4b.h +TEL_S0_16_3 opt_i4b.h +AVM_A1 opt_i4b.h +USR_STI opt_i4b.h +ITKIX1 opt_i4b.h +ELSA_PCC16 opt_i4b.h +# ------------------------------- +# isdn4bsd: passive ISA PnP cards +# ------------------------------- +CRTX_S0_P opt_i4b.h +DRN_NGO opt_i4b.h +TEL_S0_16_3_P opt_i4b.h +SEDLBAUER opt_i4b.h +DYNALINK opt_i4b.h +ASUSCOM_IPAC opt_i4b.h +ELSA_QS1ISA opt_i4b.h +SIEMENS_ISURF2 opt_i4b.h +EICON_DIVA opt_i4b.h +COMPAQ_M610 opt_i4b.h +# ------------------------------- +# isdn4bsd: passive PCI cards +# ------------------------------- +ELSA_QS1PCI opt_i4b.h +# ------------------------------- +# isdn4bsd: misc options +# ------------------------------- +# temporary workaround for SMP machines +I4B_SMP_WORKAROUND opt_i4b.h +# enable VJ compression code for ipr i/f +IPR_VJ opt_i4b.h +IPR_LOG opt_i4b.h + +# Device options +DEV_APIC opt_apic.h +DEV_NPX opt_npx.h +ASR_COMPAT opt_asr.h + +# Debugging +STOP_NMI opt_cpu.h +NPX_DEBUG opt_npx.h + +# XBOX support in the kernel +XBOX opt_xbox.h Index: dev/xen/blkfront/blkfront.c =================================================================== RCS file: dev/xen/blkfront/blkfront.c diff -N dev/xen/blkfront/blkfront.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/blkfront/blkfront.c 2 Jan 2006 07:36:44 -0000 @@ -0,0 +1,1029 @@ +/*- + * All rights reserved. + * + * 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. + * + */ + +/* + * XenoBSD block device driver + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define ASSERT(S) KASSERT(S, (#S)) +/* prototypes */ +struct xb_softc; +static void xb_startio(struct xb_softc *sc); +static void connect(struct blkfront_info *); +static void blkfront_closing(struct xenbus_device *); +static int blkfront_remove(struct xenbus_device *); +static int talk_to_backend(struct xenbus_device *, struct blkfront_info *); +static int setup_blkring(struct xenbus_device *, struct blkfront_info *); +static void blkif_int(void *); +#if 0 +static void blkif_restart_queue(void *arg); +#endif +static void blkif_recover(struct blkfront_info *); +static void blkif_completion(struct blk_shadow *); +static void blkif_free(struct blkfront_info *, int); + +#define GRANT_INVALID_REF 0 +#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) + +LIST_HEAD(xb_softc_list_head, xb_softc) xbsl_head; + +/* Control whether runtime update of vbds is enabled. */ +#define ENABLE_VBD_UPDATE 0 + +#if ENABLE_VBD_UPDATE +static void vbd_update(void); +#endif + + +#define BLKIF_STATE_DISCONNECTED 0 +#define BLKIF_STATE_CONNECTED 1 +#define BLKIF_STATE_SUSPENDED 2 + +#ifdef notyet +static char *blkif_state_name[] = { + [BLKIF_STATE_DISCONNECTED] = "disconnected", + [BLKIF_STATE_CONNECTED] = "connected", + [BLKIF_STATE_SUSPENDED] = "closed", +}; + +static char * blkif_status_name[] = { + [BLKIF_INTERFACE_STATUS_CLOSED] = "closed", + [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", + [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected", + [BLKIF_INTERFACE_STATUS_CHANGED] = "changed", +}; +#endif +#define WPRINTK(fmt, args...) printf("[XEN] " fmt, ##args) +#if 0 +#define DPRINTK(fmt, args...) printf("[XEN] %s:%d" fmt ".\n", __FUNCTION__, __LINE__,##args) +#else +#define DPRINTK(fmt, args...) +#endif + +static grant_ref_t gref_head; +#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ + (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE) + +static struct mtx blkif_io_block_lock; + +static void kick_pending_request_queues(struct blkfront_info *); +static int blkif_open(struct disk *dp); +static int blkif_close(struct disk *dp); +static int blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td); +static int blkif_queue_request(struct bio *bp); +static void xb_strategy(struct bio *bp); + + + +/* XXX move to xb_vbd.c when VBD update support is added */ +#define MAX_VBDS 64 + +#define XBD_SECTOR_SIZE 512 /* XXX: assume for now */ +#define XBD_SECTOR_SHFT 9 + +static struct mtx blkif_io_lock; +static struct mtx bioq_lock; + +static unsigned long +pfn_to_mfn(unsigned long pfn) +{ + return (phystomach(pfn << PAGE_SHIFT) >> PAGE_SHIFT); +} + + +int +xlvbd_add(blkif_sector_t capacity, int unit, uint16_t vdisk_info, uint16_t sector_size, + struct blkfront_info *info) +{ + struct xb_softc *sc; + int error = 0; + + sc = (struct xb_softc *)malloc(sizeof(*sc), M_DEVBUF, M_WAITOK); + sc->xb_unit = unit; + sc->xb_info = info; + info->sc = sc; + + memset(&sc->xb_disk, 0, sizeof(sc->xb_disk)); + sc->xb_disk.d_unit = unit; + sc->xb_disk.d_open = blkif_open; + sc->xb_disk.d_close = blkif_close; + sc->xb_disk.d_ioctl = blkif_ioctl; + sc->xb_disk.d_strategy = xb_strategy; + sc->xb_disk.d_name = "xbd"; + sc->xb_disk.d_drv1 = sc; + sc->xb_disk.d_sectorsize = sector_size; + + /* XXX */ + sc->xb_disk.d_mediasize = capacity << XBD_SECTOR_SHFT; +#if 0 + sc->xb_disk.d_maxsize = DFLTPHYS; +#else /* XXX: xen can't handle large single i/o requests */ + sc->xb_disk.d_maxsize = 4096; +#endif +#ifdef notyet + XENPRINTF("attaching device 0x%x unit %d capacity %llu\n", + xb_diskinfo[sc->xb_unit].device, sc->xb_unit, + sc->xb_disk.d_mediasize); +#endif + disk_create(&sc->xb_disk, DISK_VERSION_00); + bioq_init(&sc->xb_bioq); + + return error; +} + +void +xlvbd_del(struct blkfront_info *info) +{ + ; +} +/************************ end VBD support *****************/ + +#define USELOCK 0 + +/* + * Read/write routine for a buffer. Finds the proper unit, place it on + * the sortq and kick the controller. + */ +static void +xb_strategy(struct bio *bp) +{ + struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; + int flags; + + /* bogus disk? */ + if (sc == NULL) { + bp->bio_error = EINVAL; + bp->bio_flags |= BIO_ERROR; + goto bad; + } + + DPRINTK(""); +#if USELOCK + mtx_lock_irqsave(&bioq_lock, flags); +#else + flags = splbio(); +#endif + /* + * Place it in the queue of disk activities for this disk + */ + bioq_disksort(&sc->xb_bioq, bp); +#if USELOCK + mtx_unlock_irqrestore(&bioq_lock, flags); +#else + splx(flags); +#endif + + xb_startio(sc); + return; + + bad: + /* + * Correctly set the bio to indicate a failed tranfer. + */ + bp->bio_resid = bp->bio_bcount; + biodone(bp); + return; +} + + +/* Setup supplies the backend dir, virtual device. + + We place an event channel and shared frame entries. + We watch backend to wait if it's ok. */ +static int blkfront_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int err, vdevice, i; + struct blkfront_info *info; + + /* FIXME: Use dynamic device id if this is not set. */ + err = xenbus_scanf(NULL, dev->nodename, + "virtual-device", "%i", &vdevice); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading virtual-device"); + return err; + } + + info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK); + if (!info) { + xenbus_dev_fatal(dev, ENOMEM, "allocating info structure"); + return ENOMEM; + } + info->xbdev = dev; + info->vdevice = vdevice; + info->connected = BLKIF_STATE_DISCONNECTED; + info->mi = NULL; + info->gd = NULL; + + /* work queue needed ? */ + info->shadow_free = 0; + memset(info->shadow, 0, sizeof(info->shadow)); + for (i = 0; i < BLK_RING_SIZE; i++) + info->shadow[i].req.id = i+1; + info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + info->users = 0; + + /* Front end dir is a number, which is used as the id. */ + info->handle = strtoul(strrchr(dev->nodename,'/')+1, NULL, 0); + dev->data = info; + + err = talk_to_backend(dev, info); + if (err) { + free(info, M_DEVBUF); + dev->data = NULL; + return err; + } + + return 0; +} + + +static int blkfront_resume(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->data; + int err; + + DPRINTK("blkfront_resume: %s\n", dev->nodename); + + blkif_free(info, 1); + + err = talk_to_backend(dev, info); + if (!err) + blkif_recover(info); + + return err; +} + +/* Common code used when first setting up, and when resuming. */ +static int talk_to_backend(struct xenbus_device *dev, + struct blkfront_info *info) +{ + const char *message = NULL; + struct xenbus_transaction *xbt; + int err; + + /* Create shared ring, alloc event channel. */ + err = setup_blkring(dev, info); + if (err) + goto out; + +again: + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { + xenbus_dev_fatal(dev, err, "starting transaction"); + goto destroy_blkring; + } + + err = xenbus_printf(xbt, dev->nodename, + "ring-ref","%u", info->ring_ref); + if (err) { + message = "writing ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, + "event-channel", "%u", info->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_switch_state(dev, xbt, XenbusStateInitialised); + if (err) { + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0); + if (err) { + if (err == EAGAIN) + goto again; + xenbus_dev_fatal(dev, err, "completing transaction"); + goto destroy_blkring; + } + + return 0; + + abort_transaction: + xenbus_transaction_end(xbt, 1); + if (message) + xenbus_dev_fatal(dev, err, "%s", message); + destroy_blkring: + blkif_free(info, 0); + out: + return err; +} + +static int +setup_blkring(struct xenbus_device *dev, struct blkfront_info *info) +{ + blkif_sring_t *sring; + int err; + + info->ring_ref = GRANT_INVALID_REF; + + sring = (blkif_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); + if (!sring) { + xenbus_dev_fatal(dev, ENOMEM, "allocating shared ring"); + return ENOMEM; + } + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); + + err = xenbus_grant_ring(dev, (vtomach(info->ring.sring) >> PAGE_SHIFT)); + if (err < 0) { + free(sring, M_DEVBUF); + info->ring.sring = NULL; + goto fail; + } + info->ring_ref = err; + + err = xenbus_alloc_evtchn(dev, &info->evtchn); + if (err) + goto fail; + err = bind_evtchn_to_irqhandler(info->evtchn, "xbd", + (driver_intr_t *)blkif_int, + info, INTR_TYPE_BIO | INTR_MPSAFE); + if (err <= 0) { + xenbus_dev_fatal(dev, err, + "bind_evtchn_to_irqhandler failed"); + goto fail; + } + info->irq = err; + + return 0; +fail: + blkif_free(info, 0); + return err; +} + + +/** + * Callback received when the backend's state changes. + */ +static void backend_changed(struct xenbus_device *dev, + XenbusState backend_state) +{ + struct blkfront_info *info = dev->data; + + DPRINTK("blkfront:backend_changed.\n"); + + switch (backend_state) { + case XenbusStateUnknown: + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateClosed: + break; + + case XenbusStateConnected: + connect(info); + break; + + case XenbusStateClosing: + panic("not implemented"); +#ifdef notyet + bd = bdget(info->dev); + if (bd == NULL) + xenbus_dev_fatal(dev, -ENODEV, "bdget failed"); + + down(&bd->bd_sem); + if (info->users > 0) + xenbus_dev_error(dev, -EBUSY, + "Device in use; refusing to close"); + else + blkfront_closing(dev); + up(&bd->bd_sem); + bdput(bd); +#endif + } +} + +/* +** Invoked when the backend is finally 'ready' (and has told produced +** the details about the physical device - #sectors, size, etc). +*/ +static void +connect(struct blkfront_info *info) +{ + unsigned long sectors, sector_size; + unsigned int binfo; + int err; + + if( (info->connected == BLKIF_STATE_CONNECTED) || + (info->connected == BLKIF_STATE_SUSPENDED) ) + return; + + DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend); + + err = xenbus_gather(NULL, info->xbdev->otherend, + "sectors", "%lu", §ors, + "info", "%u", &binfo, + "sector-size", "%lu", §or_size, + NULL); + if (err) { + xenbus_dev_fatal(info->xbdev, err, + "reading backend fields at %s", + info->xbdev->otherend); + return; + } + + xlvbd_add(sectors, info->vdevice, binfo, sector_size, info); + + (void)xenbus_switch_state(info->xbdev, NULL, XenbusStateConnected); + + /* Kick pending requests. */ + mtx_lock_spin(&blkif_io_lock); + info->connected = BLKIF_STATE_CONNECTED; + kick_pending_request_queues(info); + mtx_unlock_spin(&blkif_io_lock); + +#if 0 + add_disk(info->gd); +#endif +} + +/** + * Handle the change of state of the backend to Closing. We must delete our + * device-layer structures now, to ensure that writes are flushed through to + * the backend. Once is this done, we can switch to Closed in + * acknowledgement. + */ +static void blkfront_closing(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->data; + + DPRINTK("blkfront_closing: %s removed\n", dev->nodename); + + if (info->mi) { + DPRINTK("Calling xlvbd_del\n"); + xlvbd_del(info); + info->mi = NULL; + } + + xenbus_switch_state(dev, NULL, XenbusStateClosed); +} + + +static int blkfront_remove(struct xenbus_device *dev) +{ + struct blkfront_info *info = dev->data; + + DPRINTK("blkfront_remove: %s removed\n", dev->nodename); + + blkif_free(info, 0); + + free(info, M_DEVBUF); + + return 0; +} + + +static inline int +GET_ID_FROM_FREELIST(struct blkfront_info *info) +{ + unsigned long free = info->shadow_free; + KASSERT(free <= BLK_RING_SIZE, ("free %lu > RING_SIZE", free)); + info->shadow_free = info->shadow[free].req.id; + info->shadow[free].req.id = 0x0fffffee; /* debug */ + return free; +} + +static inline void +ADD_ID_TO_FREELIST(struct blkfront_info *info, unsigned long id) +{ + info->shadow[id].req.id = info->shadow_free; + info->shadow[id].request = 0; + info->shadow_free = id; +} + +static inline void +flush_requests(struct blkfront_info *info) +{ + int notify; + + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify); + + if (notify) + notify_remote_via_irq(info->irq); +} + +static void +kick_pending_request_queues(struct blkfront_info *info) +{ + /* XXX check if we can't simplify */ +#if 0 + if (!RING_FULL(&info->ring)) { + /* Re-enable calldowns. */ + blk_start_queue(info->rq); + /* Kick things off immediately. */ + do_blkif_request(info->rq); + } +#endif + if (!RING_FULL(&info->ring)) { +#if 0 + sc = LIST_FIRST(&xbsl_head); + LIST_REMOVE(sc, entry); + /* Re-enable calldowns. */ + blk_start_queue(di->rq); +#endif + /* Kick things off immediately. */ + xb_startio(info->sc); + } +} + +#if 0 +/* XXX */ +static void blkif_restart_queue(void *arg) +{ + struct blkfront_info *info = (struct blkfront_info *)arg; + mtx_lock_spin(&blkif_io_lock); + kick_pending_request_queues(info); + mtx_unlock_spin(&blkif_io_lock); +} +#endif + +static void blkif_restart_queue_callback(void *arg) +{ +#if 0 + struct blkfront_info *info = (struct blkfront_info *)arg; + /* XXX BSD equiv ? */ + + schedule_work(&info->work); +#endif +} + +static int +blkif_open(struct disk *dp) +{ + struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; + + if (sc == NULL) { + printk("xb%d: not found", sc->xb_unit); + return (ENXIO); + } + + sc->xb_flags |= XB_OPEN; + sc->xb_info->users++; + return (0); +} + +static int +blkif_close(struct disk *dp) +{ + struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; + + if (sc == NULL) + return (ENXIO); + sc->xb_flags &= ~XB_OPEN; + if (--(sc->xb_info->users) == 0) { + /* Check whether we have been instructed to close. We will + have ignored this request initially, as the device was + still mounted. */ + struct xenbus_device * dev = sc->xb_info->xbdev; + XenbusState state = xenbus_read_driver_state(dev->otherend); + + if (state == XenbusStateClosing) + blkfront_closing(dev); + } + return (0); +} + +static int +blkif_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td) +{ + struct xb_softc *sc = (struct xb_softc *)dp->d_drv1; + + if (sc == NULL) + return (ENXIO); + + return (ENOTTY); +} + + +/* + * blkif_queue_request + * + * request block io + * + * id: for guest use only. + * operation: BLKIF_OP_{READ,WRITE,PROBE} + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + */ +static int blkif_queue_request(struct bio *bp) +{ + unsigned long buffer_ma; + blkif_request_t *ring_req; + unsigned long id; + unsigned int fsect, lsect; + struct xb_softc *sc = (struct xb_softc *)bp->bio_disk->d_drv1; + struct blkfront_info *info = sc->xb_info; + int ref; + + if (unlikely(sc->xb_info->connected != BLKIF_STATE_CONNECTED)) + return 1; + + if (gnttab_alloc_grant_references( + BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) { + gnttab_request_free_callback( + &info->callback, + blkif_restart_queue_callback, + info, + BLKIF_MAX_SEGMENTS_PER_REQUEST); + return 1; + } + + /* Check if the buffer is properly aligned */ + if ((vm_offset_t)bp->bio_data & PAGE_MASK) { + int align = (bp->bio_bcount < PAGE_SIZE/2) ? XBD_SECTOR_SIZE : + PAGE_SIZE; + caddr_t newbuf = malloc(bp->bio_bcount + align, M_DEVBUF, + M_NOWAIT); + caddr_t alignbuf = (char *)roundup2((u_long)newbuf, align); + + /* save a copy of the current buffer */ + bp->bio_driver1 = bp->bio_data; + + /* Copy the data for a write */ + if (bp->bio_cmd == BIO_WRITE) + bcopy(bp->bio_data, alignbuf, bp->bio_bcount); + bp->bio_data = alignbuf; + } + + /* Fill out a communications ring structure. */ + ring_req = RING_GET_REQUEST(&info->ring, + info->ring.req_prod_pvt); + id = GET_ID_FROM_FREELIST(info); + info->shadow[id].request = (unsigned long)bp; + + ring_req->id = id; + ring_req->operation = (bp->bio_cmd == BIO_READ) ? BLKIF_OP_READ : + BLKIF_OP_WRITE; + + ring_req->sector_number= (blkif_sector_t)bp->bio_pblkno; + ring_req->handle = (unsigned long)&sc->xb_disk; + + ring_req->nr_segments = 0; /* XXX not doing scatter/gather since buffer + * chaining is not supported. + */ + + buffer_ma = vtomach(bp->bio_data); + fsect = (buffer_ma & PAGE_MASK) >> XBD_SECTOR_SHFT; + lsect = fsect + (bp->bio_bcount >> XBD_SECTOR_SHFT) - 1; + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head); + KASSERT( ref != -ENOSPC, ("grant_reference failed") ); + + gnttab_grant_foreign_access_ref( + ref, + info->xbdev->otherend_id, + buffer_ma >> PAGE_SHIFT, + ring_req->operation & 1 ); /* ??? */ + info->shadow[id].frame[ring_req->nr_segments] = + buffer_ma >> PAGE_SHIFT; + + ring_req->seg[ring_req->nr_segments] = + (struct blkif_request_segment) { + .gref = ref, + .first_sect = fsect, + .last_sect = lsect }; + + ring_req->nr_segments++; + KASSERT((buffer_ma & (XBD_SECTOR_SIZE-1)) == 0, + ("XEN buffer must be sector aligned")); + KASSERT(lsect <= 7, + ("XEN disk driver data cannot cross a page boundary")); + + buffer_ma &= ~PAGE_MASK; + + info->ring.req_prod_pvt++; + + /* Keep a private copy so we can reissue requests when recovering. */ + info->shadow[id].req = *ring_req; + + gnttab_free_grant_references(gref_head); + + return 0; +} + + + +/* + * Dequeue buffers and place them in the shared communication ring. + * Return when no more requests can be accepted or all buffers have + * been queued. + * + * Signal XEN once the ring has been filled out. + */ +static void +xb_startio(struct xb_softc *sc) +{ + struct bio *bp; + int flags, queued = 0; + struct blkfront_info *info = sc->xb_info; + DPRINTK(""); +#if USELOCK + mtx_lock_irqsave(&bioq_lock, flags); +#else + flags = splbio(); +#endif + while ((bp = bioq_takefirst(&sc->xb_bioq)) != NULL) { + + if (RING_FULL(&info->ring)) + goto wait; + +#if USELOCK + mtx_unlock_irqrestore(&bioq_lock, flags); +#else + splx(flags); +#endif + if (blkif_queue_request(bp)) { +#if USELOCK + mtx_lock_irqsave(&bioq_lock, flags); +#else + flags = splbio(); +#endif + wait: + bioq_disksort(&sc->xb_bioq, bp); +#if USELOCK + mtx_unlock_irqrestore(&bioq_lock, flags); +#else + splx(flags); +#endif + break; + } + queued++; + } + + if (queued != 0) + flush_requests(sc->xb_info); +} + +static void +blkif_int(void *xsc) +{ + struct xb_softc *sc = NULL; + struct bio *bp; + blkif_response_t *bret; + RING_IDX i, rp; + unsigned long flags; + struct blkfront_info *info = xsc; + DPRINTK(""); + + TRACE_ENTER; + + mtx_lock_irqsave(&blkif_io_lock, flags); + + if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { + mtx_unlock_irqrestore(&blkif_io_lock, flags); + return; + } + + again: + rp = info->ring.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for (i = info->ring.rsp_cons; i != rp; i++) { + unsigned long id; + + bret = RING_GET_RESPONSE(&info->ring, i); + id = bret->id; + bp = (struct bio *)info->shadow[id].request; + + blkif_completion(&info->shadow[id]); + + ADD_ID_TO_FREELIST(info, id); + + switch (bret->operation) { + case BLKIF_OP_READ: + /* had an unaligned buffer that needs to be copied */ + if (bp->bio_driver1) + bcopy(bp->bio_data, bp->bio_driver1, bp->bio_bcount); + case BLKIF_OP_WRITE: + + /* free the copy buffer */ + if (bp->bio_driver1) { + free(bp->bio_data, M_DEVBUF); + bp->bio_data = bp->bio_driver1; + bp->bio_driver1 = NULL; + } + + if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) { + XENPRINTF("Bad return from blkdev data request: %x\n", + bret->status); + bp->bio_flags |= BIO_ERROR; + } + + sc = (struct xb_softc *)bp->bio_disk->d_drv1; + + if (bp->bio_flags & BIO_ERROR) + bp->bio_error = EIO; + else + bp->bio_resid = 0; + + biodone(bp); + break; + default: + panic("received invalid operation"); + break; + } + } + + info->ring.rsp_cons = i; + + if (i != info->ring.req_prod_pvt) { + int more_to_do; + RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do); + if (more_to_do) + goto again; + } else { + info->ring.sring->rsp_event = i + 1; + } + + kick_pending_request_queues(info); + + mtx_unlock_irqrestore(&blkif_io_lock, flags); +} + +static void +blkif_free(struct blkfront_info *info, int suspend) +{ + +/* Prevent new requests being issued until we fix things up. */ + mtx_lock_spin(&blkif_io_lock); + info->connected = suspend ? + BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; + mtx_unlock_spin(&blkif_io_lock); + + /* Free resources associated with old device channel. */ + if (info->ring_ref != GRANT_INVALID_REF) { + gnttab_end_foreign_access(info->ring_ref, 0, + info->ring.sring); + info->ring_ref = GRANT_INVALID_REF; + info->ring.sring = NULL; + } + if (info->irq) + unbind_from_irqhandler(info->irq, info); + info->evtchn = info->irq = 0; + +} + +static void +blkif_completion(struct blk_shadow *s) +{ + int i; + + for (i = 0; i < s->req.nr_segments; i++) + gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL); +} + +static void +blkif_recover(struct blkfront_info *info) +{ + int i, j; + blkif_request_t *req; + struct blk_shadow *copy; + + /* Stage 1: Make a safe copy of the shadow state. */ + copy = (struct blk_shadow *)malloc(sizeof(info->shadow), M_DEVBUF, M_NOWAIT); + PANIC_IF(copy == NULL); + memcpy(copy, info->shadow, sizeof(info->shadow)); + + /* Stage 2: Set up free list. */ + memset(&info->shadow, 0, sizeof(info->shadow)); + for (i = 0; i < BLK_RING_SIZE; i++) + info->shadow[i].req.id = i+1; + info->shadow_free = info->ring.req_prod_pvt; + info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + /* Stage 3: Find pending requests and requeue them. */ + for (i = 0; i < BLK_RING_SIZE; i++) { + /* Not in use? */ + if (copy[i].request == 0) + continue; + + /* Grab a request slot and copy shadow state into it. */ + req = RING_GET_REQUEST( + &info->ring, info->ring.req_prod_pvt); + *req = copy[i].req; + + /* We get a new request id, and must reset the shadow state. */ + req->id = GET_ID_FROM_FREELIST(info); + memcpy(&info->shadow[req->id], ©[i], sizeof(copy[i])); + + /* Rewrite any grant references invalidated by suspend/resume. */ + for (j = 0; j < req->nr_segments; j++) + gnttab_grant_foreign_access_ref( + req->seg[j].gref, + info->xbdev->otherend_id, + pfn_to_mfn(info->shadow[req->id].frame[j]), + 0 /* assume not readonly */); + + info->shadow[req->id].req = *req; + + info->ring.req_prod_pvt++; + } + + free(copy, M_DEVBUF); + + (void)xenbus_switch_state(info->xbdev, NULL, XenbusStateConnected); + + /* Now safe for us to use the shared ring */ + mtx_lock_spin(&blkif_io_lock); + info->connected = BLKIF_STATE_CONNECTED; + mtx_unlock_spin(&blkif_io_lock); + + /* Send off requeued requests */ + flush_requests(info); + + /* Kick any other new requests queued since we resumed */ + mtx_lock_spin(&blkif_io_lock); + kick_pending_request_queues(info); + mtx_unlock_spin(&blkif_io_lock); +} + +static struct xenbus_device_id blkfront_ids[] = { + { "vbd" }, + { "" } +}; + + +static struct xenbus_driver blkfront = { + .name = "vbd", + .ids = blkfront_ids, + .probe = blkfront_probe, + .remove = blkfront_remove, + .resume = blkfront_resume, + .otherend_changed = backend_changed, +}; + + + +static void +xenbus_init(void) +{ + xenbus_register_frontend(&blkfront); + +} + +MTX_SYSINIT(ioreq, &blkif_io_lock, "BIO LOCK", MTX_SPIN | MTX_NOWITNESS); /* XXX how does one enroll a lock? */ +MTX_SYSINIT(bio, &bioq_lock, "BIOQ LOCK", MTX_SPIN | MTX_NOWITNESS); /* XXX how does one enroll a lock? */ +MTX_SYSINIT(ioreq_block, &blkif_io_block_lock, "BIO BLOCK LOCK", MTX_SPIN | MTX_NOWITNESS); +SYSINIT(xbdev, SI_SUB_PSEUDO, SI_ORDER_ANY, xenbus_init, NULL); + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ Index: dev/xen/blkfront/block.h =================================================================== RCS file: dev/xen/blkfront/block.h diff -N dev/xen/blkfront/block.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/blkfront/block.h 31 Dec 2005 20:54:47 -0000 @@ -0,0 +1,80 @@ +#ifndef __XEN_DRIVERS_BLOCK_H__ +#define __XEN_DRIVERS_BLOCK_H__ + +struct xlbd_type_info +{ + int partn_shift; + int disks_per_major; + char *devname; + char *diskname; +}; + +struct xlbd_major_info +{ + int major; + int index; + int usage; + struct xlbd_type_info *type; +}; + +struct blk_shadow { + blkif_request_t req; + unsigned long request; + unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +}; + +#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) + + +struct xb_softc { + device_t xb_dev; + struct disk xb_disk; /* disk params */ + struct bio_queue_head xb_bioq; /* sort queue */ + int xb_unit; + int xb_flags; + struct blkfront_info *xb_info; + LIST_ENTRY(xb_softc) entry; +#define XB_OPEN (1<<0) /* drive is open (can't shut down) */ +}; + + +/* + * We have one of these per vbd, whether ide, scsi or 'other'. They + * hang in private_data off the gendisk structure. We may end up + * putting all kinds of interesting stuff here :-) + */ +struct blkfront_info +{ + struct xenbus_device *xbdev; + dev_t dev; + struct gendisk *gd; + int vdevice; + blkif_vdev_t handle; + int connected; + int ring_ref; + blkif_front_ring_t ring; + unsigned int evtchn, irq; + struct xlbd_major_info *mi; +#if 0 + request_queue_t *rq; + struct work_struct work; +#endif + struct gnttab_free_callback callback; + struct blk_shadow shadow[BLK_RING_SIZE]; + unsigned long shadow_free; + struct xb_softc *sc; + /** + * The number of people holding this device open. We won't allow a + * hot-unplug unless this is 0. + */ + int users; +}; +/* Note that xlvbd_add doesn't call add_disk for you: you're expected + to call add_disk on info->gd once the disk is properly connected + up. */ +int xlvbd_add(blkif_sector_t capacity, int device, + uint16_t vdisk_info, uint16_t sector_size, struct blkfront_info *info); +void xlvbd_del(struct blkfront_info *info); + +#endif /* __XEN_DRIVERS_BLOCK_H__ */ + Index: dev/xen/console/console.c =================================================================== RCS file: dev/xen/console/console.c diff -N dev/xen/console/console.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/console/console.c 1 Jan 2006 08:41:15 -0000 @@ -0,0 +1,543 @@ +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "opt_ddb.h" +#ifdef DDB +#include +#endif + +static char driver_name[] = "xc"; +devclass_t xc_devclass; /* do not make static */ +static void xcstart (struct tty *); +static int xcparam (struct tty *, struct termios *); +static void xcstop (struct tty *, int); +static void xc_timeout(void *); +static void __xencons_tx_flush(void); +static boolean_t xcons_putc(int c); + +/* switch console so that shutdown can occur gracefully */ +static void xc_shutdown(void *arg, int howto); +static int xc_mute; + +void xcons_force_flush(void); + +static cn_probe_t xccnprobe; +static cn_init_t xccninit; +static cn_getc_t xccngetc; +static cn_putc_t xccnputc; +static cn_checkc_t xccncheckc; + +#define XC_POLLTIME (hz/10) + +CONS_DRIVER(xc, xccnprobe, xccninit, NULL, xccngetc, + xccncheckc, xccnputc, NULL); + +static int xen_console_up; +static boolean_t xc_start_needed; +static struct callout xc_callout; +struct mtx cn_mtx; + +#define RBUF_SIZE 1024 +#define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1)) +#define WBUF_SIZE 4096 +#define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1)) +static char wbuf[WBUF_SIZE]; +static char rbuf[RBUF_SIZE]; +static int rc, rp; +static unsigned int cnsl_evt_reg; +static unsigned int wc, wp; /* write_cons, write_prod */ + +#define CDEV_MAJOR 12 +#define XCUNIT(x) (minor(x)) +#define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN)) +#define CN_LOCK_INIT(x, _name) \ + mtx_init(&x, _name, _name, MTX_SPIN) +#define CN_LOCK(l, f) mtx_lock_irqsave(&(l), (f)) +#define CN_UNLOCK(l, f) mtx_unlock_irqrestore(&(l), (f)) +#define CN_LOCK_ASSERT(x) mtx_assert(&x, MA_OWNED) +#define CN_LOCK_DESTROY(x) mtx_destroy(&x) + + +static struct tty *xccons; + +struct xc_softc { + int xc_unit; + struct cdev *xc_dev; +}; + + +static d_open_t xcopen; +static d_close_t xcclose; +static d_ioctl_t xcioctl; + +static struct cdevsw xc_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_TTY | D_NEEDGIANT, + .d_name = driver_name, + .d_open = xcopen, + .d_close = xcclose, + .d_read = ttyread, + .d_write = ttywrite, + .d_ioctl = xcioctl, + .d_poll = ttypoll, + .d_kqfilter = ttykqfilter, +}; + +static void +xccnprobe(struct consdev *cp) +{ + cp->cn_pri = CN_REMOTE; + cp->cn_tp = xccons; + sprintf(cp->cn_name, "%s0", driver_name); +} + + +static void +xccninit(struct consdev *cp) +{ + CN_LOCK_INIT(cn_mtx,"XCONS LOCK"); + +} +int +xccngetc(struct consdev *dev) +{ + int c; + if (xc_mute) + return 0; + do { + if ((c = xccncheckc(dev)) == -1) { + /* polling without sleeping in Xen doesn't work well. + * Sleeping gives other things like clock a chance to + * run + */ + tsleep(&cn_mtx, PWAIT | PCATCH, "console sleep", + XC_POLLTIME); + } + } while( c == -1 ); + return c; +} + +int +xccncheckc(struct consdev *dev) +{ + int ret = (xc_mute ? 0 : -1); + int flags; + CN_LOCK(cn_mtx, flags); + if ( (rp - rc) ){ + /* we need to return only one char */ + ret = (int)rbuf[RBUF_MASK(rc)]; + rc++; + } + CN_UNLOCK(cn_mtx, flags); + return(ret); +} + +static void +xccnputc(struct consdev *dev, int c) +{ + int flags; + CN_LOCK(cn_mtx, flags); + xcons_putc(c); + CN_UNLOCK(cn_mtx, flags); +} + +static boolean_t +xcons_putc(int c) +{ + int force_flush = xc_mute || +#ifdef DDB + db_active || +#endif + panicstr; /* we're not gonna recover, so force + * flush + */ + + if ( (wp-wc) < (WBUF_SIZE-1) ){ + if ( (wbuf[WBUF_MASK(wp++)] = c) == '\n' ) { + wbuf[WBUF_MASK(wp++)] = '\r'; +#ifdef notyet + if (force_flush) + xcons_force_flush(); +#endif + } + } else if (force_flush) { +#ifdef notyet + xcons_force_flush(); +#endif + } + if (cnsl_evt_reg) + __xencons_tx_flush(); + + /* inform start path that we're pretty full */ + return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE; +} + +static void +xc_identify(driver_t *driver, device_t parent) +{ + device_t child; + child = BUS_ADD_CHILD(parent, 0, driver_name, 0); + device_set_driver(child, driver); + device_set_desc(child, "Xen Console"); +} + +static int +xc_probe(device_t dev) +{ + struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev); + + sc->xc_unit = device_get_unit(dev); + return (0); +} + +static int +xc_attach(device_t dev) +{ + struct xc_softc *sc = (struct xc_softc *)device_get_softc(dev); + TRACE_ENTER; + + sc->xc_dev = make_dev(&xc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xc%r", 0); + xccons = ttymalloc(NULL); + + sc->xc_dev->si_drv1 = (void *)sc; + sc->xc_dev->si_tty = xccons; + + xccons->t_oproc = xcstart; + xccons->t_param = xcparam; + xccons->t_stop = xcstop; + xccons->t_dev = sc->xc_dev; + + callout_init(&xc_callout, 0); + + xencons_ring_init(); + + cnsl_evt_reg = 1; + callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons); + + /* register handler to flush console on shutdown */ + if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown, + NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) + printf("xencons: shutdown event registration failed!\n"); + + TRACE_EXIT; + return (0); +} + +/* + * return 0 for all console input, force flush all output. + */ +static void +xc_shutdown(void *arg, int howto) +{ + xc_mute = 1; +#ifdef notyet + xcons_force_flush(); +#endif +} + +void +xencons_rx(char *buf, unsigned len) +{ + int i, flags; + struct tty *tp = xccons; + + CN_LOCK(cn_mtx, flags); + for (i = 0; i < len; i++) { + if ( xen_console_up) + (*linesw[tp->t_line]->l_rint)(buf[i], tp); + else + rbuf[RBUF_MASK(rp++)] = buf[i]; + } + CN_UNLOCK(cn_mtx, flags); +} + +static void +__xencons_tx_flush(void) +{ + int sz, work_done = 0; + TRACE_ENTER; +#ifdef notyet + while (x_char) { + if (xencons_ring_send(&x_char, 1) == 1) { + x_char = 0; + work_done = 1; + } + } +#endif + while ( wc != wp ) { + int sent; + sz = wp - wc; + if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) ) + sz = WBUF_SIZE - WBUF_MASK(wc); + sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); + if (sent == 0) + break; + wc += sent; + work_done = 1; + + } + + if ( work_done && xen_console_up ) + ttwakeup(xccons); + TRACE_EXIT; +} + +void +xencons_tx(void) +{ + unsigned long flags; + CN_LOCK(cn_mtx, flags); + __xencons_tx_flush(); + CN_UNLOCK(cn_mtx, flags); +} +#ifdef nomore +static void +xencons_tx_flush_task_routine(void * data, int arg) +{ + int flags; + CN_LOCK(cn_mtx, flags); + xc_tx_task_queued = FALSE; + __xencons_tx_flush(); + CN_UNLOCK(cn_mtx, flags); +} +#endif +int +xcopen(struct cdev *dev, int flag, int mode, struct thread *td) +{ + struct xc_softc *sc; + int unit = XCUNIT(dev); + struct tty *tp; + int s, error; + + sc = (struct xc_softc *)device_get_softc( + devclass_get_device(xc_devclass, unit)); + if (sc == NULL) + return (ENXIO); + + TRACE_ENTER; + tp = dev->si_tty; + s = spltty(); + if (!ISTTYOPEN(tp)) { + tp->t_state |= TS_CARR_ON; + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG|CLOCAL; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + xcparam(tp, &tp->t_termios); + ttsetwater(tp); + } else if (tp->t_state & TS_XCLUDE && suser(td)) { + splx(s); + return (EBUSY); + } + splx(s); + + xen_console_up = 1; + + error = (*linesw[tp->t_line]->l_open)(dev, tp); + TRACE_EXIT; + return error; +} + +int +xcclose(struct cdev *dev, int flag, int mode, struct thread *td) +{ + struct tty *tp = dev->si_tty; + + if (tp == NULL) + return (0); + xen_console_up = 0; + + spltty(); + (*linesw[tp->t_line]->l_close)(tp, flag); + tty_close(tp); + spl0(); + return (0); +} + + +int +xcioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + struct tty *tp = dev->si_tty; + int error; + + error = (*linesw[tp->t_line]->l_ioctl)(tp, cmd, data, flag, td); + if (error != ENOIOCTL) + return (error); + + error = ttioctl(tp, cmd, data, flag); + + if (error != ENOIOCTL) + return (error); + + return (ENOTTY); +} + +static inline int +__xencons_put_char(int ch) +{ + char _ch = (char)ch; + if ( (wp - wc) == WBUF_SIZE ) + return 0; + wbuf[WBUF_MASK(wp++)] = _ch; + return 1; +} + + +static void +xcstart(struct tty *tp) +{ + int flags; + int s; + boolean_t cons_full = FALSE; + + s = spltty(); + CN_LOCK(cn_mtx, flags); + if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { + ttwwakeup(tp); + CN_UNLOCK(cn_mtx, flags); + return; + } + + tp->t_state |= TS_BUSY; + while (tp->t_outq.c_cc != 0 && !cons_full) + cons_full = xcons_putc(getc(&tp->t_outq)); + + /* if the console is close to full leave our state as busy */ + if (!cons_full) { + tp->t_state &= ~TS_BUSY; + ttwwakeup(tp); + } else { + /* let the timeout kick us in a bit */ + xc_start_needed = TRUE; + } + CN_UNLOCK(cn_mtx, flags); + splx(s); +} + +static void +xcstop(struct tty *tp, int flag) +{ + + if (tp->t_state & TS_BUSY) { + if ((tp->t_state & TS_TTSTOP) == 0) { + tp->t_state |= TS_FLUSH; + } + } +} + +static void +xc_timeout(void *v) +{ + struct tty *tp; + int c; + + tp = (struct tty *)v; + + while ((c = xccncheckc(NULL)) != -1) { + if (tp->t_state & TS_ISOPEN) { + (*linesw[tp->t_line]->l_rint)(c, tp); + } + } + + if (xc_start_needed) { + xc_start_needed = FALSE; + xcstart(tp); + } + + callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp); +} + +/* + * Set line parameters. + */ +int +xcparam(struct tty *tp, struct termios *t) +{ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + return (0); +} + + +static device_method_t xc_methods[] = { + DEVMETHOD(device_identify, xc_identify), + DEVMETHOD(device_probe, xc_probe), + DEVMETHOD(device_attach, xc_attach), + {0, 0} +}; + +static driver_t xc_driver = { + driver_name, + xc_methods, + sizeof(struct xc_softc), +}; +#if 0 +/*** Forcibly flush console data before dying. ***/ +void +xcons_force_flush(void) +{ + int sz; + + /* + * We use dangerous control-interface functions that require a quiescent + * system and no interrupts. Try to ensure this with a global cli(). + */ + cli(); + + /* Spin until console data is flushed through to the domain controller. */ + while ( (wc != wp) && !ctrl_if_transmitter_empty() ) + { + /* Interrupts are disabled -- we must manually reap responses. */ + ctrl_if_discard_responses(); + + if ( (sz = wp - wc) == 0 ) + continue; + if ( sz > sizeof(msg.msg) ) + sz = sizeof(msg.msg); + if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) ) + sz = WBUF_SIZE - WBUF_MASK(wc); + + msg.type = CMSG_CONSOLE; + msg.subtype = CMSG_CONSOLE_DATA; + msg.length = sz; + memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz); + + if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) + wc += sz; + } +} +#endif +DRIVER_MODULE(xc, nexus, xc_driver, xc_devclass, 0, 0); +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ Index: dev/xen/console/xencons_ring.c =================================================================== RCS file: dev/xen/console/xencons_ring.c diff -N dev/xen/console/xencons_ring.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/console/xencons_ring.c 1 Jan 2006 07:40:01 -0000 @@ -0,0 +1,139 @@ +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + + +extern char *console_page; + +static inline struct xencons_interface * +xencons_interface(void) +{ + return (struct xencons_interface *)console_page; +} + +int +xencons_ring_send(const char *data, unsigned len) +{ + struct xencons_interface *intf; + XENCONS_RING_IDX cons, prod; + int sent; + + intf = xencons_interface(); + cons = intf->out_cons; + prod = intf->out_prod; + sent = 0; + + mb(); + PANIC_IF((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + wmb(); + intf->out_prod = prod; + + notify_remote_via_evtchn(xen_start_info->console_evtchn); + + return sent; + +} + + +static xencons_receiver_func *xencons_receiver; + +static void +handle_input(void *unused) +{ + struct xencons_interface *intf; + XENCONS_RING_IDX cons, prod; + + intf = xencons_interface(); + + cons = intf->in_cons; + prod = intf->in_prod; + + while (cons != prod) { + xencons_rx(intf->in + MASK_XENCONS_IDX(cons, intf->in), 1); + cons++; + } + + mb(); + intf->in_cons = cons; + + notify_remote_via_evtchn(xen_start_info->console_evtchn); + + xencons_tx(); +} + +void +xencons_ring_register_receiver(xencons_receiver_func *f) +{ + xencons_receiver = f; +} + +int +xencons_ring_init(void) +{ + int err; + + if (!xen_start_info->console_evtchn) + return 0; + + err = bind_evtchn_to_irqhandler(xen_start_info->console_evtchn, + "xencons", handle_input, NULL, + INTR_TYPE_MISC | INTR_MPSAFE); + if (err) { + XENPRINTF("XEN console request irq failed %i\n", err); + return err; + } + + return 0; +} +#ifdef notyet +void +xencons_suspend(void) +{ + + if (!xen_start_info->console_evtchn) + return; + + unbind_evtchn_from_irqhandler(xen_start_info->console_evtchn, NULL); +} + +void +xencons_resume(void) +{ + + (void)xencons_ring_init(); +} +#endif +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 8 + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ Index: dev/xen/console/xencons_ring.h =================================================================== RCS file: dev/xen/console/xencons_ring.h diff -N dev/xen/console/xencons_ring.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/console/xencons_ring.h 30 Dec 2005 20:14:29 -0000 @@ -0,0 +1,13 @@ +#ifndef _XENCONS_RING_H +#define _XENCONS_RING_H + +int xencons_ring_init(void); +int xencons_ring_send(const char *data, unsigned len); +void xencons_rx(char *buf, unsigned len); +void xencons_tx(void); + + +typedef void (xencons_receiver_func)(char *buf, unsigned len); +void xencons_ring_register_receiver(xencons_receiver_func *f); + +#endif /* _XENCONS_RING_H */ Index: dev/xen/evtchn/evtchn_dev.c =================================================================== RCS file: dev/xen/evtchn/evtchn_dev.c diff -N dev/xen/evtchn/evtchn_dev.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/evtchn/evtchn_dev.c 2 Jan 2006 06:07:58 -0000 @@ -0,0 +1,406 @@ +/****************************************************************************** + * evtchn.c + * + * Xenolinux driver for receiving and demuxing event-channel signals. + * + * Copyright (c) 2004, K A Fraser + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +typedef struct evtchn_sotfc { + + struct selinfo ev_rsel; +} evtchn_softc_t; + + +#ifdef linuxcrap +/* NB. This must be shared amongst drivers if more things go in /dev/xen */ +static devfs_handle_t xen_dev_dir; +#endif + +/* Only one process may open /dev/xen/evtchn at any time. */ +static unsigned long evtchn_dev_inuse; + +/* Notification ring, accessed via /dev/xen/evtchn. */ + +#define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */ + +#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) +static uint16_t *ring; +static unsigned int ring_cons, ring_prod, ring_overflow; + +/* Which ports is user-space bound to? */ +static uint32_t bound_ports[32]; + +/* Unique address for processes to sleep on */ +static void *evtchn_waddr = ˚ + +static struct mtx lock, upcall_lock; + +static d_read_t evtchn_read; +static d_write_t evtchn_write; +static d_ioctl_t evtchn_ioctl; +static d_poll_t evtchn_poll; +static d_open_t evtchn_open; +static d_close_t evtchn_close; + + +void +evtchn_device_upcall(int port) +{ + mtx_lock(&upcall_lock); + + mask_evtchn(port); + clear_evtchn(port); + + if ( ring != NULL ) { + if ( (ring_prod - ring_cons) < EVTCHN_RING_SIZE ) { + ring[EVTCHN_RING_MASK(ring_prod)] = (uint16_t)port; + if ( ring_cons == ring_prod++ ) { + wakeup(evtchn_waddr); + } + } + else { + ring_overflow = 1; + } + } + + mtx_unlock(&upcall_lock); +} + +static void +__evtchn_reset_buffer_ring(void) +{ + /* Initialise the ring to empty. Clear errors. */ + ring_cons = ring_prod = ring_overflow = 0; +} + +static int +evtchn_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + int rc; + unsigned int count, c, p, sst = 0, bytes1 = 0, bytes2 = 0; + count = uio->uio_resid; + + count &= ~1; /* even number of bytes */ + + if ( count == 0 ) + { + rc = 0; + goto out; + } + + if ( count > PAGE_SIZE ) + count = PAGE_SIZE; + + for ( ; ; ) { + if ( (c = ring_cons) != (p = ring_prod) ) + break; + + if ( ring_overflow ) { + rc = EFBIG; + goto out; + } + + if (sst != 0) { + rc = EINTR; + goto out; + } + + /* PCATCH == check for signals before and after sleeping + * PWAIT == priority of waiting on resource + */ + sst = tsleep(evtchn_waddr, PWAIT|PCATCH, "evchwt", 10); + } + + /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ + if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 ) { + bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(uint16_t); + bytes2 = EVTCHN_RING_MASK(p) * sizeof(uint16_t); + } + else { + bytes1 = (p - c) * sizeof(uint16_t); + bytes2 = 0; + } + + /* Truncate chunks according to caller's maximum byte count. */ + if ( bytes1 > count ) { + bytes1 = count; + bytes2 = 0; + } + else if ( (bytes1 + bytes2) > count ) { + bytes2 = count - bytes1; + } + + if ( uiomove(&ring[EVTCHN_RING_MASK(c)], bytes1, uio) || + ((bytes2 != 0) && uiomove(&ring[0], bytes2, uio))) + /* keeping this around as its replacement is not equivalent + * copyout(&ring[0], &buf[bytes1], bytes2) + */ + { + rc = EFAULT; + goto out; + } + + ring_cons += (bytes1 + bytes2) / sizeof(uint16_t); + + rc = bytes1 + bytes2; + + out: + + return rc; +} + +static int +evtchn_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + int rc, i, count; + + count = uio->uio_resid; + + uint16_t *kbuf = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK); + + + if ( kbuf == NULL ) + return ENOMEM; + + count &= ~1; /* even number of bytes */ + + if ( count == 0 ) { + rc = 0; + goto out; + } + + if ( count > PAGE_SIZE ) + count = PAGE_SIZE; + + if ( uiomove(kbuf, count, uio) != 0 ) { + rc = EFAULT; + goto out; + } + + mtx_lock_spin(&lock); + for ( i = 0; i < (count/2); i++ ) + if ( test_bit(kbuf[i], &bound_ports[0]) ) + unmask_evtchn(kbuf[i]); + mtx_unlock_spin(&lock); + + rc = count; + + out: + free(kbuf, M_DEVBUF); + return rc; +} + +static int +evtchn_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg, + int mode, struct thread *td __unused) +{ + int rc = 0; + + mtx_lock_spin(&lock); + + switch ( cmd ) + { + case EVTCHN_RESET: + __evtchn_reset_buffer_ring(); + break; + case EVTCHN_BIND: + if ( !synch_test_and_set_bit((int)arg, &bound_ports[0]) ) + unmask_evtchn((int)arg); + else + rc = EINVAL; + break; + case EVTCHN_UNBIND: + if ( synch_test_and_clear_bit((int)arg, &bound_ports[0]) ) + mask_evtchn((int)arg); + else + rc = EINVAL; + break; + default: + rc = ENOSYS; + break; + } + + mtx_unlock_spin(&lock); + + return rc; +} + +static int +evtchn_poll(struct cdev *dev, int poll_events, struct thread *td) +{ + + evtchn_softc_t *sc; + unsigned int mask = POLLOUT | POLLWRNORM; + + sc = dev->si_drv1; + + if ( ring_cons != ring_prod ) + mask |= POLLIN | POLLRDNORM; + else if ( ring_overflow ) + mask = POLLERR; + else + selrecord(td, &sc->ev_rsel); + + + return mask; +} + + +static int +evtchn_open(struct cdev *dev, int flag, int otyp, struct thread *td) +{ + uint16_t *_ring; + + if (flag & O_NONBLOCK) + return EBUSY; + + if ( synch_test_and_set_bit(0, &evtchn_dev_inuse) ) + return EBUSY; + + if ( (_ring = (uint16_t *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK)) == NULL ) + return ENOMEM; + + mtx_lock_spin(&lock); + ring = _ring; + __evtchn_reset_buffer_ring(); + mtx_unlock_spin(&lock); + + + return 0; +} + +static int +evtchn_close(struct cdev *dev, int flag, int otyp, struct thread *td __unused) +{ + int i; + + mtx_lock_spin(&lock); + if (ring != NULL) { + free(ring, M_DEVBUF); + ring = NULL; + } + for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) + if ( synch_test_and_clear_bit(i, &bound_ports[0]) ) + mask_evtchn(i); + mtx_unlock_spin(&lock); + + evtchn_dev_inuse = 0; + + return 0; +} + +static struct cdevsw evtchn_devsw = { + d_version: D_VERSION, + d_open: evtchn_open, + d_close: evtchn_close, + d_read: evtchn_read, + d_write: evtchn_write, + d_ioctl: evtchn_ioctl, + d_poll: evtchn_poll, + d_name: "evtchn", + d_flags: 0, +}; + + +/* XXX - if this device is ever supposed to support use by more than one process + * this global static will have to go away + */ +static struct cdev *evtchn_dev; + + + +static int +evtchn_init(void *dummy __unused) +{ + /* XXX I believe we don't need these leaving them here for now until we + * have some semblance of it working + */ +#if 0 + devfs_handle_t symlink_handle; + int err, pos; + char link_dest[64]; +#endif + mtx_init(&upcall_lock, "evtchup", NULL, MTX_DEF); + + /* (DEVFS) create '/dev/misc/evtchn'. */ + evtchn_dev = make_dev(&evtchn_devsw, 0, UID_ROOT, GID_WHEEL, 0600, "xen/evtchn"); + + mtx_init(&lock, "evch", NULL, MTX_SPIN | MTX_NOWITNESS); + + evtchn_dev->si_drv1 = malloc(sizeof(evtchn_softc_t), M_DEVBUF, M_WAITOK); + bzero(evtchn_dev->si_drv1, sizeof(evtchn_softc_t)); + + /* XXX I don't think we need any of this rubbish */ +#if 0 + if ( err != 0 ) + { + printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); + return err; + } + + /* (DEVFS) create directory '/dev/xen'. */ + xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL); + + /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */ + pos = devfs_generate_path(evtchn_miscdev.devfs_handle, + &link_dest[3], + sizeof(link_dest) - 3); + if ( pos >= 0 ) + strncpy(&link_dest[pos], "../", 3); + /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */ + (void)devfs_mk_symlink(xen_dev_dir, + "evtchn", + DEVFS_FL_DEFAULT, + &link_dest[pos], + &symlink_handle, + NULL); + + /* (DEVFS) automatically destroy the symlink with its destination. */ + devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle); +#endif + printk("Event-channel device installed.\n"); + + return 0; +} + + +SYSINIT(evtchn_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, evtchn_init, NULL); + + +#if 0 + +static void cleanup_module(void) +{ + destroy_dev(evtchn_dev); +; +} + +module_init(init_module); +module_exit(cleanup_module); +#endif Index: dev/xen/netfront/netfront.c =================================================================== RCS file: dev/xen/netfront/netfront.c diff -N dev/xen/netfront/netfront.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/netfront/netfront.c 2 Jan 2006 11:12:39 -0000 @@ -0,0 +1,1551 @@ +/* + * + * Copyright (c) 2004-2005 Kip Macy + * All rights reserved. + * + * + * 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. + */ + +#include "opt_nfsroot.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include /* for DELAY */ +#include +#include +#include + + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GRANT_INVALID_REF 0 + +#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) +#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) + + +struct netfront_info; +static void xn_txeof(struct netfront_info *); +static void xn_rxeof(struct netfront_info *); +static void network_alloc_rx_buffers(struct netfront_info *); + +static void xn_tick_locked(struct netfront_info *); +static void xn_tick(void *); + +static void xn_intr(void *); +static void xn_start_locked(struct ifnet *); +static void xn_start(struct ifnet *); +static int xn_ioctl(struct ifnet *, u_long, caddr_t); +static void xn_ifinit_locked(struct netfront_info *); +static void xn_ifinit(void *); +static void xn_stop(struct netfront_info *); +#ifdef notyet +static void xn_watchdog(struct ifnet *); +#endif + +static void show_device(struct netfront_info *sc); +static void netfront_closing(struct xenbus_device *dev); +static void netif_free(struct netfront_info *info); +static int netfront_remove(struct xenbus_device *dev); + +static int talk_to_backend(struct xenbus_device *dev, struct netfront_info *info); +static int create_netdev(int handle, struct xenbus_device *dev, struct ifnet **ifp); +static void netif_disconnect_backend(struct netfront_info *info); +static int setup_device(struct xenbus_device *dev, struct netfront_info *info); +static void end_access(int ref, void *page); + +/* Xenolinux helper functions */ +static void network_connect(struct ifnet *ifp); + +static void xn_free_rx_ring(struct netfront_info *); + +static void xn_free_tx_ring(struct netfront_info *); + +#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) + +/* XXX: This isn't supported in FreeBSD, so ignore it for now. */ +#define TASK_UNINTERRUPTIBLE 0 +#define INVALID_P2M_ENTRY (~0UL) + +/* + * Mbuf pointers. We need these to keep track of the virtual addresses + * of our mbuf chains since we can only convert from virtual to physical, + * not the other way around. The size must track the free index arrays. + */ +struct xn_chain_data { + struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; + struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; +}; + +struct xn_softc { + struct arpcom arpcom; /* interface info */ + device_t xn_dev; + SLIST_ENTRY(xn_softc) xn_links; + void *xn_intrhand; + struct resource *xn_res; + u_int8_t xn_ifno; /* interface number */ + + int xn_txcnt; + int xn_rxbufcnt; + unsigned int xn_irq; + unsigned int xn_evtchn; + + + /* What is the status of our connection to the remote backend? */ +#define BEST_CLOSED 0 +#define BEST_DISCONNECTED 1 +#define BEST_CONNECTED 2 + unsigned int xn_backend_state; + + /* Is this interface open or closed (down or up)? */ +#define UST_CLOSED 0 +#define UST_OPEN 1 + unsigned int xn_user_state; + + int xn_rx_target; /* number to allocate */ + +}; + +static unsigned long rx_pfn_array[NET_RX_RING_SIZE]; +static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; +static mmu_update_t rx_mmu[NET_RX_RING_SIZE]; + +struct net_device_stats +{ + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long multicast; /* multicast packets received */ + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; + + /* for cslip etc */ + unsigned long rx_compressed; + unsigned long tx_compressed; +}; + +struct netfront_info +{ + struct ifnet *xn_ifp; + + struct net_device_stats stats; + unsigned int tx_full; + + netif_tx_front_ring_t tx; + netif_rx_front_ring_t rx; + + struct mtx tx_lock; + struct mtx rx_lock; + + unsigned int handle; + unsigned int evtchn, irq; + + /* What is the status of our connection to the remote backend? */ +#define BEST_CLOSED 0 +#define BEST_DISCONNECTED 1 +#define BEST_CONNECTED 2 + unsigned int backend_state; + + /* Is this interface open or closed (down or up)? */ +#define UST_CLOSED 0 +#define UST_OPEN 1 + unsigned int user_state; + + /* Receive-ring batched refills. */ +#define RX_MIN_TARGET 32 +#define RX_MAX_TARGET NET_RX_RING_SIZE + int rx_min_target, rx_max_target, rx_target; + + /* + * {tx,rx}_skbs store outstanding skbuffs. The first entry in each + * array is an index into a chain of free entries. + */ + + grant_ref_t gref_tx_head; + grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; + grant_ref_t gref_rx_head; + grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; + + struct xenbus_device *xbdev; + int tx_ring_ref; + int rx_ring_ref; + uint8_t mac[ETHER_ADDR_LEN]; + struct xn_chain_data xn_cdata; /* mbufs */ + unsigned short xn_rx_free_idxs[NET_RX_RING_SIZE+1]; + unsigned short xn_tx_free_idxs[NET_RX_RING_SIZE+1]; + struct mbuf *xn_rx_batch; /* head of the batch queue */ + struct mbuf *xn_rx_batchtail; + int xn_rx_batchlen; /* how many queued */ + int xn_if_flags; + struct callout xn_stat_ch; + +}; + + +#define XN_LOCK_INIT(_sc, _name) \ + mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_SPIN); \ + mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_SPIN); +#define XN_RX_LOCK(_sc) mtx_lock_spin(&(_sc)->rx_lock) +#define XN_RX_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->rx_lock) +#define XN_TX_LOCK(_sc) mtx_lock_spin(&(_sc)->tx_lock) +#define XN_TX_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->tx_lock) +#define XN_LOCK(_sc) mtx_lock_spin(&(_sc)->tx_lock); \ + mtx_lock_spin(&(_sc)->rx_lock); +#define XN_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->rx_lock); \ + mtx_unlock_spin(&(_sc)->tx_lock) +#define XN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); \ + mtx_assert(&(_sc)->tx_lock, MA_OWNED); +#define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); +#define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); +#define XN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_lock); \ + mtx_destroy(&(_sc)->tx_lock); + +/* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ +#define ADD_ID_TO_FREELIST(_list, _id) \ + (_list)[(_id)] = (_list)[0]; \ + (_list)[0] = (_id); +#define GET_ID_FROM_FREELIST(_list) \ + ({ unsigned short _id = (_list)[0]; \ + (_list)[0] = (_list)[_id]; \ + (unsigned short)_id; }) +#define FREELIST_EMPTY(_list, _maxid) \ + ((_list)[0] == (_maxid+1)) +#if DEBUG +static char *be_state_name[] = { + [BEST_CLOSED] = "closed", + [BEST_DISCONNECTED] = "disconnected", + [BEST_CONNECTED] = "connected", +}; +#endif +#define IPRINTK(fmt, args...) \ + printk("[XEN] " fmt, ##args) +#define WPRINTK(fmt, args...) \ + printk("[XEN] " fmt, ##args) +#define DPRINTK(fmt, args...) \ + printk("[XEN] " fmt, ##args) + +static __inline struct mbuf* +makembuf (struct mbuf *buf) +{ + struct mbuf *m = NULL; + + MGETHDR (m, M_DONTWAIT, MT_DATA); + + if (! m) + return 0; + + M_MOVE_PKTHDR(m, buf); + + MCLGET (m, M_DONTWAIT); + + m->m_pkthdr.len = buf->m_pkthdr.len; + m->m_len = buf->m_len; + m_copydata(buf, 0, buf->m_pkthdr.len, mtod(m,caddr_t) ); + m->m_ext.ext_args = (vm_paddr_t *)vtophys(mtod(m,caddr_t)); + + return m; +} + +/** + * Read the 'mac' node at the given device's node in the store, and parse that + * as colon-separated octets, placing result the given mac array. mac must be + * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). + * Return 0 on success, or errno on error. + */ +static int +xen_net_read_mac(struct xenbus_device *dev, uint8_t mac[]) +{ + char *s; + int i; + char *e; + char *macstr = xenbus_read(NULL, dev->nodename, "mac", NULL); + if (IS_ERR(macstr)) { + return PTR_ERR(macstr); + } + s = macstr; + for (i = 0; i < ETHER_ADDR_LEN; i++) { + mac[i] = strtoul(s, &e, 16); + if (s == e || (e[0] != ':' && e[0] != 0)) { + free(macstr, M_DEVBUF); + return ENOENT; + } + s = &e[1]; + } + free(macstr, M_DEVBUF); + return 0; +} + +/** + * Entry point to this code when a new device is created. Allocate the basic + * structures and the ring buffers for communication with the backend, and + * inform the backend of the appropriate details for those. Switch to + * Connected state. + */ +static int +netfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) +{ + int err; + struct ifnet *ifp; + struct netfront_info *info; + unsigned int handle; + + err = xenbus_scanf(NULL, dev->nodename, "handle", "%u", &handle); + if (err != 1) { + xenbus_dev_fatal(dev, err, "reading handle"); + return err; + } + + err = create_netdev(handle, dev, &ifp); + if (err) { + xenbus_dev_fatal(dev, err, "creating netdev"); + return err; + } + + info = ifp->if_softc; + dev->data = info; + + err = talk_to_backend(dev, info); + if (err) { + free(info, M_DEVBUF); + dev->data = NULL; + return err; + } + + return 0; +} + + +/** + * We are reconnecting to the backend, due to a suspend/resume, or a backend + * driver restart. We tear down our netif structure and recreate it, but + * leave the device-layer structures intact so that this is transparent to the + * rest of the kernel. + */ +static int +netfront_resume(struct xenbus_device *dev) +{ + struct netfront_info *info = dev->data; + + DPRINTK("%s\n", dev->nodename); + + netif_disconnect_backend(info); + return talk_to_backend(dev, info); +} + + +/* Common code used when first setting up, and when resuming. */ +static int +talk_to_backend(struct xenbus_device *dev, struct netfront_info *info) +{ + const char *message; + struct xenbus_transaction *xbt; + int err; + + /* Create shared ring, alloc event channel. */ + err = setup_device(dev, info); + if (err) + goto out; + + again: + xbt = xenbus_transaction_start(); + if (IS_ERR(xbt)) { + xenbus_dev_fatal(dev, err, "starting transaction"); + goto destroy_ring; + } + + err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u", + info->tx_ring_ref); + if (err) { + message = "writing tx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u", + info->rx_ring_ref); + if (err) { + message = "writing rx ring-ref"; + goto abort_transaction; + } + err = xenbus_printf(xbt, dev->nodename, + "event-channel", "%u", info->evtchn); + if (err) { + message = "writing event-channel"; + goto abort_transaction; + } + + err = xenbus_printf(xbt, dev->nodename, + "state", "%d", XenbusStateConnected); + if (err) { + message = "writing frontend XenbusStateConnected"; + goto abort_transaction; + } + + err = xenbus_transaction_end(xbt, 0); + if (err) { + if (err == EAGAIN) + goto again; + xenbus_dev_fatal(dev, err, "completing transaction"); + goto destroy_ring; + } + + return 0; + + abort_transaction: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, err, "%s", message); + destroy_ring: + netif_free(info); + out: + return err; +} + + +static int +setup_device(struct xenbus_device *dev, struct netfront_info *info) +{ + netif_tx_sring_t *txs; + netif_rx_sring_t *rxs; + int err; + struct ifnet *ifp; + + ifp = info->xn_ifp; + + info->tx_ring_ref = GRANT_INVALID_REF; + info->rx_ring_ref = GRANT_INVALID_REF; + info->rx.sring = NULL; + info->tx.sring = NULL; + info->irq = 0; + + txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + if (!txs) { + err = ENOMEM; + xenbus_dev_fatal(dev, err, "allocating tx ring page"); + goto fail; + } + rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + if (!rxs) { + err = ENOMEM; + xenbus_dev_fatal(dev, err, "allocating rx ring page"); + goto fail; + } + memset(txs, 0, PAGE_SIZE); + memset(rxs, 0, PAGE_SIZE); + info->backend_state = BEST_DISCONNECTED; + + SHARED_RING_INIT(txs); + FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); + + SHARED_RING_INIT(rxs); + FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); + + err = xenbus_grant_ring(dev, virt_to_mfn(txs)); + if (err < 0) + goto fail; + info->tx_ring_ref = err; + + err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); + if (err < 0) + goto fail; + info->rx_ring_ref = err; + + err = xenbus_alloc_evtchn(dev, &info->evtchn); + if (err) + goto fail; + + network_connect(ifp); + + info->irq = bind_evtchn_to_irqhandler( + info->evtchn, "xn", xn_intr, info, INTR_TYPE_NET | INTR_MPSAFE); +#if 0 + /* XXX need this for re-location to work well */ + (void)send_fake_arp(netdev); +#endif + show_device(info); + + return 0; + + fail: + netif_free(info); + return err; +} + + +/** + * Callback received when the backend's state changes. + */ +static void backend_changed(struct xenbus_device *dev, + XenbusState backend_state) +{ + DPRINTK("\n"); + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateConnected: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateClosing: + netfront_closing(dev); + break; + } +} + + + + +static void +xn_free_rx_ring(struct netfront_info *sc) +{ +#if 0 + int i; + + for (i = 0; i < NET_RX_RING_SIZE; i++) { + if (sc->xn_cdata.xn_rx_chain[i] != NULL) { + m_freem(sc->xn_cdata.xn_rx_chain[i]); + sc->xn_cdata.xn_rx_chain[i] = NULL; + } + } + + sc->rx.rsp_cons = 0; + sc->xn_rx_if->req_prod = 0; + sc->xn_rx_if->event = sc->rx.rsp_cons ; +#endif +} + +static void +xn_free_tx_ring(struct netfront_info *sc) +{ +#if 0 + int i; + + for (i = 0; i < NET_TX_RING_SIZE; i++) { + if (sc->xn_cdata.xn_tx_chain[i] != NULL) { + m_freem(sc->xn_cdata.xn_tx_chain[i]); + sc->xn_cdata.xn_tx_chain[i] = NULL; + } + } + + return; +#endif +} + +static void +network_alloc_rx_buffers(struct netfront_info *sc) +{ + unsigned short id; + struct mbuf *m_new, *next; + int i, batch_target; + RING_IDX req_prod; + struct xen_memory_reservation reservation; + grant_ref_t ref; + + req_prod = sc->rx.req_prod_pvt; + + if (unlikely(sc->backend_state != BEST_CONNECTED) ) + return; + + /* + * Allocate skbuffs greedily, even though we batch updates to the + * receive ring. This creates a less bursty demand on the memory allocator, + * so should reduce the chance of failed allocation requests both for + * ourself and for other kernel subsystems. + */ + batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); + for ( i = sc->xn_rx_batchlen; i < batch_target; i++, sc->xn_rx_batchlen++) { + MGETHDR(m_new, M_DONTWAIT, MT_DATA); + if (m_new == NULL) + break; + + MCLGET(m_new, M_DONTWAIT); + if (!(m_new->m_flags & M_EXT)) { + m_freem(m_new); + break; + } + m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; + + /* queue the mbufs allocated */ + if (!sc->xn_rx_batch) + sc->xn_rx_batch = m_new; + + if (sc->xn_rx_batchtail) + sc->xn_rx_batchtail->m_next = m_new; + sc->xn_rx_batchtail = m_new; + } + + /* Is the batch large enough to be worthwhile? */ + if ( i < (sc->rx_target/2) ) + return; + + for (i = 0, m_new = sc->xn_rx_batch; m_new; + i++, sc->xn_rx_batchlen--, m_new = next) { + + next = m_new->m_next; + m_new->m_next = NULL; + + m_new->m_ext.ext_args = (vm_paddr_t *)vtophys(m_new->m_ext.ext_buf); + + id = GET_ID_FROM_FREELIST(sc->xn_rx_free_idxs); + KASSERT(id != 0, ("alloc_rx_buffers: found free receive index of 0\n")); + sc->xn_cdata.xn_rx_chain[i] = m_new; + + + RING_GET_REQUEST(&sc->rx, req_prod + i)->id = id; + ref = gnttab_claim_grant_reference(&sc->gref_rx_head); + PANIC_IF((signed short)ref < 0); + sc->grant_rx_ref[id] = ref; + gnttab_grant_foreign_transfer_ref(ref, + sc->xbdev->otherend_id); + RING_GET_REQUEST(&sc->rx, req_prod + i)->gref = ref; + + + rx_pfn_array[i] = vtomach(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; + + /* Remove this page from pseudo phys map before passing back to Xen. */ + xen_phys_machine[((unsigned long)m_new->m_ext.ext_args >> PAGE_SHIFT)] + = INVALID_P2M_ENTRY; + + rx_mcl[i].op = __HYPERVISOR_update_va_mapping; + rx_mcl[i].args[0] = (unsigned long)mtod(m_new,vm_offset_t); + rx_mcl[i].args[1] = 0; + rx_mcl[i].args[2] = 0; + + } + + KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ + KASSERT(sc->xn_rx_batchlen == 0, ("not all mbufs processed")); + sc->xn_rx_batch = sc->xn_rx_batchtail = NULL; + + /* + * We may have allocated buffers which have entries outstanding + in the page * update queue -- make sure we flush those first! */ + PT_UPDATES_FLUSH(); + + /* After all PTEs have been zapped we blow away stale TLB entries. */ + rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_LOCAL; + + /* Give away a batch of pages. */ + rx_mcl[i].op = __HYPERVISOR_memory_op; + rx_mcl[i].args[0] = XENMEM_decrease_reservation; + rx_mcl[i].args[1] = (unsigned long)&reservation; + + reservation.extent_start = rx_pfn_array; + reservation.nr_extents = i; + reservation.extent_order = 0; + reservation.address_bits = 0; + reservation.domid = DOMID_SELF; + +#ifdef notyet + /* Tell the ballon driver what is going on. */ + balloon_update_driver_allowance(i); +#endif + + /* Zap PTEs and give away pages in one big multicall. */ + (void)HYPERVISOR_multicall(rx_mcl, i+1); + + /* Check return status of HYPERVISOR_dom_mem_op(). */ + if (unlikely(rx_mcl[i].result != i)) + panic("Unable to reduce memory reservation\n"); + + /* Above is a suitable barrier to ensure backend will see requests. */ + sc->rx.req_prod_pvt = req_prod + i; + RING_PUSH_REQUESTS(&sc->rx); + + /* Adjust our floating fill target if we risked running out of buffers. */ + if ( ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) && + ((sc->rx_target *= 2) > sc->rx_max_target) ) + sc->rx_target = sc->rx_max_target; +} + +static void +xn_rxeof(struct netfront_info *np) +{ + struct ifnet *ifp; + netif_rx_response_t *rx; + RING_IDX i, rp; + mmu_update_t *mmu = rx_mmu; + multicall_entry_t *mcl = rx_mcl; + struct mbuf *tail_mbuf = NULL, *head_mbuf = NULL, *m, *next; + unsigned long mfn; + grant_ref_t ref; + + + XN_RX_LOCK_ASSERT(np); + if (np->backend_state != BEST_CONNECTED) + return; + + ifp = np->xn_ifp; + + rp = np->rx.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for (i = np->rx.rsp_cons; i != rp; i++) { + + rx = RING_GET_RESPONSE(&np->rx, i); + KASSERT(rx->id != 0, ("xn_rxeof: found free receive index of 0\n")); + /* + * This definitely indicates a bug, either in this driver or + * in the backend driver. In future this should flag the bad + * situation to the system controller to reboot the backed. + */ + if ((ref = np->grant_rx_ref[rx->id]) == GRANT_INVALID_REF) { + WPRINTK("Bad rx response id %d.\n", rx->id); + continue; + } + + + /* Memory pressure, insufficient buffer headroom, ... */ + if ((mfn = gnttab_end_foreign_transfer_ref(ref)) == 0) { +#if 0 + if (net_ratelimit()) + WPRINTK("Unfulfilled rx req (id=%d, st=%d).\n", + rx->id, rx->status); +#endif + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = + rx->id; + RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = + ref; + np->rx.req_prod_pvt++; + RING_PUSH_REQUESTS(&np->rx); + continue; + } + + gnttab_release_grant_reference(&np->gref_rx_head, ref); + np->grant_rx_ref[rx->id] = GRANT_INVALID_REF; + + + m = (struct mbuf *)np->xn_cdata.xn_rx_chain[rx->id]; + if (m->m_next) + panic("mbuf is already part of a valid mbuf chain"); + ADD_ID_TO_FREELIST(np->xn_rx_free_idxs, rx->id); + + m->m_data += rx->offset;/* (rx->addr & PAGE_MASK); */ + m->m_pkthdr.len = m->m_len = rx->status; + m->m_pkthdr.rcvif = ifp; + +#ifdef notyet + if ( rx->flags & NETRXF_csum_valid ) + skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + np->stats.rx_packets++; + np->stats.rx_bytes += rx->status; + + + /* Remap the page. */ + mmu->ptr = ((vm_offset_t)mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; + mmu->val = (unsigned long)m->m_ext.ext_args >> PAGE_SHIFT; + mmu++; + /* XXX validate me */ + mcl->op = __HYPERVISOR_update_va_mapping; + mcl->args[0] = (unsigned long)m->m_data; + mcl->args[1] = (mfn << PAGE_SHIFT) | PG_V | PG_RW | PG_M | PG_A; + mcl->args[2] = 0; + mcl->args[3] = 0; + mcl++; + + xen_phys_machine[((unsigned long)m->m_ext.ext_args >> PAGE_SHIFT)] = + mfn; + + if (unlikely(!head_mbuf)) + head_mbuf = m; + + if (tail_mbuf) + tail_mbuf->m_next = m; + tail_mbuf = m; + + np->xn_cdata.xn_rx_chain[rx->id] = NULL; + } + + /* Do all the remapping work, and M->P updates, in one big hypercall. */ + if (likely((mcl - rx_mcl) != 0)) { + mcl->op = __HYPERVISOR_mmu_update; + mcl->args[0] = (unsigned long)rx_mmu; + mcl->args[1] = mmu - rx_mmu; + mcl->args[2] = 0; + mcl->args[3] = DOMID_SELF; + mcl++; + (void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); + } + + + /* + * Process all the mbufs after the remapping is complete. + * Break the mbuf chain first though. + */ + for (m = head_mbuf; m; m = next) { + next = m->m_next; + m->m_next = NULL; + + ifp->if_ipackets++; + + XN_RX_UNLOCK(np); + + /* Pass it up. */ + (*ifp->if_input)(ifp, m); + XN_RX_LOCK(np); + } + + np->rx.rsp_cons = i; + + /* If we get a callback with very few responses, reduce fill target. */ + /* NB. Note exponential increase, linear decrease. */ + if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > + ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) + np->rx_target = np->rx_min_target; + + network_alloc_rx_buffers(np); + +} + +static void +xn_txeof(struct netfront_info *np) +{ + RING_IDX i, prod; + unsigned short id; + struct ifnet *ifp; + struct mbuf *m; + + XN_TX_LOCK_ASSERT(np); + + if (np->backend_state != BEST_CONNECTED) + return; + + ifp = np->xn_ifp; + ifp->if_timer = 0; + + do { + prod = np->tx.sring->rsp_prod; + rmb(); /* Ensure we see responses up to 'rp'. */ + + for (i = np->tx.rsp_cons; i != prod; i++) { + id = RING_GET_RESPONSE(&np->tx, i)->id; + m = np->xn_cdata.xn_tx_chain[id]; + + KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); + M_ASSERTVALID(m); + if (unlikely(gnttab_query_foreign_access( + np->grant_tx_ref[id]) != 0)) { + printk("network_tx_buf_gc: warning " + "-- grant still in use by backend " + "domain.\n"); + goto out; + } + gnttab_end_foreign_access_ref( + np->grant_tx_ref[id], GNTMAP_readonly); + gnttab_release_grant_reference( + &np->gref_tx_head, np->grant_tx_ref[id]); + np->grant_tx_ref[id] = GRANT_INVALID_REF; + + np->xn_cdata.xn_tx_chain[id] = NULL; + ADD_ID_TO_FREELIST(np->xn_tx_free_idxs, id); + m_freem(m); + } + np->tx.rsp_cons = prod; + + /* + * Set a new event, then check for race with update of tx_cons. Note + * that it is essential to schedule a callback, no matter how few + * buffers are pending. Even if there is space in the transmit ring, + * higher layers may be blocked because too much data is outstanding: + * in such cases notification from Xen is likely to be the only kick + * that we'll get. + */ + np->tx.sring->rsp_event = + prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; + + + mb(); + + } while (prod != np->tx.sring->rsp_prod); + + out: + if (np->tx_full && + ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { + np->tx_full = 0; +#if 0 + if (np->user_state == UST_OPEN) + netif_wake_queue(dev); +#endif + } + +} + +static void +xn_intr(void *xsc) +{ + struct netfront_info *np = xsc; + struct ifnet *ifp = np->xn_ifp; + TRACE_ENTER; + + /* XXX this seems like a recipe for poor performance if not livelock */ + + XN_RX_LOCK(np); + + /* sometimes we seem to lose packets. stay in the interrupt handler while + * there is stuff to process: continually recheck the response producer. + */ + do { + if (np->rx.rsp_cons != np->rx.sring->rsp_prod && + np->user_state == UST_OPEN) + xn_rxeof(np); + + } while (np->rx.rsp_cons != np->rx.sring->rsp_prod && + np->user_state == UST_OPEN); + + XN_RX_UNLOCK(np); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + xn_start(ifp); + return; +} + +static void +xn_tick_locked(struct netfront_info *sc) +{ + XN_RX_LOCK_ASSERT(sc); + callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); + + /* XXX placeholder for printing debug information */ + +} + + +static void +xn_tick(void *xsc) +{ + struct netfront_info *sc; + + sc = xsc; + XN_RX_LOCK(sc); + xn_tick_locked(sc); + XN_RX_UNLOCK(sc); + +} +static void +xn_start_locked(struct ifnet *ifp) +{ + unsigned short id; + struct mbuf *m_head, *new_m; + struct netfront_info *sc; + netif_tx_request_t *tx; + RING_IDX i; + grant_ref_t ref; + unsigned long mfn, tx_bytes; + int notify; + + sc = ifp->if_softc; + tx_bytes = 0; + + + if (sc->backend_state != BEST_CONNECTED) + return; + + for (i = sc->tx.req_prod_pvt; TRUE; i++) { + + IF_DEQUEUE(&ifp->if_snd, m_head); + if (m_head == NULL) + break; + + if (FREELIST_EMPTY(sc->xn_tx_free_idxs, NET_TX_RING_SIZE)) { + IF_PREPEND(&ifp->if_snd, m_head); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + + id = GET_ID_FROM_FREELIST(sc->xn_tx_free_idxs); + + /* + * Start packing the mbufs in this chain into + * the fragment pointers. Stop when we run out + * of fragments or hit the end of the mbuf chain. + */ + new_m = makembuf(m_head); + tx = RING_GET_REQUEST(&sc->tx, i); + tx->id = id; + ref = gnttab_claim_grant_reference(&sc->gref_tx_head); + PANIC_IF((signed short)ref < 0); + mfn = virt_to_mfn(mtod(new_m, vm_offset_t)); + gnttab_grant_foreign_access_ref( + ref, sc->xbdev->otherend_id, mfn, GNTMAP_readonly); + tx->gref = sc->grant_tx_ref[id] = ref; + tx->size = new_m->m_pkthdr.len; +#if 0 + tx->flags = (skb->ip_summed == CHECKSUM_HW) ? NETTXF_csum_blank : 0; +#endif + tx->flags = 0; + new_m->m_next = NULL; + new_m->m_nextpkt = NULL; + + m_freem(m_head); + + sc->xn_cdata.xn_tx_chain[id] = new_m; + BPF_MTAP(ifp, new_m); + + sc->stats.tx_bytes += new_m->m_pkthdr.len; + sc->stats.tx_packets++; + } + + sc->tx.req_prod_pvt = i; + RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); + if (notify) + notify_remote_via_irq(sc->irq); + xn_txeof(sc); + + if (RING_FULL(&sc->tx)) { + sc->tx_full = 1; +#if 0 + netif_stop_queue(dev); +#endif + } + + + + return; +} + +static void +xn_start(struct ifnet *ifp) +{ + struct netfront_info *sc; + sc = ifp->if_softc; + XN_TX_LOCK(sc); + xn_start_locked(ifp); + XN_TX_UNLOCK(sc); +} + + + +/* equivalent of network_open() in Linux */ +static void +xn_ifinit_locked(struct netfront_info *sc) +{ + struct ifnet *ifp; + + XN_LOCK_ASSERT(sc); + + ifp = sc->xn_ifp; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + return; + + xn_stop(sc); + + sc->user_state = UST_OPEN; + + network_alloc_rx_buffers(sc); + sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); + +} + + +static void +xn_ifinit(void *xsc) +{ + struct netfront_info *sc = xsc; + + XN_LOCK(sc); + xn_ifinit_locked(sc); + XN_UNLOCK(sc); + +} + + +static int +xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct netfront_info *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int mask, error = 0; + switch(cmd) { + case SIOCSIFMTU: + /* XXX can we alter the MTU on a VN ?*/ +#ifdef notyet + if (ifr->ifr_mtu > XN_JUMBO_MTU) + error = EINVAL; + else +#endif + { + ifp->if_mtu = ifr->ifr_mtu; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + xn_ifinit(sc); + } + break; + case SIOCSIFFLAGS: + XN_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + /* + * If only the state of the PROMISC flag changed, + * then just use the 'set promisc mode' command + * instead of reinitializing the entire NIC. Doing + * a full re-init means reloading the firmware and + * waiting for it to start up, which may take a + * second or two. + */ +#ifdef notyet + /* No promiscuous mode with Xen */ + if (ifp->if_drv_flags & IFF_DRV_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->xn_if_flags & IFF_PROMISC)) { + XN_SETBIT(sc, XN_RX_MODE, + XN_RXMODE_RX_PROMISC); + } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->xn_if_flags & IFF_PROMISC) { + XN_CLRBIT(sc, XN_RX_MODE, + XN_RXMODE_RX_PROMISC); + } else +#endif + xn_ifinit_locked(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + xn_stop(sc); + } + } + sc->xn_if_flags = ifp->if_flags; + XN_UNLOCK(sc); + error = 0; + break; + case SIOCSIFCAP: + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if (mask & IFCAP_HWCSUM) { + if (IFCAP_HWCSUM & ifp->if_capenable) + ifp->if_capenable &= ~IFCAP_HWCSUM; + else + ifp->if_capenable |= IFCAP_HWCSUM; + } + error = 0; + break; + case SIOCADDMULTI: + case SIOCDELMULTI: +#ifdef notyet + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + XN_LOCK(sc); + xn_setmulti(sc); + XN_UNLOCK(sc); + error = 0; + } +#endif + /* FALLTHROUGH */ + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = EINVAL; + break; + default: + error = ether_ioctl(ifp, cmd, data); + } + + return (error); +} + +static void +xn_stop(struct netfront_info *sc) +{ + struct ifnet *ifp; + + XN_LOCK_ASSERT(sc); + + ifp = sc->xn_ifp; + + callout_stop(&sc->xn_stat_ch); + + xn_free_rx_ring(sc); + xn_free_tx_ring(sc); + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); +} + +/* START of Xenolinux helper functions adapted to FreeBSD */ +static void +network_connect(struct ifnet *ifp) +{ + struct netfront_info *np; + int i, requeue_idx; + netif_tx_request_t *tx; + + np = ifp->if_softc; + XN_LOCK(np); + + /* Recovery procedure: */ + + /* Step 1: Reinitialise variables. */ + np->tx_full = 0; + + /* Step 2: Rebuild the RX and TX ring contents. + * NB. We could just free the queued TX packets now but we hope + * that sending them out might do some good. We have to rebuild + * the RX ring because some of our pages are currently flipped out + * so we can't just free the RX skbs. + */ + + /* Rebuild the TX buffer freelist and the TX ring itself. + * NB. This reorders packets. We could keep more private state + * to avoid this but maybe it doesn't matter so much given the + * interface has been down. + */ + for (requeue_idx = 0, i = 1; i <= NET_TX_RING_SIZE; i++) { + if (np->xn_cdata.xn_tx_chain[i] != NULL) { + struct mbuf *m = np->xn_cdata.xn_tx_chain[i]; + + tx = RING_GET_REQUEST(&np->tx, requeue_idx); + requeue_idx++; + + tx->id = i; + gnttab_grant_foreign_access_ref( + np->grant_tx_ref[i], np->xbdev->otherend_id, + virt_to_mfn(mtod(m, vm_offset_t)), + GNTMAP_readonly); + tx->gref = np->grant_tx_ref[i]; + tx->size = m->m_pkthdr.len; + np->stats.tx_bytes += tx->size; + np->stats.tx_packets++; + } + } + + np->tx.req_prod_pvt = requeue_idx; + + /* Rebuild the RX buffer freelist and the RX ring itself. */ + for (requeue_idx = 0, i = 1; i <= NET_RX_RING_SIZE; i++) { + if (np->xn_cdata.xn_rx_chain[i] == NULL) + continue; + gnttab_grant_foreign_transfer_ref( + np->grant_rx_ref[i], np->xbdev->otherend_id); + RING_GET_REQUEST(&np->rx, requeue_idx)->gref = + np->grant_rx_ref[i]; + RING_GET_REQUEST(&np->rx, requeue_idx)->id = i; + requeue_idx++; + } + + np->rx.req_prod_pvt = requeue_idx; + RING_PUSH_REQUESTS(&np->rx); + + + + /* Step 3: All public and private state should now be sane. Get + * ready to start sending and receiving packets and give the driver + * domain a kick because we've probably just requeued some + * packets. + */ + np->backend_state = BEST_CONNECTED; + + notify_remote_via_irq(np->irq); + xn_txeof(np); + +#if 0 + if (np->user_state == UST_OPEN) + netif_start_queue(dev); +#endif + XN_UNLOCK(np); +} + + +static void +show_device(struct netfront_info *sc) +{ +#if DEBUG + if (sc) { + IPRINTK("\n", + sc->xn_ifno, + be_state_name[sc->xn_backend_state], + sc->xn_user_state ? "open" : "closed", + sc->xn_evtchn, + sc->xn_irq, + sc->xn_tx_if, + sc->xn_rx_if); + } else { + IPRINTK("\n"); + } +#endif +} + +/** Create a network device. + * @param handle device handle + */ +static int +create_netdev(int handle, struct xenbus_device *dev, struct ifnet **ifpp) +{ + int i; + struct netfront_info *np; + int err; + struct ifnet *ifp; + + np = (struct netfront_info *)malloc(sizeof(struct netfront_info), M_DEVBUF, M_WAITOK); + memset(np, 0, sizeof(struct netfront_info)); + + np->backend_state = BEST_CLOSED; + np->user_state = UST_CLOSED; + np->handle = handle; + np->xbdev = dev; + + XN_LOCK_INIT(np, xennetif); + np->rx_target = RX_MIN_TARGET; + np->rx_min_target = RX_MIN_TARGET; + np->rx_max_target = RX_MAX_TARGET; + + /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ + for (i = 0; i <= NET_TX_RING_SIZE; i++) { + np->xn_tx_free_idxs[i] = (i+1); + np->grant_tx_ref[i] = GRANT_INVALID_REF; + } + for (i = 0; i <= NET_RX_RING_SIZE; i++) { + np->xn_rx_free_idxs[i] = (i+1); + np->grant_rx_ref[i] = GRANT_INVALID_REF; + } + /* A grant for every tx ring slot */ + if (gnttab_alloc_grant_references(NET_TX_RING_SIZE, + &np->gref_tx_head) < 0) { + printf("#### netfront can't alloc tx grant refs\n"); + err = ENOMEM; + goto exit; + } + /* A grant for every rx ring slot */ + if (gnttab_alloc_grant_references(NET_RX_RING_SIZE, + &np->gref_rx_head) < 0) { + printf("#### netfront can't alloc rx grant refs\n"); + gnttab_free_grant_references(np->gref_tx_head); + err = ENOMEM; + goto exit; + } + + err = xen_net_read_mac(dev, np->mac); + if (err) { + xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); + goto out; + } + + /* Set up ifnet structure */ + *ifpp = ifp = np->xn_ifp = if_alloc(IFT_ETHER); + ifp->if_softc = np; + if_initname(ifp, "xn", np->handle /* ifno */); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_ioctl = xn_ioctl; + ifp->if_output = ether_output; + ifp->if_start = xn_start; +#ifdef notyet + ifp->if_watchdog = xn_watchdog; +#endif + ifp->if_init = xn_ifinit; + ifp->if_mtu = ETHERMTU; + ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; + +#ifdef notyet + ifp->if_hwassist = XN_CSUM_FEATURES; + ifp->if_capabilities = IFCAP_HWCSUM; + ifp->if_capenable = ifp->if_capabilities; +#endif + + ether_ifattach(ifp, np->mac); + callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE); + + return 0; + + exit: + out: + panic("do something smart"); + +} + +/** + * Handle the change of state of the backend to Closing. We must delete our + * device-layer structures now, to ensure that writes are flushed through to + * the backend. Once is this done, we can switch to Closed in + * acknowledgement. + */ +static void netfront_closing(struct xenbus_device *dev) +{ +#if 0 + struct netfront_info *info = dev->data; + + DPRINTK("netfront_closing: %s removed\n", dev->nodename); + + close_netdev(info); +#endif + xenbus_switch_state(dev, NULL, XenbusStateClosed); +} + + +static int netfront_remove(struct xenbus_device *dev) +{ + struct netfront_info *info = dev->data; + + DPRINTK("%s\n", dev->nodename); + + netif_free(info); + free(info, M_DEVBUF); + + return 0; +} + + +static void netif_free(struct netfront_info *info) +{ + netif_disconnect_backend(info); +#if 0 + close_netdev(info); +#endif +} + + + +static void netif_disconnect_backend(struct netfront_info *info) +{ +#if 0 + /* Stop old i/f to prevent errors whilst we rebuild the state. */ + mtx_lock_spin(&info->tx_lock); + mtx_lock(&info->rx_lock); + netif_stop_queue(info->netdev); + /* info->backend_state = BEST_DISCONNECTED; */ + mtx_unlock(&info->rx_lock); + mtx_unlock_spin(&info->tx_lock); +#endif + end_access(info->tx_ring_ref, info->tx.sring); + end_access(info->rx_ring_ref, info->rx.sring); + info->tx_ring_ref = GRANT_INVALID_REF; + info->rx_ring_ref = GRANT_INVALID_REF; + info->tx.sring = NULL; + info->rx.sring = NULL; + +#if 0 + if (info->irq) + unbind_from_irqhandler(info->irq, info->netdev); +#else + panic("FIX ME"); +#endif + info->evtchn = info->irq = 0; +} + + +static void end_access(int ref, void *page) +{ + if (ref != GRANT_INVALID_REF) + gnttab_end_foreign_access(ref, 0, page); +} + + +/* ** Driver registration ** */ + + +static struct xenbus_device_id netfront_ids[] = { + { "vif" }, + { "" } +}; + + +static struct xenbus_driver netfront = { + .name = "vif", + .ids = netfront_ids, + .probe = netfront_probe, + .remove = netfront_remove, + .resume = netfront_resume, + .otherend_changed = backend_changed, +}; + +#if 0 +static struct notifier_block notifier_inetdev = { + .notifier_call = inetdev_notify, + .next = NULL, + .priority = 0 +}; +#endif + +static void +netif_init(void *unused) +{ + if (xen_start_info->flags & SIF_INITDOMAIN) + return; +#if 0 + if ((err = xennet_proc_init()) != 0) + return err; +#endif + IPRINTK("Initialising virtual ethernet driver.\n"); + +#if 0 + (void)register_inetaddr_notifier(¬ifier_inetdev); +#endif + xenbus_register_frontend(&netfront); + + +} + +SYSINIT(xennetif, SI_SUB_PSEUDO, SI_ORDER_ANY, netif_init, NULL) + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 8 + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ Index: dev/xen/xenbus/init.txt =================================================================== RCS file: dev/xen/xenbus/init.txt diff -N dev/xen/xenbus/init.txt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/xenbus/init.txt 30 Dec 2005 20:14:29 -0000 @@ -0,0 +1,14 @@ + + +- frontend driver initializes static xenbus_driver with _ids, _probe, _remove, +_resume, _otherend_changed + + - initialization calls xenbus_register_frontend(xenbus_driver) + + - xenbus_register_frontend sets read_otherend details to read_backend_details + then calls xenbus_register_driver_common(xenbus_driver, xenbus_frontend) + + - xenbus_register_driver_common sets underlying driver name to xenbus_driver name + underlying driver bus to xenbus_frontend's bus, driver's probe to xenbus_dev_probe + driver's remove to xenbus_dev_remove then calls driver_register + Index: dev/xen/xenbus/xenbus_client.c =================================================================== RCS file: dev/xen/xenbus/xenbus_client.c diff -N dev/xen/xenbus/xenbus_client.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/xen/xenbus/xenbus_client.c 30 Dec 2005 23:20:24 -0000 @@ -0,0 +1,266 @@ +/****************************************************************************** + * Client-facing interface for the Xenbus driver. In other words, the + * interface between the Xenbus and the device-specific code, be it the + * frontend or the backend of that driver. + * + * Copyright (C) 2005 XenSource Ltd + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#if 0 +#define DPRINTK(fmt, args...) \ + printk("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args) +#else +#define DPRINTK(fmt, args...) ((void)0) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define EXPORT_SYMBOL(x) +#define kmalloc(size, unused) malloc(size, M_DEVBUF, M_WAITOK) +#define kfree(ptr) free(ptr, M_DEVBUF) +#define BUG_ON PANIC_IF + +int +xenbus_watch_path(struct xenbus_device *dev, char *path, + struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)) +{ + int err; + + watch->node = path; + watch->callback = callback; + + err = register_xenbus_watch(watch); + + if (err) { + watch->node = NULL; + watch->callback = NULL; + xenbus_dev_fatal(dev, err, "adding watch on %s", path); + } + + return err; +} +EXPORT_SYMBOL(xenbus_watch_path); + + +int xenbus_watch_path2(struct xenbus_device *dev, const char *path, + const char *path2, struct xenbus_watch *watch, + void (*callback)(struct xenbus_watch *, + const char **, unsigned int)) +{ + int err; + char *state = + kmalloc(strlen(path) + 1 + strlen(path2) + 1, GFP_KERNEL); + if (!state) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); + return -ENOMEM; + } + strcpy(state, path); + strcat(state, "/"); + strcat(state, path2); + + err = xenbus_watch_path(dev, state, watch, callback); + + if (err) { + kfree(state); + } + return err; +} +EXPORT_SYMBOL(xenbus_watch_path2); + + +int xenbus_switch_state(struct xenbus_device *dev, + struct xenbus_transaction *xbt, + XenbusState state) +{ + /* We check whether the state is currently set to the given value, and + if not, then the state is set. We don't want to unconditionally + write the given state, because we don't want to fire watches + unnecessarily. Furthermore, if the node has gone, we don't write + to it, as the device will be tearing down, and we don't want to + resurrect that directory. + */ + + int current_state; + + int err = xenbus_scanf(xbt, dev->nodename, "state", "%d", + ¤t_state); + if ((err == 1 && (XenbusState)current_state == state) || + err == -ENOENT) + return 0; + + err = xenbus_printf(xbt, dev->nodename, "state", "%d", state); + if (err) { + xenbus_dev_fatal(dev, err, "writing new state"); + return err; + } + return 0; +} +EXPORT_SYMBOL(xenbus_switch_state); + + +/** + * Return the path to the error node for the given device, or NULL on failure. + * If the value returned is non-NULL, then it is the caller's to kfree. + */ +static char *error_path(struct xenbus_device *dev) +{ + char *path_buffer = kmalloc(strlen("error/") + strlen(dev->nodename) + + 1, GFP_KERNEL); + if (path_buffer == NULL) { + return NULL; + } + + strcpy(path_buffer, "error/"); + strcpy(path_buffer + strlen("error/"), dev->node