[alsa-devel] [PATCH 0/8] Misc cleanups wrt firmware loading
Hi,
this is a series of clean up patches wrt firmware loading in various driver codes. Most of them are simply to concentrate on the standard f/w loading and drop the obsoleted code, and improvements of f/w caching. Also a few emu1010 fw loading code fixes are included.
Takashi
It makes no longer sense to keep the old hwdep user-space firmware loading, which has been deprecated since ages ago.
Just add a hard dependency on CONFIG_FW_LOADER and drop the useless code.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/Kconfig | 1 + sound/pci/mixart/mixart_hwdep.c | 76 ----------------------------------------- 2 files changed, 1 insertion(+), 76 deletions(-)
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 6150eb1..4356892 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -707,6 +707,7 @@ config SND_MAESTRO3_INPUT
config SND_MIXART tristate "Digigram miXart" + select FW_LOADER select SND_HWDEP select SND_PCM help diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index e0f4d87..ece1f83 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -546,14 +546,6 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw }
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */ -#define SND_MIXART_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - -#ifdef SND_MIXART_FW_LOADER - int snd_mixart_setup_firmware(struct mixart_mgr *mgr) { static char *fw_files[3] = { @@ -583,71 +575,3 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) MODULE_FIRMWARE("mixart/miXart8.xlx"); MODULE_FIRMWARE("mixart/miXart8.elf"); MODULE_FIRMWARE("mixart/miXart8AES.xlx"); - -#else /* old style firmware loading */ - -/* miXart hwdep interface id string */ -#define SND_MIXART_HWDEP_ID "miXart Loader" - -static int mixart_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct mixart_mgr *mgr = hw->private_data; - - strcpy(info->id, "miXart"); - info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX; - - if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX)) - info->chip_ready = 1; - - info->version = MIXART_DRIVER_VERSION; - return 0; -} - -static int mixart_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct mixart_mgr* mgr = hw->private_data; - struct firmware fw; - int err; - - fw.size = dsp->length; - fw.data = vmalloc(dsp->length); - if (! fw.data) { - snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n", - (int)dsp->length); - return -ENOMEM; - } - if (copy_from_user((void *) fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = mixart_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return err; -} - -int snd_mixart_setup_firmware(struct mixart_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX (see "index" module parameter)*/ - if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_MIXART; - hw->private_data = mgr; - hw->ops.dsp_status = mixart_hwdep_dsp_status; - hw->ops.dsp_load = mixart_hwdep_dsp_load; - hw->exclusive = 1; - sprintf(hw->name, SND_MIXART_HWDEP_ID); - mgr->dsp_loaded = 0; - - return snd_card_register(mgr->chip[0]->card); -} - -#endif /* SND_MIXART_FW_LOADER */
Like the previous commit for mixart, drop the home-baked fw loader code.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/Kconfig | 1 + sound/pci/pcxhr/pcxhr_hwdep.c | 86 ------------------------------------------- 2 files changed, 1 insertion(+), 86 deletions(-)
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 4356892..59dbb70 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -728,6 +728,7 @@ config SND_NM256
config SND_PCXHR tristate "Digigram PCXHR" + select FW_LOADER select SND_PCM select SND_HWDEP help diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index bf207e3..d995175 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -35,13 +35,6 @@ #include "pcxhr_mix22.h"
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_PCXHRLOADER) && !defined(CONFIG_SND_PCXHR) /* built-in kernel */ -#define SND_PCXHR_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - - static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card @@ -362,8 +355,6 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, /* * fw loader entry */ -#ifdef SND_PCXHR_FW_LOADER - int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { static char *fw_files[][5] = { @@ -424,80 +415,3 @@ MODULE_FIRMWARE("pcxhr/xlxc924.dat"); MODULE_FIRMWARE("pcxhr/dspe924.e56"); MODULE_FIRMWARE("pcxhr/dspb924.b56"); MODULE_FIRMWARE("pcxhr/dspd222.d56"); - - -#else /* old style firmware loading */ - -/* pcxhr hwdep interface id string */ -#define PCXHR_HWDEP_ID "pcxhr loader" - - -static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct pcxhr_mgr *mgr = hw->private_data; - sprintf(info->id, "pcxhr%d", mgr->fw_file_set); - info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; - - if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) - info->chip_ready = 1; - - info->version = PCXHR_DRIVER_VERSION; - return 0; -} - -static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct pcxhr_mgr *mgr = hw->private_data; - int err; - struct firmware fw; - - fw.size = dsp->length; - fw.data = vmalloc(fw.size); - if (! fw.data) { - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " - "(%lu bytes)\n", (unsigned long)fw.size); - return -ENOMEM; - } - if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = pcxhr_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return 0; -} - -int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX - * (see "index" module parameter) - */ - err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); - if (err < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_PCXHR; - hw->private_data = mgr; - hw->ops.dsp_status = pcxhr_hwdep_dsp_status; - hw->ops.dsp_load = pcxhr_hwdep_dsp_load; - hw->exclusive = 1; - /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ - hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; - mgr->dsp_loaded = 0; - sprintf(hw->name, PCXHR_HWDEP_ID); - - err = snd_card_register(mgr->chip[0]->card); - if (err < 0) - return err; - return 0; -} - -#endif /* SND_PCXHR_FW_LOADER */
Yet again like previous two commits, drop the old hwdep user-space firmware code from vx driver (snd-vxpocket and snd-vx222).
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/vx_core.h | 6 -- sound/drivers/Kconfig | 1 + sound/drivers/vx/vx_hwdep.c | 139 -------------------------------------------- 3 files changed, 1 insertion(+), 145 deletions(-)
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h index 4f67c76..f634f8f 100644 --- a/include/sound/vx_core.h +++ b/include/sound/vx_core.h @@ -27,12 +27,6 @@ #include <sound/hwdep.h> #include <linux/interrupt.h>
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_VXLOADER) && !defined(CONFIG_SND_VX_LIB) /* built-in kernel */ -#define SND_VX_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - struct firmware; struct device;
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 5e43841..7d02c32 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -14,6 +14,7 @@ config SND_OPL4_LIB
config SND_VX_LIB tristate + select FW_LOADER select SND_HWDEP select SND_PCM
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index 4a1fae9..3014b86 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c @@ -29,8 +29,6 @@ #include <sound/hwdep.h> #include <sound/vx_core.h>
-#ifdef SND_VX_FW_LOADER - MODULE_FIRMWARE("vx/bx_1_vxp.b56"); MODULE_FIRMWARE("vx/bx_1_vp4.b56"); MODULE_FIRMWARE("vx/x1_1_vx2.xlx"); @@ -119,142 +117,5 @@ void snd_vx_free_firmware(struct vx_core *chip) #endif }
-#else /* old style firmware loading */ - -static int vx_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - static char *type_ids[VX_TYPE_NUMS] = { - [VX_TYPE_BOARD] = "vxboard", - [VX_TYPE_V2] = "vx222", - [VX_TYPE_MIC] = "vx222", - [VX_TYPE_VXPOCKET] = "vxpocket", - [VX_TYPE_VXP440] = "vxp440", - }; - struct vx_core *vx = hw->private_data; - - if (snd_BUG_ON(!type_ids[vx->type])) - return -EINVAL; - strcpy(info->id, type_ids[vx->type]); - if (vx_is_pcmcia(vx)) - info->num_dsps = 4; - else - info->num_dsps = 3; - if (vx->chip_status & VX_STAT_CHIP_INIT) - info->chip_ready = 1; - info->version = VX_DRIVER_VERSION; - return 0; -} - -static void free_fw(const struct firmware *fw) -{ - if (fw) { - vfree(fw->data); - kfree(fw); - } -} - -static int vx_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct vx_core *vx = hw->private_data; - int index, err; - struct firmware *fw; - - if (snd_BUG_ON(!vx->ops->load_dsp)) - return -ENXIO; - - fw = kmalloc(sizeof(*fw), GFP_KERNEL); - if (! fw) { - snd_printk(KERN_ERR "cannot allocate firmware\n"); - return -ENOMEM; - } - fw->size = dsp->length; - fw->data = vmalloc(fw->size); - if (! fw->data) { - snd_printk(KERN_ERR "cannot allocate firmware image (length=%d)\n", - (int)fw->size); - kfree(fw); - return -ENOMEM; - } - if (copy_from_user((void *)fw->data, dsp->image, dsp->length)) { - free_fw(fw); - return -EFAULT; - } - - index = dsp->index; - if (! vx_is_pcmcia(vx)) - index++; - err = vx->ops->load_dsp(vx, index, fw); - if (err < 0) { - free_fw(fw); - return err; - } -#ifdef CONFIG_PM - vx->firmware[index] = fw; -#else - free_fw(fw); -#endif - - if (index == 1) - vx->chip_status |= VX_STAT_XILINX_LOADED; - if (index < 3) - return 0; - - /* ok, we reached to the last one */ - /* create the devices if not built yet */ - if (! (vx->chip_status & VX_STAT_DEVICE_INIT)) { - if ((err = snd_vx_pcm_new(vx)) < 0) - return err; - - if ((err = snd_vx_mixer_new(vx)) < 0) - return err; - - if (vx->ops->add_controls) - if ((err = vx->ops->add_controls(vx)) < 0) - return err; - - if ((err = snd_card_register(vx->card)) < 0) - return err; - - vx->chip_status |= VX_STAT_DEVICE_INIT; - } - vx->chip_status |= VX_STAT_CHIP_INIT; - return 0; -} - - -/* exported */ -int snd_vx_setup_firmware(struct vx_core *chip) -{ - int err; - struct snd_hwdep *hw; - - if ((err = snd_hwdep_new(chip->card, SND_VX_HWDEP_ID, 0, &hw)) < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_VX; - hw->private_data = chip; - hw->ops.dsp_status = vx_hwdep_dsp_status; - hw->ops.dsp_load = vx_hwdep_dsp_load; - hw->exclusive = 1; - sprintf(hw->name, "VX Loader (%s)", chip->card->driver); - chip->hwdep = hw; - - return snd_card_register(chip->card); -} - -/* exported */ -void snd_vx_free_firmware(struct vx_core *chip) -{ -#ifdef CONFIG_PM - int i; - for (i = 0; i < 4; i++) - free_fw(chip->firmware[i]); -#endif -} - -#endif /* SND_VX_FW_LOADER */ - EXPORT_SYMBOL(snd_vx_setup_firmware); EXPORT_SYMBOL(snd_vx_free_firmware);
The new firmware code tries to re-read the formerly read firmware files before suspend. Thus it's wiser to keep the "patch" firmware in the driver for avoiding this unnecessary re-reading.
Of course, this will consume a bit of memory for unused stuff, but the patch fw is supposed to be fairly small, so it's more benefit in the end.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 83be855..4bb52da 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -3507,8 +3507,10 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) chip->fw->data); if (err < 0) goto out_free; +#ifndef CONFIG_PM release_firmware(chip->fw); /* no longer needed */ chip->fw = NULL; +#endif } #endif if ((probe_only[dev] & 1) == 0) {
Th buffer to save registers for PM is enough small for kmalloc(), not necessary to use vmalloc().
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/ymfpci/ymfpci_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 3a6f03f..60e8cb2 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -25,7 +25,6 @@ #include <linux/pci.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/mutex.h> #include <linux/module.h>
@@ -2261,7 +2260,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) #endif
#ifdef CONFIG_PM_SLEEP - vfree(chip->saved_regs); + kfree(chip->saved_regs); #endif if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -2471,7 +2470,8 @@ int __devinit snd_ymfpci_create(struct snd_card *card, }
#ifdef CONFIG_PM_SLEEP - chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32)); + chip->saved_regs = kmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32), + GFP_KERNEL); if (chip->saved_regs == NULL) { snd_ymfpci_free(chip); return -ENOMEM;
As the recent firmware code tries to reread and cache the firmware by itself, it's even better to keep the struct firmware data instead of keeping a local copy. Also, it makes little sense to disable the fw loader for this driver, so added the explicit dependency, too.
Last, but not least, allocate the firmware data loaded via ioctl in vmalloc'ed buffer instead, as the firmware size isn't that small.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/Kconfig | 1 + sound/pci/rme9652/hdsp.c | 62 ++++++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 59dbb70..947cfb4 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -572,6 +572,7 @@ source "sound/pci/hda/Kconfig"
config SND_HDSP tristate "RME Hammerfall DSP Audio" + select FW_LOADER select SND_HWDEP select SND_RAWMIDI select SND_PCM diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 0d6930c..b8ddbb1 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -59,13 +59,11 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," "{RME HDSP-9652}," "{RME HDSP-9632}}"); -#ifdef HDSP_FW_LOADER MODULE_FIRMWARE("rpm_firmware.bin"); MODULE_FIRMWARE("multiface_firmware.bin"); MODULE_FIRMWARE("multiface_firmware_rev11.bin"); MODULE_FIRMWARE("digiface_firmware.bin"); MODULE_FIRMWARE("digiface_firmware_rev11.bin"); -#endif
#define HDSP_MAX_CHANNELS 26 #define HDSP_MAX_DS_CHANNELS 14 @@ -423,12 +421,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024)
-/* use hotplug firmware loader? */ -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(HDSP_USE_HWDEP_LOADER) -#define HDSP_FW_LOADER -#endif -#endif +#define HDSP_FIRMWARE_SIZE (24413 * 4)
struct hdsp_9632_meters { u32 input_peak[16]; @@ -475,7 +468,8 @@ struct hdsp { enum HDSP_IO_Type io_type; /* ditto, but for code use */ unsigned short firmware_rev; unsigned short state; /* stores state bits */ - u32 firmware_cache[24413]; /* this helps recover from accidental iobox power failure */ + const struct firmware *firmware; + u32 *fw_uploaded; size_t period_bytes; /* guess what this is */ unsigned char max_channels; unsigned char qs_in_channels; /* quad speed mode for H9632 */ @@ -712,6 +706,17 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
int i; unsigned long flags; + const u32 *cache; + + if (hdsp->fw_uploaded) + cache = hdsp->fw_uploaded; + else { + if (!hdsp->firmware) + return -ENODEV; + cache = (u32 *)hdsp->firmware->data; + if (!cache) + return -ENODEV; + }
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
@@ -727,8 +732,8 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) {
hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD);
- for (i = 0; i < 24413; ++i) { - hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]); + for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) { + hdsp_write(hdsp, HDSP_fifoData, cache[i]); if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) { snd_printk ("Hammerfall-DSP: timeout during firmware loading\n"); return -EIO; @@ -798,9 +803,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) }
-#ifdef HDSP_FW_LOADER static int hdsp_request_fw_loader(struct hdsp *hdsp); -#endif
static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) { @@ -813,10 +816,8 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); /* try to load firmware */ if (! (hdsp->state & HDSP_FirmwareCached)) { -#ifdef HDSP_FW_LOADER if (! hdsp_request_fw_loader(hdsp)) return 0; -#endif snd_printk(KERN_ERR "Hammerfall-DSP: No firmware loaded nor " "cached, please upload firmware.\n"); @@ -3673,9 +3674,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } } else { int err = -EINVAL; -#ifdef HDSP_FW_LOADER err = hdsp_request_fw_loader(hdsp); -#endif if (err < 0) { snd_iprintf(buffer, "No firmware loaded nor cached, " @@ -5100,8 +5099,18 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if (hdsp_check_for_iobox (hdsp)) return -EIO;
- if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0) + if (!hdsp->fw_uploaded) { + hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE); + if (!hdsp->fw_uploaded) + return -ENOMEM; + } + + if (copy_from_user(hdsp->fw_uploaded, firmware_data, + HDSP_FIRMWARE_SIZE)) { + vfree(hdsp->fw_uploaded); + hdsp->fw_uploaded = NULL; return -EFAULT; + }
hdsp->state |= HDSP_FirmwareCached;
@@ -5330,7 +5339,6 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp return 0; }
-#ifdef HDSP_FW_LOADER /* load firmware via hotplug fw loader */ static int hdsp_request_fw_loader(struct hdsp *hdsp) { @@ -5373,16 +5381,13 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile); return -ENOENT; } - if (fw->size < sizeof(hdsp->firmware_cache)) { + if (fw->size < HDSP_FIRMWARE_SIZE) { snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n", - (int)fw->size, (int)sizeof(hdsp->firmware_cache)); - release_firmware(fw); + (int)fw->size, HDSP_FIRMWARE_SIZE); return -EINVAL; }
- memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); - - release_firmware(fw); + hdsp->firmware = fw;
hdsp->state |= HDSP_FirmwareCached;
@@ -5406,7 +5411,6 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) } return 0; } -#endif
static int __devinit snd_hdsp_create(struct snd_card *card, struct hdsp *hdsp) @@ -5504,7 +5508,6 @@ static int __devinit snd_hdsp_create(struct snd_card *card, return err;
if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { -#ifdef HDSP_FW_LOADER if ((err = hdsp_request_fw_loader(hdsp)) < 0) /* we don't fail as this can happen if userspace is not ready for @@ -5514,7 +5517,6 @@ static int __devinit snd_hdsp_create(struct snd_card *card, else /* init is complete, we return */ return 0; -#endif /* we defer initialization */ snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n"); if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) @@ -5568,6 +5570,10 @@ static int snd_hdsp_free(struct hdsp *hdsp)
snd_hdsp_free_buffers(hdsp);
+ if (hdsp->firmware) + release_firmware(hdsp->firmware); + vfree(hdsp->fw_uploaded); + if (hdsp->iobase) iounmap(hdsp->iobase);
Instead of calling request_firmware() at each time, keep the obtained firmware internally and reuse it.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/emu10k1.h | 3 ++ sound/pci/emu10k1/emu10k1_main.c | 88 ++++++++++++++++------------------------ 2 files changed, 39 insertions(+), 52 deletions(-)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 3707288..9dc94b5 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -32,6 +32,7 @@ #include <sound/timer.h> #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/firmware.h>
#include <asm/io.h> #include <uapi/sound/emu10k1.h> @@ -1785,6 +1786,8 @@ struct snd_emu10k1 { unsigned int efx_voices_mask[2]; unsigned int next_free_voice;
+ const struct firmware *firmware; + #ifdef CONFIG_PM_SLEEP unsigned int *saved_ptr; unsigned int *saved_gpr; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c21adb6..1dfb94d 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -657,22 +657,17 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; }
-static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename) +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu) { - int err; int n, i; int reg; int value; unsigned int write_post; unsigned long flags; - const struct firmware *fw_entry; + const struct firmware *fw_entry = emu->firmware;
- err = request_firmware(&fw_entry, filename, &emu->pci->dev); - if (err != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err); - return err; - } - snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); + if (!fw_entry) + return -EIO;
/* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -705,7 +700,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags);
- release_firmware(fw_entry); return 0; }
@@ -727,22 +721,9 @@ static int emu1010_firmware_thread(void *data) /* Return to Audio Dock programming mode */ snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010) { - err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010B) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1616) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) - continue; - } + err = snd_emu1010_load_firmware(emu); + if (err != 0) + continue;
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); @@ -807,7 +788,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) unsigned int i; u32 tmp, tmp2, reg; int err; - const char *filename = NULL;
snd_printk(KERN_INFO "emu1010: Special config.\n"); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, @@ -849,31 +829,33 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) return -ENODEV; } snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg); - switch (emu->card_capabilities->emu_model) { - case EMU_MODEL_EMU1010: - filename = HANA_FILENAME; - break; - case EMU_MODEL_EMU1010B: - filename = EMU1010B_FILENAME; - break; - case EMU_MODEL_EMU1616: - filename = EMU1010_NOTEBOOK_FILENAME; - break; - case EMU_MODEL_EMU0404: - filename = EMU0404_FILENAME; - break; - default: - filename = NULL; - return -ENODEV; - break; - } - snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename); - err = snd_emu1010_load_firmware(emu, filename); - if (err != 0) { - snd_printk( - KERN_INFO "emu1010: Loading Firmware file %s failed\n", - filename); - return err; + + if (!emu->firmware) { + const char *filename; + switch (emu->card_capabilities->emu_model) { + case EMU_MODEL_EMU1010: + filename = HANA_FILENAME; + break; + case EMU_MODEL_EMU1010B: + filename = EMU1010B_FILENAME; + break; + case EMU_MODEL_EMU1616: + filename = EMU1010_NOTEBOOK_FILENAME; + break; + case EMU_MODEL_EMU0404: + filename = EMU0404_FILENAME; + break; + default: + return -ENODEV; + } + + err = request_firmware(&emu->firmware, filename, &emu->pci->dev); + if (err != 0) { + snd_printk(KERN_ERR "emu1010: firmware: %s not found. Err = %d\n", filename, err); + return err; + } + snd_printk(KERN_INFO "emu1010: firmware file = %s, size = 0x%zx\n", + filename, emu->firmware->size); }
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */ @@ -1259,6 +1241,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); + if (emu->firmware) + release_firmware(emu->firmware); if (emu->irq >= 0) free_irq(emu->irq, emu); /* remove reserved page */
Add a flag to suppress the update in emu1010_firmware_thread() during suspend/resume.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/emu10k1.h | 1 + sound/pci/emu10k1/emu10k1.c | 4 ++++ sound/pci/emu10k1/emu10k1_main.c | 2 ++ 3 files changed, 7 insertions(+)
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 9dc94b5..f841ba4 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1796,6 +1796,7 @@ struct snd_emu10k1 { unsigned int *saved_icode; unsigned int *p16v_saved; unsigned int saved_a_iocfg, saved_hcfg; + bool suspend; #endif
}; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index b7c1875..a168138 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -215,6 +215,8 @@ static int snd_emu10k1_suspend(struct device *dev)
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ emu->suspend = 1; + snd_pcm_suspend_all(emu->pcm); snd_pcm_suspend_all(emu->pcm_mic); snd_pcm_suspend_all(emu->pcm_efx); @@ -260,6 +262,8 @@ static int snd_emu10k1_resume(struct device *dev) if (emu->card_capabilities->ca0151_chip) snd_p16v_resume(emu);
+ emu->suspend = 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 1dfb94d..cfd6cf9 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -714,6 +714,8 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; + if (emu->suspend) + continue; snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
participants (1)
-
Takashi Iwai