![Michele Baldessari](/assets/img/avatar_default.png)
Firmware load on AS102 is using the stack which is not allowed any longer. We currently fail with: kernel: transfer buffer not dma capable kernel: ------------[ cut here ]------------ kernel: WARNING: CPU: 0 PID: 598 at drivers/usb/core/hcd.c:1595 usb_hcd_map_urb_for_dma+0x41d/0x620 kernel: Modules linked in: amd64_edac_mod(-) edac_mce_amd as102_fe dvb_as102(+) kvm_amd kvm snd_hda_codec_realtek dvb_core snd_hda_codec_generic snd_hda_codec_hdmi snd_hda_intel snd_hda_codec irqbypass crct10dif_pclmul crc32_pclmul snd_hda_core snd_hwdep snd_seq ghash_clmulni_intel sp5100_tco fam15h_power wmi k10temp i2c_piix4 snd_seq_device snd_pcm snd_timer parport_pc parport tpm_infineon snd tpm_tis soundcore tpm_tis_core tpm shpchp acpi_cpufreq xfs libcrc32c amdgpu amdkfd amd_iommu_v2 radeon hid_logitech_hidpp i2c_algo_bit drm_kms_helper crc32c_intel ttm drm r8169 mii hid_logitech_dj kernel: CPU: 0 PID: 598 Comm: systemd-udevd Not tainted 4.13.10-200.fc26.x86_64 #1 kernel: Hardware name: ASUS All Series/AM1I-A, BIOS 0505 03/13/2014 kernel: task: ffff979933b24c80 task.stack: ffffaf83413a4000 kernel: RIP: 0010:usb_hcd_map_urb_for_dma+0x41d/0x620 systemd-fsck[659]: /dev/sda2: clean, 49/128016 files, 268609/512000 blocks kernel: RSP: 0018:ffffaf83413a7728 EFLAGS: 00010282 systemd-udevd[604]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable. kernel: RAX: 000000000000001f RBX: ffff979930bce780 RCX: 0000000000000000 kernel: RDX: 0000000000000000 RSI: ffff97993ec0e118 RDI: ffff97993ec0e118 kernel: RBP: ffffaf83413a7768 R08: 000000000000039a R09: 0000000000000000 kernel: R10: 0000000000000001 R11: 00000000ffffffff R12: 00000000fffffff5 kernel: R13: 0000000001400000 R14: 0000000000000001 R15: ffff979930806800 kernel: FS: 00007effaca5c8c0(0000) GS:ffff97993ec00000(0000) knlGS:0000000000000000 kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 kernel: CR2: 00007effa9fca962 CR3: 0000000233089000 CR4: 00000000000406f0 kernel: Call Trace: kernel: usb_hcd_submit_urb+0x493/0xb40 kernel: ? page_cache_tree_insert+0x100/0x100 kernel: ? xfs_iunlock+0xd5/0x100 [xfs] kernel: ? xfs_file_buffered_aio_read+0x57/0xc0 [xfs] kernel: usb_submit_urb+0x22d/0x560 kernel: usb_start_wait_urb+0x6e/0x180 kernel: usb_bulk_msg+0xb8/0x160 kernel: as102_send_ep1+0x49/0xe0 [dvb_as102] kernel: ? devres_add+0x3f/0x50 kernel: as102_firmware_upload.isra.0+0x1dc/0x210 [dvb_as102] kernel: as102_fw_upload+0xb6/0x1f0 [dvb_as102] kernel: as102_dvb_register+0x2af/0x2d0 [dvb_as102] kernel: as102_usb_probe+0x1f3/0x260 [dvb_as102] kernel: usb_probe_interface+0x124/0x300 kernel: driver_probe_device+0x2ff/0x450 kernel: __driver_attach+0xa4/0xe0 kernel: ? driver_probe_device+0x450/0x450 kernel: bus_for_each_dev+0x6e/0xb0 kernel: driver_attach+0x1e/0x20 kernel: bus_add_driver+0x1c7/0x270 kernel: driver_register+0x60/0xe0 kernel: usb_register_driver+0x81/0x150 kernel: ? 0xffffffffc0807000 kernel: as102_usb_driver_init+0x1e/0x1000 [dvb_as102] kernel: do_one_initcall+0x50/0x190 kernel: ? __vunmap+0x81/0xb0 kernel: ? kfree+0x154/0x170 kernel: ? kmem_cache_alloc_trace+0x15f/0x1c0 kernel: ? do_init_module+0x27/0x1e9 kernel: do_init_module+0x5f/0x1e9 kernel: load_module+0x2602/0x2c30 kernel: SYSC_init_module+0x170/0x1a0 kernel: ? SYSC_init_module+0x170/0x1a0 kernel: SyS_init_module+0xe/0x10 kernel: do_syscall_64+0x67/0x140 kernel: entry_SYSCALL64_slow_path+0x25/0x25 kernel: RIP: 0033:0x7effab6cf3ea kernel: RSP: 002b:00007fff5cfcbbc8 EFLAGS: 00000246 ORIG_RAX: 00000000000000af kernel: RAX: ffffffffffffffda RBX: 00005569e0b83760 RCX: 00007effab6cf3ea kernel: RDX: 00007effac2099c5 RSI: 0000000000009a13 RDI: 00005569e0b98c50 kernel: RBP: 00007effac2099c5 R08: 00005569e0b83ed0 R09: 0000000000001d80 kernel: R10: 00007effab98db00 R11: 0000000000000246 R12: 00005569e0b98c50 kernel: R13: 00005569e0b81c60 R14: 0000000000020000 R15: 00005569dfadfdf7 kernel: Code: 48 39 c8 73 30 80 3d 59 60 9d 00 00 41 bc f5 ff ff ff 0f 85 26 ff ff ff 48 c7 c7 b8 6b d0 92 c6 05 3f 60 9d 00 01 e8 24 3d ad ff <0f> ff 8b 53 64 e9 09 ff ff ff 65 48 8b 0c 25 00 d3 00 00 48 8b kernel: ---[ end trace c4cae366180e70ec ]--- kernel: as10x_usb: error during firmware upload part1 Let's allocate the the structure dynamically so we can get the firmware loaded correctly: [ 14.243057] as10x_usb: firmware: as102_data1_st.hex loaded with success [ 14.500777] as10x_usb: firmware: as102_data2_st.hex loaded with success Signed-off-by: Michele Baldessari <michele@acksyn.org> Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
236 lines
5.5 KiB
C
236 lines
5.5 KiB
C
/*
|
|
* Abilis Systems Single DVB-T Receiver
|
|
* Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
|
|
* Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/firmware.h>
|
|
|
|
#include "as102_drv.h"
|
|
#include "as102_fw.h"
|
|
|
|
static const char as102_st_fw1[] = "as102_data1_st.hex";
|
|
static const char as102_st_fw2[] = "as102_data2_st.hex";
|
|
static const char as102_dt_fw1[] = "as102_data1_dt.hex";
|
|
static const char as102_dt_fw2[] = "as102_data2_dt.hex";
|
|
|
|
static unsigned char atohx(unsigned char *dst, char *src)
|
|
{
|
|
unsigned char value = 0;
|
|
|
|
char msb = tolower(*src) - '0';
|
|
char lsb = tolower(*(src + 1)) - '0';
|
|
|
|
if (msb > 9)
|
|
msb -= 7;
|
|
if (lsb > 9)
|
|
lsb -= 7;
|
|
|
|
*dst = value = ((msb & 0xF) << 4) | (lsb & 0xF);
|
|
return value;
|
|
}
|
|
|
|
/*
|
|
* Parse INTEL HEX firmware file to extract address and data.
|
|
*/
|
|
static int parse_hex_line(unsigned char *fw_data, unsigned char *addr,
|
|
unsigned char *data, int *dataLength,
|
|
unsigned char *addr_has_changed) {
|
|
|
|
int count = 0;
|
|
unsigned char *src, dst;
|
|
|
|
if (*fw_data++ != ':') {
|
|
pr_err("invalid firmware file\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
/* locate end of line */
|
|
for (src = fw_data; *src != '\n'; src += 2) {
|
|
atohx(&dst, src);
|
|
/* parse line to split addr / data */
|
|
switch (count) {
|
|
case 0:
|
|
*dataLength = dst;
|
|
break;
|
|
case 1:
|
|
addr[2] = dst;
|
|
break;
|
|
case 2:
|
|
addr[3] = dst;
|
|
break;
|
|
case 3:
|
|
/* check if data is an address */
|
|
if (dst == 0x04)
|
|
*addr_has_changed = 1;
|
|
else
|
|
*addr_has_changed = 0;
|
|
break;
|
|
case 4:
|
|
case 5:
|
|
if (*addr_has_changed)
|
|
addr[(count - 4)] = dst;
|
|
else
|
|
data[(count - 4)] = dst;
|
|
break;
|
|
default:
|
|
data[(count - 4)] = dst;
|
|
break;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
/* return read value + ':' + '\n' */
|
|
return (count * 2) + 2;
|
|
}
|
|
|
|
static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
|
|
unsigned char *cmd,
|
|
const struct firmware *firmware) {
|
|
|
|
struct as10x_fw_pkt_t *fw_pkt;
|
|
int total_read_bytes = 0, errno = 0;
|
|
unsigned char addr_has_changed = 0;
|
|
|
|
fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL);
|
|
if (!fw_pkt)
|
|
return -ENOMEM;
|
|
|
|
|
|
for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
|
|
int read_bytes = 0, data_len = 0;
|
|
|
|
/* parse intel hex line */
|
|
read_bytes = parse_hex_line(
|
|
(u8 *) (firmware->data + total_read_bytes),
|
|
fw_pkt->raw.address,
|
|
fw_pkt->raw.data,
|
|
&data_len,
|
|
&addr_has_changed);
|
|
|
|
if (read_bytes <= 0)
|
|
goto error;
|
|
|
|
/* detect the end of file */
|
|
total_read_bytes += read_bytes;
|
|
if (total_read_bytes == firmware->size) {
|
|
fw_pkt->u.request[0] = 0x00;
|
|
fw_pkt->u.request[1] = 0x03;
|
|
|
|
/* send EOF command */
|
|
errno = bus_adap->ops->upload_fw_pkt(bus_adap,
|
|
(uint8_t *)
|
|
fw_pkt, 2, 0);
|
|
if (errno < 0)
|
|
goto error;
|
|
} else {
|
|
if (!addr_has_changed) {
|
|
/* prepare command to send */
|
|
fw_pkt->u.request[0] = 0x00;
|
|
fw_pkt->u.request[1] = 0x01;
|
|
|
|
data_len += sizeof(fw_pkt->u.request);
|
|
data_len += sizeof(fw_pkt->raw.address);
|
|
|
|
/* send cmd to device */
|
|
errno = bus_adap->ops->upload_fw_pkt(bus_adap,
|
|
(uint8_t *)
|
|
fw_pkt,
|
|
data_len,
|
|
0);
|
|
if (errno < 0)
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
error:
|
|
kfree(fw_pkt);
|
|
return (errno == 0) ? total_read_bytes : errno;
|
|
}
|
|
|
|
int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
|
|
{
|
|
int errno = -EFAULT;
|
|
const struct firmware *firmware = NULL;
|
|
unsigned char *cmd_buf = NULL;
|
|
const char *fw1, *fw2;
|
|
struct usb_device *dev = bus_adap->usb_dev;
|
|
|
|
/* select fw file to upload */
|
|
if (dual_tuner) {
|
|
fw1 = as102_dt_fw1;
|
|
fw2 = as102_dt_fw2;
|
|
} else {
|
|
fw1 = as102_st_fw1;
|
|
fw2 = as102_st_fw2;
|
|
}
|
|
|
|
/* allocate buffer to store firmware upload command and data */
|
|
cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL);
|
|
if (cmd_buf == NULL) {
|
|
errno = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
/* request kernel to locate firmware file: part1 */
|
|
errno = request_firmware(&firmware, fw1, &dev->dev);
|
|
if (errno < 0) {
|
|
pr_err("%s: unable to locate firmware file: %s\n",
|
|
DRIVER_NAME, fw1);
|
|
goto error;
|
|
}
|
|
|
|
/* initiate firmware upload */
|
|
errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
|
|
if (errno < 0) {
|
|
pr_err("%s: error during firmware upload part1\n",
|
|
DRIVER_NAME);
|
|
goto error;
|
|
}
|
|
|
|
pr_info("%s: firmware: %s loaded with success\n",
|
|
DRIVER_NAME, fw1);
|
|
release_firmware(firmware);
|
|
firmware = NULL;
|
|
|
|
/* wait for boot to complete */
|
|
mdelay(100);
|
|
|
|
/* request kernel to locate firmware file: part2 */
|
|
errno = request_firmware(&firmware, fw2, &dev->dev);
|
|
if (errno < 0) {
|
|
pr_err("%s: unable to locate firmware file: %s\n",
|
|
DRIVER_NAME, fw2);
|
|
goto error;
|
|
}
|
|
|
|
/* initiate firmware upload */
|
|
errno = as102_firmware_upload(bus_adap, cmd_buf, firmware);
|
|
if (errno < 0) {
|
|
pr_err("%s: error during firmware upload part2\n",
|
|
DRIVER_NAME);
|
|
goto error;
|
|
}
|
|
|
|
pr_info("%s: firmware: %s loaded with success\n",
|
|
DRIVER_NAME, fw2);
|
|
error:
|
|
kfree(cmd_buf);
|
|
release_firmware(firmware);
|
|
|
|
return errno;
|
|
}
|