mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
Compare commits
29 Commits
ft5x06-fil
...
stable_202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ed6d34d53 | ||
|
|
eccaa8588f | ||
|
|
f075893e9b | ||
|
|
5a52cae54a | ||
|
|
4137b49989 | ||
|
|
93b52ae53a | ||
|
|
4cb97982f8 | ||
|
|
cb8a4adb58 | ||
|
|
74d906b6ca | ||
|
|
87be940591 | ||
|
|
0e9e925112 | ||
|
|
e33170e214 | ||
|
|
f429fc1a07 | ||
|
|
ff2db5847b | ||
|
|
61b138adae | ||
|
|
1216ea56c2 | ||
|
|
0c7fb448e0 | ||
|
|
b6bfece0d9 | ||
|
|
c145506588 | ||
|
|
0f51aa6afb | ||
|
|
6ab30a5dd3 | ||
|
|
2a47ccf97c | ||
|
|
adc4d740ad | ||
|
|
38fd36728f | ||
|
|
ff74bdc838 | ||
|
|
b0cee281c4 | ||
|
|
ebf5841ac1 | ||
|
|
506cf335d9 | ||
|
|
e8db8b5581 |
2
Makefile
2
Makefile
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 1
|
||||
SUBLEVEL = 57
|
||||
SUBLEVEL = 58
|
||||
EXTRAVERSION =
|
||||
NAME = Curry Ramen
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* Downstream modifications to bcm2835-rpi.dtsi */
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
aliases: aliases {
|
||||
aux = &aux;
|
||||
sound = &sound;
|
||||
soc = &soc;
|
||||
@@ -98,6 +98,9 @@
|
||||
sdio_overclock = <&mmc>,"brcm,overclock-50:0",
|
||||
<&mmcnr>,"brcm,overclock-50:0";
|
||||
axiperf = <&axiperf>,"status";
|
||||
drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
|
||||
drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
|
||||
drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
/ {
|
||||
compatible = "raspberrypi,5-model-b", "brcm,bcm2712";
|
||||
model = "Raspberry Pi 5 Model B";
|
||||
model = "Raspberry Pi 5";
|
||||
|
||||
/* Will be filled by the bootloader */
|
||||
memory@0 {
|
||||
@@ -787,8 +787,8 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
|
||||
gpio4 = &pinctrl_aon;
|
||||
usb0 = &rp1_usb0;
|
||||
usb1 = &rp1_usb1;
|
||||
drm_dsi1 = &dsi0;
|
||||
drm_dsi2 = &dsi1;
|
||||
drm-dsi1 = &dsi0;
|
||||
drm-dsi2 = &dsi1;
|
||||
};
|
||||
|
||||
__overrides__ {
|
||||
@@ -809,6 +809,7 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
|
||||
i2c_baudrate = <&i2c_arm>, "clock-frequency:0";
|
||||
i2c_arm_baudrate = <&i2c_arm>, "clock-frequency:0";
|
||||
i2c_vc_baudrate = <&i2c_vc>, "clock-frequency:0";
|
||||
krnbt = <&bluetooth>, "status";
|
||||
nvme = <&pciex1>, "status";
|
||||
pciex1 = <&pciex1>, "status";
|
||||
pciex1_gen = <&pciex1> , "max-link-speed:0";
|
||||
@@ -824,5 +825,17 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
|
||||
act_led_trigger = <&act_led>, "linux,default-trigger";
|
||||
pwr_led_activelow = <&pwr_led>, "gpios:8";
|
||||
pwr_led_trigger = <&pwr_led>, "linux,default-trigger";
|
||||
drm_fb0_rp1_dsi0 = <&aliases>, "drm-fb0=",&dsi0;
|
||||
drm_fb0_rp1_dsi1 = <&aliases>, "drm-fb0=",&dsi1;
|
||||
drm_fb0_rp1_dpi = <&aliases>, "drm-fb0=",&dpi;
|
||||
drm_fb0_vc4 = <&aliases>, "drm-fb0=",&vc4;
|
||||
drm_fb1_rp1_dsi0 = <&aliases>, "drm-fb1=",&dsi0;
|
||||
drm_fb1_rp1_dsi1 = <&aliases>, "drm-fb1=",&dsi1;
|
||||
drm_fb1_rp1_dpi = <&aliases>, "drm-fb1=",&dpi;
|
||||
drm_fb1_vc4 = <&aliases>, "drm-fb1=",&vc4;
|
||||
drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
|
||||
drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
|
||||
drm_fb2_rp1_dpi = <&aliases>, "drm-fb2=",&dpi;
|
||||
drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
};
|
||||
|
||||
firmwarekms: firmwarekms@7d503000 {
|
||||
compatible = "raspberrypi,rpi-firmware-kms";
|
||||
compatible = "raspberrypi,rpi-firmware-kms-2712";
|
||||
/* SUN_L2 interrupt reg */
|
||||
reg = <0x7d503000 0x18>;
|
||||
interrupt-parent = <&cpu_l2_irq>;
|
||||
|
||||
@@ -59,6 +59,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
|
||||
draws.dtbo \
|
||||
dwc-otg.dtbo \
|
||||
dwc2.dtbo \
|
||||
dwc2-pi5.dtbo \
|
||||
edt-ft5406.dtbo \
|
||||
enc28j60.dtbo \
|
||||
enc28j60-spi2.dtbo \
|
||||
|
||||
@@ -173,6 +173,30 @@ Params:
|
||||
cooling_fan Enables the Pi 5 cooling fan (enabled
|
||||
automatically by the firmware)
|
||||
|
||||
drm_fb0_rp1_dpi Assign /dev/fb0 to the RP1 DPI output
|
||||
|
||||
drm_fb0_rp1_dsi0 Assign /dev/fb0 to the RP1 DSI0 output
|
||||
|
||||
drm_fb0_rp1_dsi1 Assign /dev/fb0 to the RP1 DSI1 output
|
||||
|
||||
drm_fb0_vc4 Assign /dev/fb0 to the vc4 outputs
|
||||
|
||||
drm_fb1_rp1_dpi Assign /dev/fb1 to the RP1 DPI output
|
||||
|
||||
drm_fb1_rp1_dsi0 Assign /dev/fb1 to the RP1 DSI0 output
|
||||
|
||||
drm_fb1_rp1_dsi1 Assign /dev/fb1 to the RP1 DSI1 output
|
||||
|
||||
drm_fb1_vc4 Assign /dev/fb1 to the vc4 outputs
|
||||
|
||||
drm_fb2_rp1_dpi Assign /dev/fb2 to the RP1 DPI output
|
||||
|
||||
drm_fb2_rp1_dsi0 Assign /dev/fb2 to the RP1 DSI0 output
|
||||
|
||||
drm_fb2_rp1_dsi1 Assign /dev/fb2 to the RP1 DSI1 output
|
||||
|
||||
drm_fb2_vc4 Assign /dev/fb2 to the vc4 outputs
|
||||
|
||||
eee Enable Energy Efficient Ethernet support for
|
||||
compatible devices (default "on"). See also
|
||||
"tx_lpi_timer". Pi3B+ only.
|
||||
@@ -1083,6 +1107,10 @@ Params: dr_mode Dual role mode: "host", "peripheral" or "otg"
|
||||
mode
|
||||
|
||||
|
||||
Name: dwc2-pi5
|
||||
Info: See dwc2 (this is the Pi 5 version)
|
||||
|
||||
|
||||
[ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]
|
||||
|
||||
|
||||
@@ -3714,7 +3742,7 @@ Name: rpi-ft5406
|
||||
Info: Official Raspberry Pi display touchscreen
|
||||
Load: dtoverlay=rpi-ft5406,<param>=<val>
|
||||
Params: touchscreen-size-x Touchscreen X resolution (default 800)
|
||||
touchscreen-size-y Touchscreen Y resolution (default 600);
|
||||
touchscreen-size-y Touchscreen Y resolution (default 480);
|
||||
touchscreen-inverted-x Invert touchscreen X coordinates (default 0);
|
||||
touchscreen-inverted-y Invert touchscreen Y coordinates (default 0);
|
||||
touchscreen-swapped-x-y Swap X and Y cordinates (default 0);
|
||||
|
||||
18
arch/arm/boot/dts/overlays/dwc2-pi5-overlay.dts
Normal file
18
arch/arm/boot/dts/overlays/dwc2-pi5-overlay.dts
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "dwc2-overlay.dts"
|
||||
|
||||
/{
|
||||
fragment@1 {
|
||||
target-path = "/";
|
||||
__overlay__ {
|
||||
/*
|
||||
* Add a node with a dma-ranges value that exists only to be found
|
||||
* by of_dma_get_max_cpu_address, and hence limit the DMA zone.
|
||||
*/
|
||||
zone_dma {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
dma-ranges = <0x0 0x0 0x0 0x40000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -24,30 +24,13 @@
|
||||
};
|
||||
|
||||
fragment@2 {
|
||||
target = <&i2cbus>;
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mcp23017: mcp@20 {
|
||||
compatible = "microchip,mcp23017";
|
||||
reg = <0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fragment@3 {
|
||||
target = <&mcp23017>;
|
||||
__dormant__ {
|
||||
compatible = "microchip,mcp23008";
|
||||
};
|
||||
};
|
||||
|
||||
fragment@4 {
|
||||
fragment@3 {
|
||||
target = <&mcp23017>;
|
||||
mcp23017_irq: __overlay__ {
|
||||
#interrupt-cells=<2>;
|
||||
@@ -58,6 +41,25 @@
|
||||
};
|
||||
};
|
||||
|
||||
fragment@4 {
|
||||
target = <&i2cbus>;
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mcp23017: mcp@20 {
|
||||
compatible = "microchip,mcp23017";
|
||||
pinctrl-name = "default";
|
||||
pinctrl-0 = <&mcp23017_pins>;
|
||||
reg = <0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
frag100: fragment@100 {
|
||||
target = <&i2c1>;
|
||||
i2cbus: __overlay__ {
|
||||
@@ -83,8 +85,8 @@
|
||||
gpiopin = <&mcp23017_pins>,"brcm,pins:0",
|
||||
<&mcp23017_irq>,"interrupts:0";
|
||||
addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
|
||||
mcp23008 = <0>,"=3";
|
||||
noints = <0>,"!1!4";
|
||||
mcp23008 = <0>,"=2";
|
||||
noints = <0>,"!1!3";
|
||||
i2c0 = <&frag100>, "target:0=",<&i2c0>;
|
||||
i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
|
||||
<0>,"+101+102";
|
||||
|
||||
@@ -48,6 +48,16 @@
|
||||
bcm2712;
|
||||
};
|
||||
|
||||
dwc2 {
|
||||
bcm2835;
|
||||
bcm2711;
|
||||
bcm2712 = "dwc2-pi5";
|
||||
};
|
||||
|
||||
dwc2-pi5 {
|
||||
bcm2712;
|
||||
};
|
||||
|
||||
highperi {
|
||||
bcm2711;
|
||||
};
|
||||
|
||||
@@ -23,9 +23,21 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/broadcom/vc_mem.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/platform_data/dma-bcm2708.h>
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#define DRIVER_NAME "vc-mem"
|
||||
|
||||
/* N.B. These use a different magic value for compatibility with bmc7208_fb */
|
||||
#define VC_MEM_IOC_DMACOPY _IOW('z', 0x22, struct vc_mem_dmacopy)
|
||||
#define VC_MEM_IOC_DMACOPY32 _IOW('z', 0x22, struct vc_mem_dmacopy32)
|
||||
|
||||
/* address with no aliases */
|
||||
#define INTALIAS_NORMAL(x) ((x) & ~0xc0000000)
|
||||
/* cache coherent but non-allocating in L1 and L2 */
|
||||
#define INTALIAS_L1L2_NONALLOCATING(x) (((x) & ~0xc0000000) | 0x80000000)
|
||||
|
||||
/* Device (/dev) related variables */
|
||||
static dev_t vc_mem_devnum;
|
||||
static struct class *vc_mem_class;
|
||||
@@ -36,6 +48,20 @@ static int vc_mem_inited;
|
||||
static struct dentry *vc_mem_debugfs_entry;
|
||||
#endif
|
||||
|
||||
struct vc_mem_dmacopy {
|
||||
void *dst;
|
||||
__u32 src;
|
||||
__u32 length;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct vc_mem_dmacopy32 {
|
||||
compat_uptr_t dst;
|
||||
__u32 src;
|
||||
__u32 length;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Videocore memory addresses and size
|
||||
*
|
||||
@@ -62,6 +88,20 @@ static uint phys_addr;
|
||||
static uint mem_size;
|
||||
static uint mem_base;
|
||||
|
||||
struct vc_mem_dma {
|
||||
struct device *dev;
|
||||
int dma_chan;
|
||||
int dma_irq;
|
||||
void __iomem *dma_chan_base;
|
||||
wait_queue_head_t dma_waitq;
|
||||
void *cb_base; /* DMA control blocks */
|
||||
dma_addr_t cb_handle;
|
||||
};
|
||||
|
||||
struct { u32 base, length; } gpu_mem;
|
||||
static struct mutex dma_mutex;
|
||||
static struct vc_mem_dma vc_mem_dma;
|
||||
|
||||
static int
|
||||
vc_mem_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
@@ -99,6 +139,189 @@ vc_mem_get_current_size(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
|
||||
|
||||
static int
|
||||
vc_mem_dma_init(void)
|
||||
{
|
||||
struct vc_mem_dma *vcdma = &vc_mem_dma;
|
||||
struct platform_device *pdev;
|
||||
struct device_node *fwnode;
|
||||
struct rpi_firmware *fw;
|
||||
struct device *dev;
|
||||
u32 revision;
|
||||
int rc;
|
||||
|
||||
if (vcdma->dev)
|
||||
return 0;
|
||||
|
||||
fwnode = of_find_node_by_path("/system");
|
||||
rc = of_property_read_u32(fwnode, "linux,revision", &revision);
|
||||
revision = (revision >> 12) & 0xf;
|
||||
if (revision != 1 && revision != 2) {
|
||||
/* Only BCM2709 and BCM2710 may have logs where the ARMs
|
||||
* can't see them.
|
||||
*/
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
fwnode = rpi_firmware_find_node();
|
||||
if (!fwnode)
|
||||
return -ENXIO;
|
||||
|
||||
pdev = of_find_device_by_node(fwnode);
|
||||
dev = &pdev->dev;
|
||||
|
||||
rc = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
fw = rpi_firmware_get(fwnode);
|
||||
if (!fw)
|
||||
return -ENXIO;
|
||||
rc = rpi_firmware_property(fw, RPI_FIRMWARE_GET_VC_MEMORY,
|
||||
&gpu_mem, sizeof(gpu_mem));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
gpu_mem.base = INTALIAS_NORMAL(gpu_mem.base);
|
||||
|
||||
if (!gpu_mem.base || !gpu_mem.length) {
|
||||
dev_err(dev, "%s: unable to determine gpu memory (%x,%x)\n",
|
||||
__func__, gpu_mem.base, gpu_mem.length);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
vcdma->cb_base = dma_alloc_wc(dev, SZ_4K, &vcdma->cb_handle, GFP_KERNEL);
|
||||
if (!vcdma->cb_base) {
|
||||
dev_err(dev, "failed to allocate DMA CBs\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
|
||||
&vcdma->dma_chan_base,
|
||||
&vcdma->dma_irq);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "failed to allocate a DMA channel\n");
|
||||
goto free_cb;
|
||||
}
|
||||
|
||||
vcdma->dma_chan = rc;
|
||||
|
||||
init_waitqueue_head(&vcdma->dma_waitq);
|
||||
|
||||
vcdma->dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
free_cb:
|
||||
dma_free_wc(dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
vc_mem_dma_uninit(void)
|
||||
{
|
||||
struct vc_mem_dma *vcdma = &vc_mem_dma;
|
||||
|
||||
if (vcdma->dev) {
|
||||
bcm_dma_chan_free(vcdma->dma_chan);
|
||||
dma_free_wc(vcdma->dev, SZ_4K, vcdma->cb_base, vcdma->cb_handle);
|
||||
vcdma->dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int dma_memcpy(struct vc_mem_dma *vcdma, dma_addr_t dst, dma_addr_t src,
|
||||
int size)
|
||||
{
|
||||
struct bcm2708_dma_cb *cb = vcdma->cb_base;
|
||||
int burst_size = (vcdma->dma_chan == 0) ? 8 : 2;
|
||||
|
||||
cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
|
||||
BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
|
||||
BCM2708_DMA_D_INC;
|
||||
cb->dst = dst;
|
||||
cb->src = src;
|
||||
cb->length = size;
|
||||
cb->stride = 0;
|
||||
cb->pad[0] = 0;
|
||||
cb->pad[1] = 0;
|
||||
cb->next = 0;
|
||||
|
||||
bcm_dma_start(vcdma->dma_chan_base, vcdma->cb_handle);
|
||||
bcm_dma_wait_idle(vcdma->dma_chan_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long vc_mem_copy(struct vc_mem_dmacopy *ioparam)
|
||||
{
|
||||
struct vc_mem_dma *vcdma = &vc_mem_dma;
|
||||
size_t size = PAGE_SIZE;
|
||||
const u32 dma_xfer_chunk = 256;
|
||||
u32 *buf = NULL;
|
||||
dma_addr_t bus_addr;
|
||||
long rc = 0;
|
||||
size_t offset;
|
||||
|
||||
/* restrict this to root user */
|
||||
if (!uid_eq(current_euid(), GLOBAL_ROOT_UID))
|
||||
return -EFAULT;
|
||||
|
||||
if (mutex_lock_interruptible(&dma_mutex))
|
||||
return -EINTR;
|
||||
|
||||
rc = vc_mem_dma_init();
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
vcdma = &vc_mem_dma;
|
||||
|
||||
if (INTALIAS_NORMAL(ioparam->src) < gpu_mem.base ||
|
||||
INTALIAS_NORMAL(ioparam->src) >= gpu_mem.base + gpu_mem.length) {
|
||||
pr_err("%s: invalid memory access %x (%x-%x)", __func__,
|
||||
INTALIAS_NORMAL(ioparam->src), gpu_mem.base,
|
||||
gpu_mem.base + gpu_mem.length);
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = dma_alloc_coherent(vcdma->dev, PAGE_ALIGN(size), &bus_addr,
|
||||
GFP_ATOMIC);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (offset = 0; offset < ioparam->length; offset += size) {
|
||||
size_t remaining = ioparam->length - offset;
|
||||
size_t s = min(size, remaining);
|
||||
u8 *p = (u8 *)((uintptr_t)ioparam->src + offset);
|
||||
u8 *q = (u8 *)ioparam->dst + offset;
|
||||
|
||||
rc = dma_memcpy(vcdma, bus_addr,
|
||||
INTALIAS_L1L2_NONALLOCATING((u32)(uintptr_t)p),
|
||||
(s + dma_xfer_chunk - 1) & ~(dma_xfer_chunk - 1));
|
||||
if (rc) {
|
||||
dev_err(vcdma->dev, "dma_memcpy failed\n");
|
||||
break;
|
||||
}
|
||||
if (copy_to_user(q, buf, s) != 0) {
|
||||
pr_err("%s: copy_to_user failed\n", __func__);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (buf)
|
||||
dma_free_coherent(vcdma->dev, PAGE_ALIGN(size), buf,
|
||||
bus_addr);
|
||||
|
||||
mutex_unlock(&dma_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long
|
||||
vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
@@ -163,6 +386,21 @@ vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VC_MEM_IOC_DMACOPY:
|
||||
{
|
||||
struct vc_mem_dmacopy ioparam;
|
||||
/* Get the parameter data.
|
||||
*/
|
||||
if (copy_from_user
|
||||
(&ioparam, (void *)arg, sizeof(ioparam))) {
|
||||
pr_err("%s: copy_from_user failed\n", __func__);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = vc_mem_copy(&ioparam);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return -ENOTTY;
|
||||
@@ -193,6 +431,24 @@ vc_mem_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
|
||||
break;
|
||||
|
||||
case VC_MEM_IOC_DMACOPY32:
|
||||
{
|
||||
struct vc_mem_dmacopy32 param32;
|
||||
struct vc_mem_dmacopy param;
|
||||
/* Get the parameter data.
|
||||
*/
|
||||
if (copy_from_user(¶m32, (void *)arg, sizeof(param32))) {
|
||||
pr_err("%s: copy_from_user failed\n", __func__);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
param.dst = compat_ptr(param32.dst);
|
||||
param.src = param32.src;
|
||||
param.length = param32.length;
|
||||
rc = vc_mem_copy(¶m);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
rc = vc_mem_ioctl(file, cmd, arg);
|
||||
break;
|
||||
@@ -330,6 +586,7 @@ vc_mem_init(void)
|
||||
vc_mem_debugfs_init(dev);
|
||||
#endif
|
||||
|
||||
mutex_init(&dma_mutex);
|
||||
vc_mem_inited = 1;
|
||||
return 0;
|
||||
|
||||
@@ -352,6 +609,7 @@ vc_mem_exit(void)
|
||||
{
|
||||
pr_debug("%s: called\n", __func__);
|
||||
|
||||
vc_mem_dma_uninit();
|
||||
if (vc_mem_inited) {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
vc_mem_debugfs_deinit();
|
||||
@@ -360,6 +618,7 @@ vc_mem_exit(void)
|
||||
class_destroy(vc_mem_class);
|
||||
cdev_del(&vc_mem_cdev);
|
||||
unregister_chrdev_region(vc_mem_devnum, 1);
|
||||
vc_mem_inited = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
|
||||
};
|
||||
|
||||
#define MAX_DT_NODE_NAME_LEN 20
|
||||
#define DT_DRM_NODE_PREFIX "drm_"
|
||||
#define DT_DRM_NODE_PREFIX "drm-"
|
||||
|
||||
static void drm_connector_get_of_name(int type, char *node_name, int length)
|
||||
{
|
||||
|
||||
@@ -1932,7 +1932,7 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
|
||||
struct drm_device *dev = fb_helper->dev;
|
||||
struct fb_info *info;
|
||||
unsigned int width, height;
|
||||
int ret;
|
||||
int ret, id;
|
||||
|
||||
width = dev->mode_config.max_width;
|
||||
height = dev->mode_config.max_height;
|
||||
@@ -1967,6 +1967,15 @@ __drm_fb_helper_initial_config_and_unlock(struct drm_fb_helper *fb_helper,
|
||||
* register the fbdev emulation instance in kernel_fb_helper_list. */
|
||||
mutex_unlock(&fb_helper->lock);
|
||||
|
||||
id = of_alias_get_highest_id("drm-fb");
|
||||
if (id >= 0)
|
||||
fb_set_lowest_dynamic_fb(id + 1);
|
||||
|
||||
id = of_alias_get_id(dev->dev->of_node, "drm-fb");
|
||||
if (id >= 0) {
|
||||
info->node = id;
|
||||
info->custom_fb_num = true;
|
||||
}
|
||||
ret = register_framebuffer(info);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -47,9 +47,15 @@ struct get_display_cfg {
|
||||
u32 max_pixel_clock[2]; //Max pixel clock for each display
|
||||
};
|
||||
|
||||
enum vc4_fkms_revision {
|
||||
BCM2835_6_7,
|
||||
BCM2711,
|
||||
BCM2712,
|
||||
};
|
||||
|
||||
struct vc4_fkms {
|
||||
struct get_display_cfg cfg;
|
||||
bool bcm2711;
|
||||
enum vc4_fkms_revision revision;
|
||||
};
|
||||
|
||||
#define PLANES_PER_CRTC 8
|
||||
@@ -255,6 +261,13 @@ static const struct vc_image_format *vc4_get_vc_image_fmt(u32 drm_format)
|
||||
/* The firmware delivers a vblank interrupt to us through the SMI
|
||||
* hardware, which has only this one register.
|
||||
*/
|
||||
#define SMICS 0x0
|
||||
#define SMIDSW0 0x14
|
||||
#define SMIDSW1 0x1C
|
||||
#define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
|
||||
|
||||
/* Flag to denote that the firmware is giving multiple display callbacks */
|
||||
#define SMI_NEW 0xabcd0000
|
||||
|
||||
#define vc4_crtc vc4_kms_crtc
|
||||
#define to_vc4_crtc to_vc4_kms_crtc
|
||||
@@ -1142,7 +1155,7 @@ vc4_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode)
|
||||
/* Pi4 can't generate odd horizontal timings on HDMI, so reject modes
|
||||
* that would set them.
|
||||
*/
|
||||
if (fkms->bcm2711 &&
|
||||
if (fkms->revision >= BCM2711 &&
|
||||
(vc4_crtc->display_number == 2 || vc4_crtc->display_number == 7) &&
|
||||
!(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
|
||||
((mode->hdisplay | /* active */
|
||||
@@ -1214,13 +1227,16 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct vc4_crtc **crtc_list = data;
|
||||
int i;
|
||||
u32 stat = readl(crtc_list[0]->regs + SMICS);
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 chan;
|
||||
if (1) {
|
||||
|
||||
chan = 0;
|
||||
if (stat & SMICS_INTERRUPTS) {
|
||||
writel(0, crtc_list[0]->regs + SMICS);
|
||||
|
||||
if (1) {
|
||||
chan = readl(crtc_list[0]->regs + SMIDSW0);
|
||||
|
||||
if ((chan & 0xFFFF0000) != SMI_NEW) {
|
||||
/* Older firmware. Treat the one interrupt as vblank/
|
||||
* complete for all crtcs.
|
||||
*/
|
||||
@@ -1231,7 +1247,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
||||
}
|
||||
} else {
|
||||
if (chan & 1) {
|
||||
//writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
|
||||
writel(SMI_NEW, crtc_list[0]->regs + SMIDSW0);
|
||||
if (crtc_list[0]->vblank_enabled)
|
||||
drm_crtc_handle_vblank(&crtc_list[0]->base);
|
||||
vc4_crtc_handle_page_flip(crtc_list[0]);
|
||||
@@ -1239,10 +1255,10 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
||||
|
||||
if (crtc_list[1]) {
|
||||
/* Check for the secondary display too */
|
||||
//chan = readl(crtc_list[0]->regs + SMIDSW1);
|
||||
chan = readl(crtc_list[0]->regs + SMIDSW1);
|
||||
|
||||
if (chan & 1) {
|
||||
//writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
|
||||
writel(SMI_NEW, crtc_list[0]->regs + SMIDSW1);
|
||||
|
||||
if (crtc_list[1]->vblank_enabled)
|
||||
drm_crtc_handle_vblank(&crtc_list[1]->base);
|
||||
@@ -1257,6 +1273,20 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t vc4_crtc2712_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct vc4_crtc **crtc_list = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; crtc_list[i]; i++) {
|
||||
if (crtc_list[i]->vblank_enabled)
|
||||
drm_crtc_handle_vblank(&crtc_list[i]->base);
|
||||
vc4_crtc_handle_page_flip(crtc_list[i]);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int vc4_fkms_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
@@ -1342,9 +1372,12 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
|
||||
};
|
||||
|
||||
static const struct of_device_id vc4_firmware_kms_dt_match[] = {
|
||||
{ .compatible = "raspberrypi,rpi-firmware-kms" },
|
||||
{ .compatible = "raspberrypi,rpi-firmware-kms",
|
||||
.data = (void *)BCM2835_6_7 },
|
||||
{ .compatible = "raspberrypi,rpi-firmware-kms-2711",
|
||||
.data = (void *)1 },
|
||||
.data = (void *)BCM2711 },
|
||||
{ .compatible = "raspberrypi,rpi-firmware-kms-2712",
|
||||
.data = (void *)BCM2712 },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1914,8 +1947,7 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
match = of_match_device(vc4_firmware_kms_dt_match, dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
if (match->data)
|
||||
fkms->bcm2711 = true;
|
||||
fkms->revision = (enum vc4_fkms_revision)match->data;
|
||||
|
||||
firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
|
||||
vc4->firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node);
|
||||
@@ -1982,10 +2014,16 @@ static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
|
||||
if (IS_ERR(crtc_list[0]->regs))
|
||||
DRM_ERROR("Oh dear, failed to map registers\n");
|
||||
|
||||
//writel(0, crtc_list[0]->regs + SMICS);
|
||||
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
vc4_crtc_irq_handler, 0,
|
||||
"vc4 firmware kms", crtc_list);
|
||||
if (fkms->revision >= BCM2712) {
|
||||
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
vc4_crtc2712_irq_handler, 0,
|
||||
"vc4 firmware kms", crtc_list);
|
||||
} else {
|
||||
writel(0, crtc_list[0]->regs + SMICS);
|
||||
ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
vc4_crtc_irq_handler, 0,
|
||||
"vc4 firmware kms", crtc_list);
|
||||
}
|
||||
if (ret)
|
||||
DRM_ERROR("Oh dear, failed to register IRQ\n");
|
||||
} else {
|
||||
|
||||
@@ -1447,9 +1447,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
|
||||
vc4_state->ptr0_offset[0] = vc4_state->dlist_count;
|
||||
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i);
|
||||
struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i);
|
||||
|
||||
vc4_dlist_write(vc4_state, paddr + offsets[i]);
|
||||
vc4_dlist_write(vc4_state, bo->dma_addr + fb->offsets[i] + offsets[i]);
|
||||
}
|
||||
|
||||
/* Pointer Context Word 0/1/2: Written by the HVS */
|
||||
@@ -1842,9 +1842,8 @@ static int vc6_plane_mode_set(struct drm_plane *plane,
|
||||
* TODO: This only covers Raster Scan Order planes
|
||||
*/
|
||||
for (i = 0; i < num_planes; i++) {
|
||||
dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i);
|
||||
|
||||
paddr += offsets[i];
|
||||
struct drm_gem_dma_object *bo = drm_fb_dma_get_gem_obj(fb, i);
|
||||
dma_addr_t paddr = bo->dma_addr + fb->offsets[i] + offsets[i];
|
||||
|
||||
/* Pointer Word 0 */
|
||||
vc4_state->ptr0_offset[i] = vc4_state->dlist_count;
|
||||
|
||||
@@ -632,7 +632,7 @@ static const struct imx477_reg mode_2028x1520_regs[] = {
|
||||
{0x9e9f, 0x00},
|
||||
{0xa2a9, 0x60},
|
||||
{0xa2b7, 0x00},
|
||||
{0x0401, 0x01},
|
||||
{0x0401, 0x00},
|
||||
{0x0404, 0x00},
|
||||
{0x0405, 0x20},
|
||||
{0x0408, 0x00},
|
||||
@@ -733,7 +733,7 @@ static const struct imx477_reg mode_2028x1080_regs[] = {
|
||||
{0x9e9f, 0x00},
|
||||
{0xa2a9, 0x60},
|
||||
{0xa2b7, 0x00},
|
||||
{0x0401, 0x01},
|
||||
{0x0401, 0x00},
|
||||
{0x0404, 0x00},
|
||||
{0x0405, 0x20},
|
||||
{0x0408, 0x00},
|
||||
|
||||
@@ -786,6 +786,9 @@ static void cfe_start_channel(struct cfe_node *node)
|
||||
width = source_fmt->width;
|
||||
height = source_fmt->height;
|
||||
|
||||
/* Must have a valid CSI2 datatype. */
|
||||
WARN_ON(!fmt->csi_dt);
|
||||
|
||||
/*
|
||||
* Start the associated CSI2 Channel as well.
|
||||
*
|
||||
@@ -809,6 +812,9 @@ static void cfe_start_channel(struct cfe_node *node)
|
||||
node_desc[node->id].link_pad - CSI2_NUM_CHANNELS);
|
||||
fmt = find_format_by_code(source_fmt->code);
|
||||
|
||||
/* Must have a valid CSI2 datatype. */
|
||||
WARN_ON(!fmt->csi_dt);
|
||||
|
||||
if (is_image_output_node(node)) {
|
||||
width = source_fmt->width;
|
||||
height = source_fmt->height;
|
||||
@@ -1504,7 +1510,8 @@ static int cfe_video_link_validate(struct media_link *link)
|
||||
|
||||
if (is_image_output_node(node)) {
|
||||
struct v4l2_pix_format *pix_fmt = &node->fmt.fmt.pix;
|
||||
const struct cfe_fmt *fmt;
|
||||
const struct cfe_fmt *fmt = NULL;
|
||||
unsigned int i;
|
||||
|
||||
if (source_fmt->width != pix_fmt->width ||
|
||||
source_fmt->height != pix_fmt->height) {
|
||||
@@ -1516,8 +1523,14 @@ static int cfe_video_link_validate(struct media_link *link)
|
||||
goto out;
|
||||
}
|
||||
|
||||
fmt = find_format_by_code(source_fmt->code);
|
||||
if (!fmt || fmt->fourcc != pix_fmt->pixelformat) {
|
||||
for (i = 0; i < ARRAY_SIZE(formats); i++) {
|
||||
if (formats[i].code == source_fmt->code &&
|
||||
formats[i].fourcc == pix_fmt->pixelformat) {
|
||||
fmt = &formats[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fmt) {
|
||||
cfe_err("Format mismatch!\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
||||
@@ -52,6 +52,7 @@ static DEFINE_MUTEX(registration_lock);
|
||||
|
||||
struct fb_info *registered_fb[FB_MAX] __read_mostly;
|
||||
int num_registered_fb __read_mostly;
|
||||
int min_dynamic_fb __read_mostly;
|
||||
#define for_each_registered_fb(i) \
|
||||
for (i = 0; i < FB_MAX; i++) \
|
||||
if (!registered_fb[i]) {} else
|
||||
@@ -1579,19 +1580,22 @@ static int do_register_framebuffer(struct fb_info *fb_info)
|
||||
return -ENXIO;
|
||||
|
||||
num_registered_fb++;
|
||||
for (i = 0 ; i < FB_MAX; i++)
|
||||
if (!registered_fb[i])
|
||||
break;
|
||||
fb_info->node = i;
|
||||
if (!fb_info->custom_fb_num || fb_info->node >= FB_MAX || registered_fb[fb_info->node]) {
|
||||
for (i = min_dynamic_fb ; i < FB_MAX; i++)
|
||||
if (!registered_fb[i])
|
||||
break;
|
||||
fb_info->node = i;
|
||||
}
|
||||
refcount_set(&fb_info->count, 1);
|
||||
mutex_init(&fb_info->lock);
|
||||
mutex_init(&fb_info->mm_lock);
|
||||
|
||||
fb_info->dev = device_create(fb_class, fb_info->device,
|
||||
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
|
||||
MKDEV(FB_MAJOR, fb_info->node), NULL, "fb%d", fb_info->node);
|
||||
if (IS_ERR(fb_info->dev)) {
|
||||
/* Not fatal */
|
||||
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
|
||||
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n",
|
||||
fb_info->node, PTR_ERR(fb_info->dev));
|
||||
fb_info->dev = NULL;
|
||||
} else
|
||||
fb_init_device(fb_info);
|
||||
@@ -1624,7 +1628,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
|
||||
|
||||
fb_var_to_videomode(&mode, &fb_info->var);
|
||||
fb_add_videomode(&mode, &fb_info->modelist);
|
||||
registered_fb[i] = fb_info;
|
||||
registered_fb[fb_info->node] = fb_info;
|
||||
|
||||
#ifdef CONFIG_GUMSTIX_AM200EPD
|
||||
{
|
||||
@@ -1719,6 +1723,12 @@ static int fb_aperture_acquire_for_platform_device(struct fb_info *fb_info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fb_set_lowest_dynamic_fb(int min_fb_dev)
|
||||
{
|
||||
min_dynamic_fb = min_fb_dev;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_set_lowest_dynamic_fb);
|
||||
|
||||
/**
|
||||
* register_framebuffer - registers a frame buffer device
|
||||
* @fb_info: frame buffer info structure
|
||||
|
||||
138
fs/nfs/direct.c
138
fs/nfs/direct.c
@@ -93,10 +93,12 @@ nfs_direct_handle_truncated(struct nfs_direct_req *dreq,
|
||||
dreq->max_count = dreq_len;
|
||||
if (dreq->count > dreq_len)
|
||||
dreq->count = dreq_len;
|
||||
}
|
||||
|
||||
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && !dreq->error)
|
||||
dreq->error = hdr->error;
|
||||
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
|
||||
dreq->error = hdr->error;
|
||||
else /* Clear outstanding error if this is EOF */
|
||||
dreq->error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -118,18 +120,6 @@ nfs_direct_count_bytes(struct nfs_direct_req *dreq,
|
||||
dreq->count = dreq_len;
|
||||
}
|
||||
|
||||
static void nfs_direct_truncate_request(struct nfs_direct_req *dreq,
|
||||
struct nfs_page *req)
|
||||
{
|
||||
loff_t offs = req_offset(req);
|
||||
size_t req_start = (size_t)(offs - dreq->io_start);
|
||||
|
||||
if (req_start < dreq->max_count)
|
||||
dreq->max_count = req_start;
|
||||
if (req_start < dreq->count)
|
||||
dreq->count = req_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_swap_rw - NFS address space operation for swap I/O
|
||||
* @iocb: target I/O control block
|
||||
@@ -500,9 +490,7 @@ static void nfs_direct_add_page_head(struct list_head *list,
|
||||
kref_get(&head->wb_kref);
|
||||
}
|
||||
|
||||
static void nfs_direct_join_group(struct list_head *list,
|
||||
struct nfs_commit_info *cinfo,
|
||||
struct inode *inode)
|
||||
static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
|
||||
{
|
||||
struct nfs_page *req, *subreq;
|
||||
|
||||
@@ -524,7 +512,7 @@ static void nfs_direct_join_group(struct list_head *list,
|
||||
nfs_release_request(subreq);
|
||||
}
|
||||
} while ((subreq = subreq->wb_this_page) != req);
|
||||
nfs_join_page_group(req, cinfo, inode);
|
||||
nfs_join_page_group(req, inode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,15 +530,20 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
|
||||
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||
{
|
||||
struct nfs_pageio_descriptor desc;
|
||||
struct nfs_page *req;
|
||||
struct nfs_page *req, *tmp;
|
||||
LIST_HEAD(reqs);
|
||||
struct nfs_commit_info cinfo;
|
||||
LIST_HEAD(failed);
|
||||
|
||||
nfs_init_cinfo_from_dreq(&cinfo, dreq);
|
||||
nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
|
||||
|
||||
nfs_direct_join_group(&reqs, &cinfo, dreq->inode);
|
||||
nfs_direct_join_group(&reqs, dreq->inode);
|
||||
|
||||
dreq->count = 0;
|
||||
dreq->max_count = 0;
|
||||
list_for_each_entry(req, &reqs, wb_list)
|
||||
dreq->max_count += req->wb_bytes;
|
||||
nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
|
||||
get_dreq(dreq);
|
||||
|
||||
@@ -558,40 +551,27 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||
&nfs_direct_write_completion_ops);
|
||||
desc.pg_dreq = dreq;
|
||||
|
||||
while (!list_empty(&reqs)) {
|
||||
req = nfs_list_entry(reqs.next);
|
||||
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
|
||||
/* Bump the transmission count */
|
||||
req->wb_nio++;
|
||||
if (!nfs_pageio_add_request(&desc, req)) {
|
||||
spin_lock(&dreq->lock);
|
||||
if (dreq->error < 0) {
|
||||
desc.pg_error = dreq->error;
|
||||
} else if (desc.pg_error != -EAGAIN) {
|
||||
dreq->flags = 0;
|
||||
if (!desc.pg_error)
|
||||
desc.pg_error = -EIO;
|
||||
nfs_list_move_request(req, &failed);
|
||||
spin_lock(&cinfo.inode->i_lock);
|
||||
dreq->flags = 0;
|
||||
if (desc.pg_error < 0)
|
||||
dreq->error = desc.pg_error;
|
||||
} else
|
||||
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
|
||||
spin_unlock(&dreq->lock);
|
||||
break;
|
||||
else
|
||||
dreq->error = -EIO;
|
||||
spin_unlock(&cinfo.inode->i_lock);
|
||||
}
|
||||
nfs_release_request(req);
|
||||
}
|
||||
nfs_pageio_complete(&desc);
|
||||
|
||||
while (!list_empty(&reqs)) {
|
||||
req = nfs_list_entry(reqs.next);
|
||||
while (!list_empty(&failed)) {
|
||||
req = nfs_list_entry(failed.next);
|
||||
nfs_list_remove_request(req);
|
||||
nfs_unlock_and_release_request(req);
|
||||
if (desc.pg_error == -EAGAIN) {
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
} else {
|
||||
spin_lock(&dreq->lock);
|
||||
nfs_direct_truncate_request(dreq, req);
|
||||
spin_unlock(&dreq->lock);
|
||||
nfs_release_request(req);
|
||||
}
|
||||
}
|
||||
|
||||
if (put_dreq(dreq))
|
||||
@@ -611,6 +591,8 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
|
||||
if (status < 0) {
|
||||
/* Errors in commit are fatal */
|
||||
dreq->error = status;
|
||||
dreq->max_count = 0;
|
||||
dreq->count = 0;
|
||||
dreq->flags = NFS_ODIRECT_DONE;
|
||||
} else {
|
||||
status = dreq->error;
|
||||
@@ -621,12 +603,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
|
||||
while (!list_empty(&data->pages)) {
|
||||
req = nfs_list_entry(data->pages.next);
|
||||
nfs_list_remove_request(req);
|
||||
if (status < 0) {
|
||||
spin_lock(&dreq->lock);
|
||||
nfs_direct_truncate_request(dreq, req);
|
||||
spin_unlock(&dreq->lock);
|
||||
nfs_release_request(req);
|
||||
} else if (!nfs_write_match_verf(verf, req)) {
|
||||
if (status >= 0 && !nfs_write_match_verf(verf, req)) {
|
||||
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
|
||||
/*
|
||||
* Despite the reboot, the write was successful,
|
||||
@@ -634,7 +611,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
|
||||
*/
|
||||
req->wb_nio = 0;
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
} else
|
||||
} else /* Error or match */
|
||||
nfs_release_request(req);
|
||||
nfs_unlock_and_release_request(req);
|
||||
}
|
||||
@@ -687,7 +664,6 @@ static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq)
|
||||
while (!list_empty(&reqs)) {
|
||||
req = nfs_list_entry(reqs.next);
|
||||
nfs_list_remove_request(req);
|
||||
nfs_direct_truncate_request(dreq, req);
|
||||
nfs_release_request(req);
|
||||
nfs_unlock_and_release_request(req);
|
||||
}
|
||||
@@ -737,8 +713,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
||||
}
|
||||
|
||||
nfs_direct_count_bytes(dreq, hdr);
|
||||
if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags) &&
|
||||
!test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
|
||||
if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) {
|
||||
if (!dreq->flags)
|
||||
dreq->flags = NFS_ODIRECT_DO_COMMIT;
|
||||
flags = dreq->flags;
|
||||
@@ -782,23 +757,18 @@ static void nfs_write_sync_pgio_error(struct list_head *head, int error)
|
||||
static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr)
|
||||
{
|
||||
struct nfs_direct_req *dreq = hdr->dreq;
|
||||
struct nfs_page *req;
|
||||
struct nfs_commit_info cinfo;
|
||||
|
||||
trace_nfs_direct_write_reschedule_io(dreq);
|
||||
|
||||
nfs_init_cinfo_from_dreq(&cinfo, dreq);
|
||||
spin_lock(&dreq->lock);
|
||||
if (dreq->error == 0)
|
||||
if (dreq->error == 0) {
|
||||
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
|
||||
set_bit(NFS_IOHDR_REDO, &hdr->flags);
|
||||
spin_unlock(&dreq->lock);
|
||||
while (!list_empty(&hdr->pages)) {
|
||||
req = nfs_list_entry(hdr->pages.next);
|
||||
nfs_list_remove_request(req);
|
||||
nfs_unlock_request(req);
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
/* fake unstable write to let common nfs resend pages */
|
||||
hdr->verf.committed = NFS_UNSTABLE;
|
||||
hdr->good_bytes = hdr->args.offset + hdr->args.count -
|
||||
hdr->io_start;
|
||||
}
|
||||
spin_unlock(&dreq->lock);
|
||||
}
|
||||
|
||||
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
|
||||
@@ -826,11 +796,9 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
|
||||
{
|
||||
struct nfs_pageio_descriptor desc;
|
||||
struct inode *inode = dreq->inode;
|
||||
struct nfs_commit_info cinfo;
|
||||
ssize_t result = 0;
|
||||
size_t requested_bytes = 0;
|
||||
size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE);
|
||||
bool defer = false;
|
||||
|
||||
trace_nfs_direct_write_schedule_iovec(dreq);
|
||||
|
||||
@@ -871,39 +839,19 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
|
||||
break;
|
||||
}
|
||||
|
||||
nfs_lock_request(req);
|
||||
req->wb_index = pos >> PAGE_SHIFT;
|
||||
req->wb_offset = pos & ~PAGE_MASK;
|
||||
if (!nfs_pageio_add_request(&desc, req)) {
|
||||
result = desc.pg_error;
|
||||
nfs_unlock_and_release_request(req);
|
||||
break;
|
||||
}
|
||||
pgbase = 0;
|
||||
bytes -= req_len;
|
||||
requested_bytes += req_len;
|
||||
pos += req_len;
|
||||
dreq->bytes_left -= req_len;
|
||||
|
||||
if (defer) {
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
nfs_lock_request(req);
|
||||
req->wb_index = pos >> PAGE_SHIFT;
|
||||
req->wb_offset = pos & ~PAGE_MASK;
|
||||
if (nfs_pageio_add_request(&desc, req))
|
||||
continue;
|
||||
|
||||
/* Exit on hard errors */
|
||||
if (desc.pg_error < 0 && desc.pg_error != -EAGAIN) {
|
||||
result = desc.pg_error;
|
||||
nfs_unlock_and_release_request(req);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the error is soft, defer remaining requests */
|
||||
nfs_init_cinfo_from_dreq(&cinfo, dreq);
|
||||
spin_lock(&dreq->lock);
|
||||
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
|
||||
spin_unlock(&dreq->lock);
|
||||
nfs_unlock_request(req);
|
||||
nfs_mark_request_commit(req, NULL, &cinfo, 0);
|
||||
desc.pg_error = 0;
|
||||
defer = true;
|
||||
}
|
||||
nfs_direct_release_pages(pagevec, npages);
|
||||
kvfree(pagevec);
|
||||
|
||||
@@ -58,8 +58,7 @@ static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops;
|
||||
static const struct nfs_commit_completion_ops nfs_commit_completion_ops;
|
||||
static const struct nfs_rw_ops nfs_rw_write_ops;
|
||||
static void nfs_inode_remove_request(struct nfs_page *req);
|
||||
static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
|
||||
struct nfs_page *req);
|
||||
static void nfs_clear_request_commit(struct nfs_page *req);
|
||||
static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo,
|
||||
struct inode *inode);
|
||||
static struct nfs_page *
|
||||
@@ -503,8 +502,8 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
|
||||
* the (former) group. All subrequests are removed from any write or commit
|
||||
* lists, unlinked from the group and destroyed.
|
||||
*/
|
||||
void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
|
||||
struct inode *inode)
|
||||
void
|
||||
nfs_join_page_group(struct nfs_page *head, struct inode *inode)
|
||||
{
|
||||
struct nfs_page *subreq;
|
||||
struct nfs_page *destroy_list = NULL;
|
||||
@@ -534,7 +533,7 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
|
||||
* Commit list removal accounting is done after locks are dropped */
|
||||
subreq = head;
|
||||
do {
|
||||
nfs_clear_request_commit(cinfo, subreq);
|
||||
nfs_clear_request_commit(subreq);
|
||||
subreq = subreq->wb_this_page;
|
||||
} while (subreq != head);
|
||||
|
||||
@@ -568,10 +567,8 @@ nfs_lock_and_join_requests(struct page *page)
|
||||
{
|
||||
struct inode *inode = page_file_mapping(page)->host;
|
||||
struct nfs_page *head;
|
||||
struct nfs_commit_info cinfo;
|
||||
int ret;
|
||||
|
||||
nfs_init_cinfo_from_inode(&cinfo, inode);
|
||||
/*
|
||||
* A reference is taken only on the head request which acts as a
|
||||
* reference to the whole page group - the group will not be destroyed
|
||||
@@ -588,7 +585,7 @@ nfs_lock_and_join_requests(struct page *page)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
nfs_join_page_group(head, &cinfo, inode);
|
||||
nfs_join_page_group(head, inode);
|
||||
|
||||
return head;
|
||||
}
|
||||
@@ -959,16 +956,18 @@ nfs_clear_page_commit(struct page *page)
|
||||
}
|
||||
|
||||
/* Called holding the request lock on @req */
|
||||
static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
|
||||
struct nfs_page *req)
|
||||
static void
|
||||
nfs_clear_request_commit(struct nfs_page *req)
|
||||
{
|
||||
if (test_bit(PG_CLEAN, &req->wb_flags)) {
|
||||
struct nfs_open_context *ctx = nfs_req_openctx(req);
|
||||
struct inode *inode = d_inode(ctx->dentry);
|
||||
struct nfs_commit_info cinfo;
|
||||
|
||||
nfs_init_cinfo_from_inode(&cinfo, inode);
|
||||
mutex_lock(&NFS_I(inode)->commit_mutex);
|
||||
if (!pnfs_clear_request_commit(req, cinfo)) {
|
||||
nfs_request_remove_commit_list(req, cinfo);
|
||||
if (!pnfs_clear_request_commit(req, &cinfo)) {
|
||||
nfs_request_remove_commit_list(req, &cinfo);
|
||||
}
|
||||
mutex_unlock(&NFS_I(inode)->commit_mutex);
|
||||
nfs_clear_page_commit(req->wb_page);
|
||||
|
||||
@@ -512,6 +512,7 @@ struct fb_info {
|
||||
} *apertures;
|
||||
|
||||
bool skip_vt_switch; /* no VT switch on suspend/resume required */
|
||||
bool custom_fb_num; /* Use value in node as the preferred node number */
|
||||
};
|
||||
|
||||
static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
|
||||
@@ -614,6 +615,7 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
|
||||
size_t count, loff_t *ppos);
|
||||
|
||||
/* drivers/video/fbmem.c */
|
||||
extern void fb_set_lowest_dynamic_fb(int min_fb_dev);
|
||||
extern int register_framebuffer(struct fb_info *fb_info);
|
||||
extern void unregister_framebuffer(struct fb_info *fb_info);
|
||||
extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
|
||||
|
||||
@@ -145,9 +145,7 @@ extern void nfs_unlock_request(struct nfs_page *req);
|
||||
extern void nfs_unlock_and_release_request(struct nfs_page *);
|
||||
extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req);
|
||||
extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
|
||||
extern void nfs_join_page_group(struct nfs_page *head,
|
||||
struct nfs_commit_info *cinfo,
|
||||
struct inode *inode);
|
||||
extern void nfs_join_page_group(struct nfs_page *head, struct inode *inode);
|
||||
extern int nfs_page_group_lock(struct nfs_page *);
|
||||
extern void nfs_page_group_unlock(struct nfs_page *);
|
||||
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
|
||||
|
||||
@@ -93,7 +93,7 @@ static int __init test_pages(int *total_failures)
|
||||
int failures = 0, num_tests = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= MAX_ORDER; i++)
|
||||
for (i = 0; i < MAX_ORDER; i++)
|
||||
num_tests += do_alloc_pages_order(i, &failures);
|
||||
|
||||
REPORT_FAILURES_IN_FN();
|
||||
|
||||
Reference in New Issue
Block a user