Commit 907afe59 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:
 "Here are a couple of mmc fixes intended for v4.13 rc1.

  MMC core:
   - Restore some behaviour of MMC_IOC_MULTI_CMD commands
   - Fix using un-initialized variable in mmc_blk_issue_drv_op()
   - Fix mmc block queue cleanup

  MMC host:
   - sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld
   - tmio-mmc: Fix bad pointer math"

* tag 'mmc-v4.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: tmio-mmc: fix bad pointer math
  mmc: block: Prevent new req entering queue after its cleanup
  mmc: block: Let MMC_IOC_MULTI_CMD return zero again for zero entries
  mmc: block: Initialize ret in mmc_blk_issue_drv_op() for MMC_DRV_OP_IOCTL
  mmc: sdhci-acpi: Workaround conflict with PCI wifi on GPD Win handheld
parents 0a264b6d 9c284c41
...@@ -637,6 +637,9 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, ...@@ -637,6 +637,9 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
sizeof(num_of_cmds))) sizeof(num_of_cmds)))
return -EFAULT; return -EFAULT;
if (!num_of_cmds)
return 0;
if (num_of_cmds > MMC_IOC_MAX_CMDS) if (num_of_cmds > MMC_IOC_MAX_CMDS)
return -EINVAL; return -EINVAL;
...@@ -1182,7 +1185,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) ...@@ -1182,7 +1185,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) { switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL: case MMC_DRV_OP_IOCTL:
for (i = 0; i < mq_rq->ioc_count; i++) { for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]); ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]);
if (ret) if (ret)
break; break;
...@@ -2167,6 +2170,7 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md) ...@@ -2167,6 +2170,7 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
* from being accepted. * from being accepted.
*/ */
card = md->queue.card; card = md->queue.card;
blk_set_queue_dying(md->queue.queue);
mmc_cleanup_queue(&md->queue); mmc_cleanup_queue(&md->queue);
if (md->disk->flags & GENHD_FL_UP) { if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro); device_remove_file(disk_to_dev(md->disk), &md->force_ro);
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#include <asm/intel-family.h> #include <asm/intel-family.h>
#include <asm/iosf_mbi.h> #include <asm/iosf_mbi.h>
#include <linux/pci.h>
#endif #endif
#include "sdhci.h" #include "sdhci.h"
...@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void) ...@@ -134,6 +135,16 @@ static bool sdhci_acpi_byt(void)
return x86_match_cpu(byt); return x86_match_cpu(byt);
} }
static bool sdhci_acpi_cht(void)
{
static const struct x86_cpu_id cht[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
{}
};
return x86_match_cpu(cht);
}
#define BYT_IOSF_SCCEP 0x63 #define BYT_IOSF_SCCEP 0x63
#define BYT_IOSF_OCP_NETCTRL0 0x1078 #define BYT_IOSF_OCP_NETCTRL0 0x1078
#define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8) #define BYT_IOSF_OCP_TIMEOUT_BASE GENMASK(10, 8)
...@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev) ...@@ -178,6 +189,45 @@ static bool sdhci_acpi_byt_defer(struct device *dev)
return false; return false;
} }
static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
unsigned int slot, unsigned int parent_slot)
{
struct pci_dev *dev, *parent, *from = NULL;
while (1) {
dev = pci_get_device(vendor, device, from);
pci_dev_put(from);
if (!dev)
break;
parent = pci_upstream_bridge(dev);
if (ACPI_COMPANION(&dev->dev) && PCI_SLOT(dev->devfn) == slot &&
parent && PCI_SLOT(parent->devfn) == parent_slot &&
!pci_upstream_bridge(parent)) {
pci_dev_put(dev);
return true;
}
from = dev;
}
return false;
}
/*
* GPDwin uses PCI wifi which conflicts with SDIO's use of
* acpi_device_fix_up_power() on child device nodes. Identifying GPDwin is
* problematic, but since SDIO is only used for wifi, the presence of the PCI
* wifi card in the expected slot with an ACPI companion node, is used to
* indicate that acpi_device_fix_up_power() should be avoided.
*/
static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
const char *uid)
{
return sdhci_acpi_cht() &&
!strcmp(hid, "80860F14") &&
!strcmp(uid, "2") &&
sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
}
#else #else
static inline void sdhci_acpi_byt_setting(struct device *dev) static inline void sdhci_acpi_byt_setting(struct device *dev)
...@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev) ...@@ -189,6 +239,12 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
return false; return false;
} }
static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
const char *uid)
{
return false;
}
#endif #endif
static int bxt_get_cd(struct mmc_host *mmc) static int bxt_get_cd(struct mmc_host *mmc)
...@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -389,18 +445,20 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (acpi_bus_get_device(handle, &device)) if (acpi_bus_get_device(handle, &device))
return -ENODEV; return -ENODEV;
hid = acpi_device_hid(device);
uid = device->pnp.unique_id;
/* Power on the SDHCI controller and its children */ /* Power on the SDHCI controller and its children */
acpi_device_fix_up_power(device); acpi_device_fix_up_power(device);
if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
list_for_each_entry(child, &device->children, node) list_for_each_entry(child, &device->children, node)
if (child->status.present && child->status.enabled) if (child->status.present && child->status.enabled)
acpi_device_fix_up_power(child); acpi_device_fix_up_power(child);
}
if (sdhci_acpi_byt_defer(dev)) if (sdhci_acpi_byt_defer(dev))
return -EPROBE_DEFER; return -EPROBE_DEFER;
hid = acpi_device_hid(device);
uid = device->pnp.unique_id;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) if (!iomem)
return -ENOMEM; return -ENOMEM;
......
...@@ -409,30 +409,29 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host, ...@@ -409,30 +409,29 @@ static void tmio_mmc_transfer_data(struct tmio_mmc_host *host,
* Transfer the data * Transfer the data
*/ */
if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) { if (host->pdata->flags & TMIO_MMC_32BIT_DATA_PORT) {
u8 data[4] = { }; u32 data = 0;
u32 *buf32 = (u32 *)buf;
if (is_read) if (is_read)
sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf, sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, buf32,
count >> 2); count >> 2);
else else
sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, (u32 *)buf, sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, buf32,
count >> 2); count >> 2);
/* if count was multiple of 4 */ /* if count was multiple of 4 */
if (!(count & 0x3)) if (!(count & 0x3))
return; return;
buf8 = (u8 *)(buf + (count >> 2)); buf32 += count >> 2;
count %= 4; count %= 4;
if (is_read) { if (is_read) {
sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, sd_ctrl_read32_rep(host, CTL_SD_DATA_PORT, &data, 1);
(u32 *)data, 1); memcpy(buf32, &data, count);
memcpy(buf8, data, count);
} else { } else {
memcpy(data, buf8, count); memcpy(&data, buf32, count);
sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, sd_ctrl_write32_rep(host, CTL_SD_DATA_PORT, &data, 1);
(u32 *)data, 1);
} }
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment