openwrt/target/linux/ipq806x/patches-4.9/860-qcom-mtd-nand-Add-bam_dma-support-in-qcom_nand-drive.patch
Jo-Philipp Wich 55623a9c83 kernel: update kernel 4.9 to 4.9.31
Fixes the following security vulnerabilities:

CVE-2017-8890
The inet_csk_clone_lock function in net/ipv4/inet_connection_sock.c in the
Linux kernel through 4.10.15 allows attackers to cause a denial of service
(double free) or possibly have unspecified other impact by leveraging use
of the accept system call.

CVE-2017-9074
The IPv6 fragmentation implementation in the Linux kernel through 4.11.1
does not consider that the nexthdr field may be associated with an invalid
option, which allows local users to cause a denial of service (out-of-bounds
read and BUG) or possibly have unspecified other impact via crafted socket
and send system calls.

CVE-2017-9075
The sctp_v6_create_accept_sk function in net/sctp/ipv6.c in the Linux kernel
through 4.11.1 mishandles inheritance, which allows local users to cause a
denial of service or possibly have unspecified other impact via crafted
system calls, a related issue to CVE-2017-8890.

CVE-2017-9076
The dccp_v6_request_recv_sock function in net/dccp/ipv6.c in the Linux
kernel through 4.11.1 mishandles inheritance, which allows local users to
cause a denial of service or possibly have unspecified other impact via
crafted system calls, a related issue to CVE-2017-8890.

CVE-2017-9077
The tcp_v6_syn_recv_sock function in net/ipv6/tcp_ipv6.c in the Linux kernel
through 4.11.1 mishandles inheritance, which allows local users to cause a
denial of service or possibly have unspecified other impact via crafted
system calls, a related issue to CVE-2017-8890.

CVE-2017-9242
The __ip6_append_data function in net/ipv6/ip6_output.c in the Linux kernel
through 4.11.3 is too late in checking whether an overwrite of an skb data
structure may occur, which allows local users to cause a denial of service
(system crash) via crafted system calls.

Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-8890
Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9074
Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9075
Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9076
Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9077
Ref: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9242
Ref: https://www.kernel.org/pub/linux/kernel/v4.x/ChangeLog-4.9.31

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2017-06-08 01:03:39 +02:00

380 lines
11 KiB
Diff

