From 6e99456ad3089ecf55dcf73d8162defdc637fa88 Mon Sep 17 00:00:00 2001 From: Sudheesh Mavila Date: Mon, 20 Aug 2018 00:18:38 +0530 Subject: [PATCH 4123/4131] Fix to the crash observed when the following operations are performed. write and read an i2c device from i2c1 and then i2c0 - works write to a device in i2c1 - crash happens because mp2 gives a wrong interrupt Write to MP2 device is performed but the interrupt received is for read completion [ 493.360134] in write [ 493.362745] BUG: unable to handle kernel NULL pointer dereference at (null) [ 493.370643] IP: [] i2c_amd_read_completion+0x91/0xe0 [i2c_amd_platdrv] [ 493.378779] PGD 2f92ad067 [ 493.381322] PUD 2c4243067 PMD 0 [ 493.384596] [ 493.386107] Oops: 0002 [#1] SMP [ 493.389259] Modules linked in: i2c_amd_platdrv(E) marvell binfmt_misc nls_iso8859_1 pl2303 usbserial amd64_edac_mod edac_mce_amd edac_core snd_hda_codec_hdmi kvm irqbypass snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_seq_midi snd_seq_midi_event joydev input_leds aesni_intel snd_rawmidi snd_seq aes_x86_64 snd_seq_device snd_timer lrw snd_pci_acp3x snd gf128mul soundcore glue_helper i2c_amd_pci_mp2(E) ablk_helper cryptd shpchp i2c_designware_platform i2c_piix4 i2c_designware_core mac_hid parport_pc ppdev lp parport autofs4 amdkfd amd_iommu_v2 mmc_block hid_generic amdgpu chash i2c_algo_bit ttm drm_kms_helper syscopyarea sysfillrect sysimgblt usbhid fb_sys_fops ixgbe dca amd_xgbe ahci ptp drm sdhci_acpi hid libahci pps_core mdio video fjes sdhci [ 493.462798] CPU: 1 PID: 371 Comm: kworker/1:2 Tainted: G E 4.9.0-2018_30_staging+ #71 [ 493.471769] Hardware name: AMD Dibbler/Dibbler, BIOS RDB1106B 07/02/2018 [ 493.478486] Workqueue: events amd_mp2_pci_work [i2c_amd_pci_mp2] [ 493.484526] task: ffff9f3d36bf2ac0 task.stack: ffffbdfac21e4000 [ 493.490457] RIP: 0010:[] [] i2c_amd_read_completion+0x91/0xe0 [i2c_amd_platdrv] [ 493.501014] RSP: 0018:ffffbdfac21e7e08 EFLAGS: 00010246 [ 493.506337] RAX: 0000000000000001 RBX: ffff9f3d40998f00 RCX: 0000000000000000 [ 493.513481] RDX: 0000000000000000 RSI: ffff9f3d3b46da10 RDI: 0000000000060001 [ 493.520624] RBP: ffffbdfac21e7e08 R08: ffff9f3d39db1818 R09: 0000000000000000 [ 493.527771] R10: 00000000ffffffff R11: 0000000000000eb5 R12: ffff9f3d43259180 [ 493.534915] R13: ffff9f3d4325da00 R14: 0000000000000040 R15: ffff9f3d380054b0 [ 493.542061] FS: 0000000000000000(0000) GS:ffff9f3d43240000(0000) knlGS:0000000000000000 [ 493.550162] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 493.555918] CR2: 0000000000000000 CR3: 00000002fe0a7000 CR4: 00000000003406f0 [ 493.563064] Stack: [ 493.565087] ffffbdfac21e7e18 ffffffffc034d202 ffffbdfac21e7e58 ffffffffbb0a0641 [ 493.572587] 0000000000000000 ffff9f3d43259180 ffff9f3d40998f30 0000000000000008 [ 493.580096] ffff9f3d432591a0 ffff9f3d40998f00 ffffbdfac21e7ec0 ffffffffbb0a09ab [ 493.587600] Call Trace: [ 493.590059] [] amd_mp2_pci_work+0xa2/0x130 [i2c_amd_pci_mp2] [ 493.597382] [] process_one_work+0x171/0x490 [ 493.603225] [] worker_thread+0x4b/0x500 [ 493.608719] [] ? process_one_work+0x490/0x490 [ 493.614736] [] ? process_one_work+0x490/0x490 [ 493.620753] [] ? SyS_exit_group+0x14/0x20 [ 493.626424] [] kthread+0xdb/0x100 [ 493.631401] [] ? kthread_park+0x60/0x60 [ 493.636900] [] ? do_syscall_64+0x73/0xe0 [ 493.642486] [] ret_from_fork+0x44/0x70 [ 493.647894] Code: 03 f3 48 a5 31 d2 49 8d b8 68 04 00 00 66 41 89 90 92 04 00 00 e8 10 2f 96 fa 31 c0 5d c3 a8 04 75 46 85 c0 74 de 0f b6 16 a8 02 <88> 11 74 d5 89 c2 0f b7 44 16 fe 66 89 44 11 fe eb c7 83 f8 08 [ 493.668399] RIP [] i2c_amd_read_completion+0x91/0xe0 [i2c_amd_platdrv] [ 493.676623] RSP [ 493.680125] CR2: 0000000000000000 [ 493.685840] ---[ end trace 7505e21302a270d5 ]--- [ 493.690480] BUG: unable to handle kernel paging request at 00000000ee1d23ba [ 493.697502] IP:[ 493.697968] in write [ 493.702151] [] __wake_up_common+0x2e/0x90 [ 493.708523] PGD 2f92ad067 [ 493.711069] PUD 0 [ 493.713785] [ 493.715961] Oops: 0000 [#2] SMP Signed-off-by: Sudheesh Mavila --- drivers/i2c/busses/i2c-amd-pci-mp2.c | 50 +++++++++++++++++++++++++----------- drivers/i2c/busses/i2c-amd-pci-mp2.h | 2 +- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.c b/drivers/i2c/busses/i2c-amd-pci-mp2.c index e8c58c7..d313435 100644 --- a/drivers/i2c/busses/i2c-amd-pci-mp2.c +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.c @@ -76,6 +76,7 @@ int amd_mp2_connect(struct pci_dev *dev, dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__, connect_cfg.dev_addr, connect_cfg.bus_id); + privdata->requested[connect_cfg.bus_id] = true; i2c_cmd_base.ul = 0; i2c_cmd_base.s.i2c_cmd = i2c_enable; i2c_cmd_base.s.bus_id = connect_cfg.bus_id; @@ -99,11 +100,12 @@ int amd_mp2_read(struct pci_dev *dev, struct i2c_read_config read_cfg) { struct amd_mp2_dev *privdata = pci_get_drvdata(dev); union i2c_cmd_base i2c_cmd_base; - + int busid = read_cfg.bus_id; + dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__, read_cfg.dev_addr, read_cfg.bus_id); - privdata->requested = true; + privdata->requested[busid] = true; i2c_cmd_base.ul = 0; i2c_cmd_base.s.i2c_cmd = i2c_read; i2c_cmd_base.s.dev_addr = read_cfg.dev_addr; @@ -166,8 +168,10 @@ int amd_mp2_write(struct pci_dev *dev, struct i2c_write_config write_cfg) struct amd_mp2_dev *privdata = pci_get_drvdata(dev); union i2c_cmd_base i2c_cmd_base; int i = 0; + int busid = write_cfg.bus_id; - privdata->requested = true; + privdata->requested[busid] = true; + dev_dbg(ndev_dev(privdata), "%s addr: %x id: %d\n", __func__, write_cfg.dev_addr, write_cfg.bus_id); @@ -292,31 +296,46 @@ static irqreturn_t amd_mp2_irq_isr(int irq, void *dev) { struct amd_mp2_dev *privdata = dev; u32 val = 0; + int busid = i2c_bus_max; unsigned long flags; + + if (!privdata->ops) { + writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); + return IRQ_HANDLED; + } raw_spin_lock_irqsave(&privdata->lock, flags); val = readl(privdata->mmio + AMD_P2C_MSG1); if (val != 0) { writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); - privdata->eventval.base.ul = val; - } else { + busid = i2c_bus_0; + + if (privdata->requested[i2c_bus_0] ) { + privdata->eventval.base.ul = val; + privdata->requested[i2c_bus_0] = false; + raw_spin_unlock_irqrestore(&privdata->lock, flags); + schedule_delayed_work(&privdata->work, 0); + return IRQ_HANDLED; + } + } + val = readl(privdata->mmio + AMD_P2C_MSG2); if (val != 0) { writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); + busid = i2c_bus_1; + if (privdata->requested[i2c_bus_1] ) { privdata->eventval.base.ul = val; + privdata->requested[i2c_bus_1] = false; + raw_spin_unlock_irqrestore(&privdata->lock, flags); + schedule_delayed_work(&privdata->work, 0); + return IRQ_HANDLED; } } + if(busid == i2c_bus_max) { + writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); + } raw_spin_unlock_irqrestore(&privdata->lock, flags); - if (!privdata->ops) - return IRQ_NONE; - - if (!privdata->requested) - return IRQ_HANDLED; - - privdata->requested = false; - schedule_delayed_work(&privdata->work, 0); - return IRQ_HANDLED; } @@ -495,7 +514,8 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct pci_dev *pdev) /* Try to set up intx irq */ pci_intx(pdev, 1); privdata->eventval.buf = NULL; - privdata->requested = false; + privdata->requested[i2c_bus_0] = false; + privdata->requested[i2c_bus_1] = false; raw_spin_lock_init(&privdata->lock); rc = request_irq(pdev->irq, amd_mp2_irq_isr, IRQF_SHARED, "mp2_irq_isr", privdata); diff --git a/drivers/i2c/busses/i2c-amd-pci-mp2.h b/drivers/i2c/busses/i2c-amd-pci-mp2.h index d4b343a..8fef977 100644 --- a/drivers/i2c/busses/i2c-amd-pci-mp2.h +++ b/drivers/i2c/busses/i2c-amd-pci-mp2.h @@ -233,7 +233,7 @@ struct amd_mp2_dev { const struct amd_i2c_pci_ops *ops; struct delayed_work work; u8 i2c_dev_id; - bool requested; + bool requested[i2c_bus_max]; raw_spinlock_t lock; }; -- 2.7.4