Index: sys/i386/cpufreq/smist.c =================================================================== RCS file: /home/ncvs/src/sys/i386/cpufreq/smist.c,v retrieving revision 1.1 diff -u -r1.1 smist.c --- sys/i386/cpufreq/smist.c 19 Apr 2005 16:38:24 -0000 1.1 +++ sys/i386/cpufreq/smist.c 16 Jun 2007 16:58:34 -0000 @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -71,6 +72,8 @@ struct cf_setting sets[2]; /* Only two settings. */ }; +static char smist_magic[] = "Copyright (c) 1999 Intel Corporation"; + static void smist_identify(driver_t *driver, device_t parent); static int smist_probe(device_t dev); static int smist_attach(device_t dev); @@ -147,34 +150,86 @@ return (0); } -static int -set_ownership(device_t dev) -{ - int result; - struct smist_softc *sc; - vm_paddr_t pmagic; - static char magic[] = "Copyright (c) 1999 Intel Corporation"; +/* Temporary structure to hold mapped page and status. */ +struct set_ownership_data { + int smi_cmd; + int command; + int result; + void *buf; +}; - sc = device_get_softc(dev); - if (!sc) - return (ENXIO); +/* Perform actual SMI call to enable SpeedStep. */ +static void +set_ownership_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct set_ownership_data *data; - pmagic = vtophys(magic); + data = arg; + if (error) { + data->result = error; + return; + } + strlcpy(data->buf, smist_magic, PAGE_SIZE); __asm __volatile( "movl $-1, %%edi\n\t" "out %%al, (%%dx)\n" - : "=D" (result) - : "a" (sc->command), + : "=D" (data->result) + : "a" (data->command), "b" (0), "c" (0), - "d" (sc->smi_cmd), - "S" (pmagic) + "d" (data->smi_cmd), + "S" ((uint32_t)segs[0].ds_addr) ); +} + +static int +set_ownership(device_t dev) +{ + struct smist_softc *sc; + struct set_ownership_data cb_data; + bus_dma_tag_t tag; + bus_dmamap_t map; + + /* + * Specify the region to store the magic string. Since its address is + * passed to the BIOS in a 32-bit register, we have to make sure it is + * located in a physical page below 4 GB (i.e., for PAE.) Since the + * kernel has an identity map for the first 2 MB, we can get a V=P + * page in the first 1 MB and use it for this purpose. + */ + sc = device_get_softc(dev); + if (bus_dma_tag_create(/*parent*/ NULL, + /*alignment*/ PAGE_SIZE, /*no boundary*/ 0, + /*lowaddr*/ 0x9ffff, /*highaddr*/ BUS_SPACE_MAXADDR, + NULL, NULL, /*maxsize*/ PAGE_SIZE, /*segments*/ 1, + /*maxsegsize*/ PAGE_SIZE, + 0, busdma_lock_mutex, &Giant, &tag) != 0) { + device_printf(dev, "can't create mem tag\n"); + return (ENXIO); + } + if (bus_dmamem_alloc(tag, &cb_data.buf, BUS_DMA_NOWAIT, &map) != 0) { + bus_dma_tag_destroy(tag); + device_printf(dev, "can't alloc mapped mem\n"); + return (ENXIO); + } + + cb_data.smi_cmd = sc->smi_cmd; + cb_data.command = sc->command; + if (bus_dmamap_load(tag, map, cb_data.buf, PAGE_SIZE, set_ownership_cb, + &cb_data, BUS_DMA_NOWAIT) != 0) { + bus_dmamem_free(tag, cb_data.buf, map); + bus_dma_tag_destroy(tag); + device_printf(dev, "can't load mem\n"); + return (ENXIO); + }; - DPRINT(dev, "taking ownership over BIOS return %d\n", result); + DPRINT(dev, "taking ownership over BIOS return %d\n", cb_data.result); - return (result ? ENXIO : 0); + bus_dmamap_unload(tag, map); + bus_dmamem_free(tag, cb_data.buf, map); + bus_dma_tag_destroy(tag); + return (cb_data.result ? ENXIO : 0); } static int