From 074036f9de6b8c5fc642e8e2540950f6a35aa804 Mon Sep 17 00:00:00 2001
From: Ram Chandra Jangir <rjangir@codeaurora.org>
Date: Thu, 20 Apr 2017 10:31:10 +0530
Subject: [PATCH] qcom: mtd: nand: Add bam_dma support in qcom_nand driver
The current driver only support ADM DMA so this patch adds the
BAM DMA support in current NAND driver with compatible string
qcom,ebi2-nandc-bam.
Added bam channels and data buffers, NAND BAM uses 3 channels:
command, data tx and data rx, while ADM uses only single channel.
So this patch adds the BAM channel in device tree and using the
same in NAND driver allocation function.
Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
---
.../devicetree/bindings/mtd/qcom_nandc.txt | 69 +++++++--
drivers/mtd/nand/qcom_nandc.c | 160 +++++++++++++++++----
2 files changed, 190 insertions(+), 39 deletions(-)
--- a/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
@@ -1,21 +1,26 @@
* Qualcomm NAND controller
Required properties:
-- compatible: should be "qcom,ipq806x-nand"
+- compatible: "qcom,ipq806x-nand" for IPQ8064 which uses
+ ADM DMA.
+ "qcom,ebi2-nand-bam" - nand drivers using BAM DMA
+ like IPQ4019.
- reg: MMIO address range
- clocks: must contain core clock and always on clock
- clock-names: must contain "core" for the core clock and "aon" for the
always on clock
- dmas: DMA specifier, consisting of a phandle to the ADM DMA
- controller node and the channel number to be used for
- NAND. Refer to dma.txt and qcom_adm.txt for more details
-- dma-names: must be "rxtx"
-- qcom,cmd-crci: must contain the ADM command type CRCI block instance
- number specified for the NAND controller on the given
- platform
-- qcom,data-crci: must contain the ADM data type CRCI block instance
- number specified for the NAND controller on the given
- platform
+ or BAM DMA controller node and the channel number to
+ be used for NAND. Refer to dma.txt, qcom_adm.txt(ADM)
+ and qcom_bam_dma.txt(BAM) for more details
+- dma-names: "rxtx" - ADM
+ "tx", "rx", "cmd" - BAM
+- qcom,cmd-crci: Only required for ADM DMA. must contain the ADM command
+ type CRCI block instance number specified for the NAND
+ controller on the given platform.
+- qcom,data-crci: Only required for ADM DMA. must contain the ADM data
+ type CRCI block instance number specified for the NAND
+ controller on the given platform.
- #address-cells: <1> - subnodes give the chip-select number
- #size-cells: <0>
@@ -44,7 +49,7 @@ partition.txt for more detail.
Example:
nand@1ac00000 {
- compatible = "qcom,ebi2-nandc";
+ compatible = "qcom,ipq806x-nand","qcom.qcom_nand";
reg = <0x1ac00000 0x800>;
clocks = <&gcc EBI2_CLK>,
@@ -58,6 +63,48 @@ nand@1ac00000 {
#address-cells = <1>;
#size-cells = <0>;
+
+ nandcs@0 {
+ compatible = "qcom,nandcs";
+ reg = <0>;
+
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+ nand-bus-width = <8>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "boot-nand";
+ reg = <0 0x58a0000>;
+ };
+
+ partition@58a0000 {
+ label = "fs-nand";
+ reg = <0x58a0000 0x4000000>;
+ };
+ };
+ };
+};
+
+nand@79B0000 {
+ compatible = "qcom,ebi2-nandc-bam";
+ reg = <0x79B0000 0x1000>;
+
+ clocks = <&gcc EBI2_CLK>,
+ <&gcc EBI2_AON_CLK>;
+ clock-names = "core", "aon";
+
+ dmas = <&qpicbam 0>,
+ <&qpicbam 1>,
+ <&qpicbam 2>;
+ dma-names = "tx", "rx", "cmd";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
nandcs@0 {
compatible = "qcom,nandcs";
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -226,6 +226,7 @@ struct nandc_regs {
* by upper layers directly
* @buf_size/count/start: markers for chip->read_buf/write_buf functions
* @reg_read_buf: local buffer for reading back registers via DMA
+ * @reg_read_buf_phys: contains dma address for register read buffer
* @reg_read_pos: marker for data read in reg_read_buf
*
* @regs: a contiguous chunk of memory for DMA register
@@ -234,7 +235,10 @@ struct nandc_regs {
* @cmd1/vld: some fixed controller register values
* @ecc_modes: supported ECC modes by the current controller,
* initialized via DT match data
- */
+ * @bch_enabled: flag to tell whether BCH or RS ECC mode is used
+ * @dma_bam_enabled: flag to tell whether nand controller is using
+ * bam dma
+*/
struct qcom_nand_controller {
struct nand_hw_control controller;
struct list_head host_list;
@@ -247,17 +251,28 @@ struct qcom_nand_controller {
struct clk *core_clk;
struct clk *aon_clk;
- struct dma_chan *chan;
- unsigned int cmd_crci;
- unsigned int data_crci;
struct list_head desc_list;
+ union {
+ struct {
+ struct dma_chan *tx_chan;
+ struct dma_chan *rx_chan;
+ struct dma_chan *cmd_chan;
+ };
+ struct {
+ struct dma_chan *chan;
+ unsigned int cmd_crci;
+ unsigned int data_crci;
+ };
+ };
u8 *data_buffer;
+ bool dma_bam_enabled;
int buf_size;
int buf_count;
int buf_start;
__le32 *reg_read_buf;
+ dma_addr_t reg_read_buf_phys;
int reg_read_pos;
struct nandc_regs *regs;
@@ -316,6 +331,17 @@ struct qcom_nand_host {
u32 clrreadstatus;
};
+/*
+ * This data type corresponds to the nand driver data which will be used at
+ * driver probe time
+ * @ecc_modes - ecc mode for nand
+ * @dma_bam_enabled - whether this driver is using bam
+ */
+struct qcom_nand_driver_data {
+ u32 ecc_modes;
+ bool dma_bam_enabled;
+};
+
static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip)
{
return container_of(chip, struct qcom_nand_host, chip);
@@ -1893,7 +1919,7 @@ static int qcom_nand_host_setup(struct q
| wide_bus << WIDE_FLASH
| 1 << DEV0_CFG1_ECC_DISABLE;
- host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+ host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
| 0 << ECC_SW_RESET
| host->cw_data << ECC_NUM_DATA_BYTES
| 1 << ECC_FORCE_CLK_OPEN
@@ -1942,16 +1968,46 @@ static int qcom_nandc_alloc(struct qcom_
if (!nandc->regs)
return -ENOMEM;
- nandc->reg_read_buf = devm_kzalloc(nandc->dev,
- MAX_REG_RD * sizeof(*nandc->reg_read_buf),
- GFP_KERNEL);
- if (!nandc->reg_read_buf)
- return -ENOMEM;
+ if (!nandc->dma_bam_enabled) {
+ nandc->reg_read_buf = devm_kzalloc(nandc->dev,
+ MAX_REG_RD *
+ sizeof(*nandc->reg_read_buf),
+ GFP_KERNEL);
- nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
- if (!nandc->chan) {
- dev_err(nandc->dev, "failed to request slave channel\n");
- return -ENODEV;
+ if (!nandc->reg_read_buf)
+ return -ENOMEM;
+
+ nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx");
+ if (!nandc->chan) {
+ dev_err(nandc->dev, "failed to request slave channel\n");
+ return -ENODEV;
+ }
+ } else {
+ nandc->reg_read_buf = dmam_alloc_coherent(nandc->dev,
+ MAX_REG_RD *
+ sizeof(*nandc->reg_read_buf),
+ &nandc->reg_read_buf_phys, GFP_KERNEL);
+
+ if (!nandc->reg_read_buf)
+ return -ENOMEM;
+
+ nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx");
+ if (!nandc->tx_chan) {
+ dev_err(nandc->dev, "failed to request tx channel\n");
+ return -ENODEV;
+ }
+
+ nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx");
+ if (!nandc->rx_chan) {
+ dev_err(nandc->dev, "failed to request rx channel\n");
+ return -ENODEV;
+ }
+
+ nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd");
+ if (!nandc->cmd_chan) {
+ dev_err(nandc->dev, "failed to request cmd channel\n");
+ return -ENODEV;
+ }
}
INIT_LIST_HEAD(&nandc->desc_list);
@@ -1964,8 +2020,35 @@ static int qcom_nandc_alloc(struct qcom_
static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc)
{
- dma_release_channel(nandc->chan);
-}
+ if (nandc->dma_bam_enabled) {
+ if (nandc->tx_chan)
+ dma_release_channel(nandc->tx_chan);
+
+ if (nandc->rx_chan)
+ dma_release_channel(nandc->rx_chan);
+
+ if (nandc->cmd_chan)
+ dma_release_channel(nandc->tx_chan);
+
+ if (nandc->reg_read_buf)
+ dmam_free_coherent(nandc->dev, MAX_REG_RD *
+ sizeof(*nandc->reg_read_buf),
+ nandc->reg_read_buf,
+ nandc->reg_read_buf_phys);
+ } else {
+ if (nandc->chan)
+ dma_release_channel(nandc->chan);
+
+ if (nandc->reg_read_buf)
+ devm_kfree(nandc->dev, nandc->reg_read_buf);
+ }
+
+ if (nandc->regs)
+ devm_kfree(nandc->dev, nandc->regs);
+
+ if (nandc->data_buffer)
+ devm_kfree(nandc->dev, nandc->data_buffer);
+ }
/* one time setup of a few nand controller registers */
static int qcom_nandc_setup(struct qcom_nand_controller *nandc)
@@ -2002,6 +2085,8 @@ static int qcom_nand_host_init(struct qc
mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs);
mtd->owner = THIS_MODULE;
mtd->dev.parent = dev;
+ mtd->priv = chip;
+ chip->priv = nandc;
chip->cmdfunc = qcom_nandc_command;
chip->select_chip = qcom_nandc_select_chip;
@@ -2049,16 +2134,20 @@ static int qcom_nandc_parse_dt(struct pl
struct device_node *np = nandc->dev->of_node;
int ret;
- ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci);
- if (ret) {
- dev_err(nandc->dev, "command CRCI unspecified\n");
- return ret;
- }
+ if (!nandc->dma_bam_enabled) {
+ ret = of_property_read_u32(np, "qcom,cmd-crci",
+ &nandc->cmd_crci);
+ if (ret) {
+ dev_err(nandc->dev, "command CRCI unspecified\n");
+ return ret;
+ }
- ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci);
- if (ret) {
- dev_err(nandc->dev, "data CRCI unspecified\n");
- return ret;
+ ret = of_property_read_u32(np, "qcom,data-crci",
+ &nandc->data_crci);
+ if (ret) {
+ dev_err(nandc->dev, "data CRCI unspecified\n");
+ return ret;
+ }
}
return 0;
@@ -2073,6 +2162,7 @@ static int qcom_nandc_probe(struct platf
struct device_node *dn = dev->of_node, *child;
struct resource *res;
int ret;
+ struct qcom_nand_driver_data *driver_data;
nandc = devm_kzalloc(&pdev->dev, sizeof(*nandc), GFP_KERNEL);
if (!nandc)
@@ -2087,7 +2177,10 @@ static int qcom_nandc_probe(struct platf
return -ENODEV;
}
- nandc->ecc_modes = (unsigned long)dev_data;
+ driver_data = (struct qcom_nand_driver_data *)dev_data;
+
+ nandc->ecc_modes = driver_data->ecc_modes;
+ nandc->dma_bam_enabled = driver_data->dma_bam_enabled;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nandc->base = devm_ioremap_resource(dev, res);
@@ -2179,7 +2272,15 @@ static int qcom_nandc_remove(struct plat
return 0;
}
-#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT)
+struct qcom_nand_driver_data ebi2_nandc_bam_data = {
+ .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT),
+ .dma_bam_enabled = true,
+};
+
+struct qcom_nand_driver_data ebi2_nandc_data = {
+ .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT),
+ .dma_bam_enabled = false,
+};
/*
* data will hold a struct pointer containing more differences once we support
@@ -2187,7 +2288,10 @@ static int qcom_nandc_remove(struct plat
*/
static const struct of_device_id qcom_nandc_of_match[] = {
{ .compatible = "qcom,ipq806x-nand",
- .data = (void *)EBI2_NANDC_ECC_MODES,
+ .data = (void *) &ebi2_nandc_data,
+ },
+ { .compatible = "qcom,ebi2-nandc-bam",
+ .data = (void *) &ebi2_nandc_bam_data,
},
{}
};