Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Small conflict around locking in rxrpc_process_event() -
channel_lock moved to bundle in next, while state lock
needs _bh() from net.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2020-10-08 15:44:50 -07:00
commit 9d49aea13f
74 changed files with 1943 additions and 565 deletions

View file

@ -1460,6 +1460,11 @@ S: Odd Fixes
F: drivers/amba/ F: drivers/amba/
F: include/linux/amba/bus.h F: include/linux/amba/bus.h
ARM PRIMECELL CLCD PL110 DRIVER
M: Russell King <linux@armlinux.org.uk>
S: Odd Fixes
F: drivers/video/fbdev/amba-clcd.*
ARM PRIMECELL KMI PL050 DRIVER ARM PRIMECELL KMI PL050 DRIVER
M: Russell King <linux@armlinux.org.uk> M: Russell King <linux@armlinux.org.uk>
S: Odd Fixes S: Odd Fixes

View file

@ -150,7 +150,7 @@ static int xen_starting_cpu(unsigned int cpu)
pr_info("Xen: initializing cpu%d\n", cpu); pr_info("Xen: initializing cpu%d\n", cpu);
vcpup = per_cpu_ptr(xen_vcpu_info, cpu); vcpup = per_cpu_ptr(xen_vcpu_info, cpu);
info.mfn = virt_to_gfn(vcpup); info.mfn = percpu_to_gfn(vcpup);
info.offset = xen_offset_in_page(vcpup); info.offset = xen_offset_in_page(vcpup);
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu), err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu),

View file

@ -788,7 +788,7 @@ SYM_FUNC_START_LOCAL(__xts_crypt8)
0: mov bskey, x21 0: mov bskey, x21
mov rounds, x22 mov rounds, x22
br x7 br x16
SYM_FUNC_END(__xts_crypt8) SYM_FUNC_END(__xts_crypt8)
.macro __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7 .macro __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7
@ -806,7 +806,7 @@ SYM_FUNC_END(__xts_crypt8)
uzp1 v30.4s, v30.4s, v25.4s uzp1 v30.4s, v30.4s, v25.4s
ld1 {v25.16b}, [x24] ld1 {v25.16b}, [x24]
99: adr x7, \do8 99: adr x16, \do8
bl __xts_crypt8 bl __xts_crypt8
ldp q16, q17, [sp, #.Lframe_local_offset] ldp q16, q17, [sp, #.Lframe_local_offset]

View file

@ -176,6 +176,8 @@ void
nouveau_mem_del(struct ttm_mem_reg *reg) nouveau_mem_del(struct ttm_mem_reg *reg)
{ {
struct nouveau_mem *mem = nouveau_mem(reg); struct nouveau_mem *mem = nouveau_mem(reg);
if (!mem)
return;
nouveau_mem_fini(mem); nouveau_mem_fini(mem);
kfree(reg->mm_node); kfree(reg->mm_node);
reg->mm_node = NULL; reg->mm_node = NULL;

View file

@ -3149,6 +3149,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
case 0x168: device->chip = &nv168_chipset; break; case 0x168: device->chip = &nv168_chipset; break;
default: default:
nvdev_error(device, "unknown chipset (%08x)\n", boot0); nvdev_error(device, "unknown chipset (%08x)\n", boot0);
ret = -ENODEV;
goto done; goto done;
} }

View file

@ -998,6 +998,8 @@ static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
*/ */
static u16 vsc9959_wm_enc(u16 value) static u16 vsc9959_wm_enc(u16 value)
{ {
WARN_ON(value >= 16 * BIT(8));
if (value >= BIT(8)) if (value >= BIT(8))
return BIT(8) | (value / 16); return BIT(8) | (value / 16);

View file

@ -1049,6 +1049,8 @@ static int vsc9953_prevalidate_phy_mode(struct ocelot *ocelot, int port,
*/ */
static u16 vsc9953_wm_enc(u16 value) static u16 vsc9953_wm_enc(u16 value)
{ {
WARN_ON(value >= 16 * BIT(9));
if (value >= BIT(9)) if (value >= BIT(9))
return BIT(9) | (value / 16); return BIT(9) | (value / 16);

View file

@ -1270,7 +1270,7 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
struct ocelot_port *ocelot_port = ocelot->ports[port]; struct ocelot_port *ocelot_port = ocelot->ports[port];
int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN; int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
int pause_start, pause_stop; int pause_start, pause_stop;
int atop_wm; int atop, atop_tot;
if (port == ocelot->npi) { if (port == ocelot->npi) {
maxlen += OCELOT_TAG_LEN; maxlen += OCELOT_TAG_LEN;
@ -1291,12 +1291,12 @@ void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_STOP, ocelot_fields_write(ocelot, port, SYS_PAUSE_CFG_PAUSE_STOP,
pause_stop); pause_stop);
/* Tail dropping watermark */ /* Tail dropping watermarks */
atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) / atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) /
OCELOT_BUFFER_CELL_SZ; OCELOT_BUFFER_CELL_SZ;
ocelot_write_rix(ocelot, ocelot->ops->wm_enc(9 * maxlen), atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
SYS_ATOP, port); ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
ocelot_write(ocelot, ocelot->ops->wm_enc(atop_wm), SYS_ATOP_TOT_CFG); ocelot_write(ocelot, ocelot->ops->wm_enc(atop_tot), SYS_ATOP_TOT_CFG);
} }
EXPORT_SYMBOL(ocelot_port_set_maxlen); EXPORT_SYMBOL(ocelot_port_set_maxlen);

View file

@ -754,6 +754,8 @@ static int ocelot_reset(struct ocelot *ocelot)
*/ */
static u16 ocelot_wm_enc(u16 value) static u16 ocelot_wm_enc(u16 value)
{ {
WARN_ON(value >= 16 * BIT(8));
if (value >= BIT(8)) if (value >= BIT(8))
return BIT(8) | (value / 16); return BIT(8) | (value / 16);

View file

@ -2055,11 +2055,18 @@ static void rtl_release_firmware(struct rtl8169_private *tp)
void r8169_apply_firmware(struct rtl8169_private *tp) void r8169_apply_firmware(struct rtl8169_private *tp)
{ {
int val;
/* TODO: release firmware if rtl_fw_write_firmware signals failure. */ /* TODO: release firmware if rtl_fw_write_firmware signals failure. */
if (tp->rtl_fw) { if (tp->rtl_fw) {
rtl_fw_write_firmware(tp, tp->rtl_fw); rtl_fw_write_firmware(tp, tp->rtl_fw);
/* At least one firmware doesn't reset tp->ocp_base. */ /* At least one firmware doesn't reset tp->ocp_base. */
tp->ocp_base = OCP_STD_PHY_BASE; tp->ocp_base = OCP_STD_PHY_BASE;
/* PHY soft reset may still be in progress */
phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
!(val & BMCR_RESET),
50000, 600000, true);
} }
} }

View file

@ -1077,6 +1077,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
struct macsec_rx_sa *rx_sa; struct macsec_rx_sa *rx_sa;
struct macsec_rxh_data *rxd; struct macsec_rxh_data *rxd;
struct macsec_dev *macsec; struct macsec_dev *macsec;
unsigned int len;
sci_t sci; sci_t sci;
u32 hdr_pn; u32 hdr_pn;
bool cbit; bool cbit;
@ -1232,9 +1233,10 @@ deliver:
macsec_rxsc_put(rx_sc); macsec_rxsc_put(rx_sc);
skb_orphan(skb); skb_orphan(skb);
len = skb->len;
ret = gro_cells_receive(&macsec->gro_cells, skb); ret = gro_cells_receive(&macsec->gro_cells, skb);
if (ret == NET_RX_SUCCESS) if (ret == NET_RX_SUCCESS)
count_rx(dev, skb->len); count_rx(dev, len);
else else
macsec->secy.netdev->stats.rx_dropped++; macsec->secy.netdev->stats.rx_dropped++;

View file

@ -1375,6 +1375,7 @@ static const struct usb_device_id products[] = {
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */ {QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */
{QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/ {QMI_FIXED_INTF(0x0489, 0xe0b5, 0)}, /* Foxconn T77W968 LTE with eSIM support*/
{QMI_FIXED_INTF(0x2692, 0x9025, 4)}, /* Cellient MPL200 (rebranded Qualcomm 05c6:9025) */
/* 4. Gobi 1000 devices */ /* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */

View file

@ -274,12 +274,20 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
return 1; return 1;
} }
static inline void set_ethernet_addr(rtl8150_t * dev) static void set_ethernet_addr(rtl8150_t *dev)
{ {
u8 node_id[6]; u8 node_id[ETH_ALEN];
int ret;
get_registers(dev, IDR, sizeof(node_id), node_id); ret = get_registers(dev, IDR, sizeof(node_id), node_id);
memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
if (ret == sizeof(node_id)) {
ether_addr_copy(dev->netdev->dev_addr, node_id);
} else {
eth_hw_addr_random(dev->netdev);
netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
dev->netdev->dev_addr);
}
} }
static int rtl8150_set_mac_address(struct net_device *netdev, void *p) static int rtl8150_set_mac_address(struct net_device *netdev, void *p)

View file

@ -115,6 +115,10 @@ static struct quirk_entry quirk_asus_vendor_backlight = {
.wmi_backlight_set_devstate = true, .wmi_backlight_set_devstate = true,
}; };
static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
.use_kbd_dock_devid = true,
};
static int dmi_matched(const struct dmi_system_id *dmi) static int dmi_matched(const struct dmi_system_id *dmi)
{ {
pr_info("Identified laptop model '%s'\n", dmi->ident); pr_info("Identified laptop model '%s'\n", dmi->ident);
@ -488,6 +492,34 @@ static const struct dmi_system_id asus_quirks[] = {
}, },
.driver_data = &quirk_asus_vendor_backlight, .driver_data = &quirk_asus_vendor_backlight,
}, },
{
.callback = dmi_matched,
.ident = "Asus Transformer T100TA / T100HA / T100CHI",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
/* Match *T100* */
DMI_MATCH(DMI_PRODUCT_NAME, "T100"),
},
.driver_data = &quirk_asus_use_kbd_dock_devid,
},
{
.callback = dmi_matched,
.ident = "Asus Transformer T101HA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T101HA"),
},
.driver_data = &quirk_asus_use_kbd_dock_devid,
},
{
.callback = dmi_matched,
.ident = "Asus Transformer T200TA",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
},
.driver_data = &quirk_asus_use_kbd_dock_devid,
},
{}, {},
}; };

View file

@ -365,12 +365,14 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
if (err) if (err)
goto err_free_dev; goto err_free_dev;
result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK); if (asus->driver->quirks->use_kbd_dock_devid) {
if (result >= 0) { result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE); if (result >= 0) {
input_report_switch(asus->inputdev, SW_TABLET_MODE, !result); input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
} else if (result != -ENODEV) { input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
pr_err("Error checking for keyboard-dock: %d\n", result); } else if (result != -ENODEV) {
pr_err("Error checking for keyboard-dock: %d\n", result);
}
} }
err = input_register_device(asus->inputdev); err = input_register_device(asus->inputdev);
@ -2115,7 +2117,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
return; return;
} }
if (code == NOTIFY_KBD_DOCK_CHANGE) { if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
result = asus_wmi_get_devstate_simple(asus, result = asus_wmi_get_devstate_simple(asus,
ASUS_WMI_DEVID_KBD_DOCK); ASUS_WMI_DEVID_KBD_DOCK);
if (result >= 0) { if (result >= 0) {

View file

@ -33,6 +33,7 @@ struct quirk_entry {
bool wmi_backlight_native; bool wmi_backlight_native;
bool wmi_backlight_set_devstate; bool wmi_backlight_set_devstate;
bool wmi_force_als_set; bool wmi_force_als_set;
bool use_kbd_dock_devid;
int wapf; int wapf;
/* /*
* For machines with AMD graphic chips, it will send out WMI event * For machines with AMD graphic chips, it will send out WMI event

View file

@ -30,9 +30,7 @@ config IFCVF
be called ifcvf. be called ifcvf.
config MLX5_VDPA config MLX5_VDPA
bool "MLX5 VDPA support library for ConnectX devices" bool
depends on MLX5_CORE
default n
help help
Support library for Mellanox VDPA drivers. Provides code that is Support library for Mellanox VDPA drivers. Provides code that is
common for all types of VDPA drivers. The following drivers are planned: common for all types of VDPA drivers. The following drivers are planned:
@ -40,7 +38,8 @@ config MLX5_VDPA
config MLX5_VDPA_NET config MLX5_VDPA_NET
tristate "vDPA driver for ConnectX devices" tristate "vDPA driver for ConnectX devices"
depends on MLX5_VDPA select MLX5_VDPA
depends on MLX5_CORE
default n default n
help help
VDPA network driver for ConnectX6 and newer. Provides offloading VDPA network driver for ConnectX6 and newer. Provides offloading

View file

@ -1133,15 +1133,17 @@ static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
if (!mvq->initialized) if (!mvq->initialized)
return; return;
if (query_virtqueue(ndev, mvq, &attr)) {
mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n");
return;
}
if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY) if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)
return; return;
if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)) if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n"); mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n");
if (query_virtqueue(ndev, mvq, &attr)) {
mlx5_vdpa_warn(&ndev->mvdev, "failed to query virtqueue\n");
return;
}
mvq->avail_idx = attr.available_index;
} }
static void suspend_vqs(struct mlx5_vdpa_net *ndev) static void suspend_vqs(struct mlx5_vdpa_net *ndev)
@ -1411,8 +1413,14 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa
struct mlx5_virtq_attr attr; struct mlx5_virtq_attr attr;
int err; int err;
if (!mvq->initialized) /* If the virtq object was destroyed, use the value saved at
return -EAGAIN; * the last minute of suspend_vq. This caters for userspace
* that cares about emulating the index after vq is stopped.
*/
if (!mvq->initialized) {
state->avail_index = mvq->avail_idx;
return 0;
}
err = query_virtqueue(ndev, mvq, &attr); err = query_virtqueue(ndev, mvq, &attr);
if (err) { if (err) {

View file

@ -565,6 +565,9 @@ static int vhost_vdpa_map(struct vhost_vdpa *v,
perm_to_iommu_flags(perm)); perm_to_iommu_flags(perm));
} }
if (r)
vhost_iotlb_del_range(dev->iotlb, iova, iova + size - 1);
return r; return r;
} }
@ -592,21 +595,19 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
struct vhost_dev *dev = &v->vdev; struct vhost_dev *dev = &v->vdev;
struct vhost_iotlb *iotlb = dev->iotlb; struct vhost_iotlb *iotlb = dev->iotlb;
struct page **page_list; struct page **page_list;
unsigned long list_size = PAGE_SIZE / sizeof(struct page *); struct vm_area_struct **vmas;
unsigned int gup_flags = FOLL_LONGTERM; unsigned int gup_flags = FOLL_LONGTERM;
unsigned long npages, cur_base, map_pfn, last_pfn = 0; unsigned long map_pfn, last_pfn = 0;
unsigned long locked, lock_limit, pinned, i; unsigned long npages, lock_limit;
unsigned long i, nmap = 0;
u64 iova = msg->iova; u64 iova = msg->iova;
long pinned;
int ret = 0; int ret = 0;
if (vhost_iotlb_itree_first(iotlb, msg->iova, if (vhost_iotlb_itree_first(iotlb, msg->iova,
msg->iova + msg->size - 1)) msg->iova + msg->size - 1))
return -EEXIST; return -EEXIST;
page_list = (struct page **) __get_free_page(GFP_KERNEL);
if (!page_list)
return -ENOMEM;
if (msg->perm & VHOST_ACCESS_WO) if (msg->perm & VHOST_ACCESS_WO)
gup_flags |= FOLL_WRITE; gup_flags |= FOLL_WRITE;
@ -614,61 +615,86 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
if (!npages) if (!npages)
return -EINVAL; return -EINVAL;
page_list = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
vmas = kvmalloc_array(npages, sizeof(struct vm_area_struct *),
GFP_KERNEL);
if (!page_list || !vmas) {
ret = -ENOMEM;
goto free;
}
mmap_read_lock(dev->mm); mmap_read_lock(dev->mm);
locked = atomic64_add_return(npages, &dev->mm->pinned_vm);
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) {
if (locked > lock_limit) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto unlock;
} }
cur_base = msg->uaddr & PAGE_MASK; pinned = pin_user_pages(msg->uaddr & PAGE_MASK, npages, gup_flags,
iova &= PAGE_MASK; page_list, vmas);
if (npages != pinned) {
while (npages) { if (pinned < 0) {
pinned = min_t(unsigned long, npages, list_size); ret = pinned;
ret = pin_user_pages(cur_base, pinned, } else {
gup_flags, page_list, NULL); unpin_user_pages(page_list, pinned);
if (ret != pinned) ret = -ENOMEM;
goto out;
if (!last_pfn)
map_pfn = page_to_pfn(page_list[0]);
for (i = 0; i < ret; i++) {
unsigned long this_pfn = page_to_pfn(page_list[i]);
u64 csize;
if (last_pfn && (this_pfn != last_pfn + 1)) {
/* Pin a contiguous chunk of memory */
csize = (last_pfn - map_pfn + 1) << PAGE_SHIFT;
if (vhost_vdpa_map(v, iova, csize,
map_pfn << PAGE_SHIFT,
msg->perm))
goto out;
map_pfn = this_pfn;
iova += csize;
}
last_pfn = this_pfn;
} }
goto unlock;
cur_base += ret << PAGE_SHIFT;
npages -= ret;
} }
/* Pin the rest chunk */ iova &= PAGE_MASK;
ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT, map_pfn = page_to_pfn(page_list[0]);
map_pfn << PAGE_SHIFT, msg->perm);
/* One more iteration to avoid extra vdpa_map() call out of loop. */
for (i = 0; i <= npages; i++) {
unsigned long this_pfn;
u64 csize;
/* The last chunk may have no valid PFN next to it */
this_pfn = i < npages ? page_to_pfn(page_list[i]) : -1UL;
if (last_pfn && (this_pfn == -1UL ||
this_pfn != last_pfn + 1)) {
/* Pin a contiguous chunk of memory */
csize = last_pfn - map_pfn + 1;
ret = vhost_vdpa_map(v, iova, csize << PAGE_SHIFT,
map_pfn << PAGE_SHIFT,
msg->perm);
if (ret) {
/*
* Unpin the rest chunks of memory on the
* flight with no corresponding vdpa_map()
* calls having been made yet. On the other
* hand, vdpa_unmap() in the failure path
* is in charge of accounting the number of
* pinned pages for its own.
* This asymmetrical pattern of accounting
* is for efficiency to pin all pages at
* once, while there is no other callsite
* of vdpa_map() than here above.
*/
unpin_user_pages(&page_list[nmap],
npages - nmap);
goto out;
}
atomic64_add(csize, &dev->mm->pinned_vm);
nmap += csize;
iova += csize << PAGE_SHIFT;
map_pfn = this_pfn;
}
last_pfn = this_pfn;
}
WARN_ON(nmap != npages);
out: out:
if (ret) { if (ret)
vhost_vdpa_unmap(v, msg->iova, msg->size); vhost_vdpa_unmap(v, msg->iova, msg->size);
atomic64_sub(npages, &dev->mm->pinned_vm); unlock:
}
mmap_read_unlock(dev->mm); mmap_read_unlock(dev->mm);
free_page((unsigned long)page_list); free:
kvfree(vmas);
kvfree(page_list);
return ret; return ret;
} }
@ -810,6 +836,7 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
err_init_iotlb: err_init_iotlb:
vhost_dev_cleanup(&v->vdev); vhost_dev_cleanup(&v->vdev);
kfree(vqs);
err: err:
atomic_dec(&v->opened); atomic_dec(&v->opened);
return r; return r;

View file

@ -1290,6 +1290,11 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
vring_used_t __user *used) vring_used_t __user *used)
{ {
/* If an IOTLB device is present, the vring addresses are
* GIOVAs. Access validation occurs at prefetch time. */
if (vq->iotlb)
return true;
return access_ok(desc, vhost_get_desc_size(vq, num)) && return access_ok(desc, vhost_get_desc_size(vq, num)) &&
access_ok(avail, vhost_get_avail_size(vq, num)) && access_ok(avail, vhost_get_avail_size(vq, num)) &&
access_ok(used, vhost_get_used_size(vq, num)); access_ok(used, vhost_get_used_size(vq, num));
@ -1365,6 +1370,20 @@ bool vhost_log_access_ok(struct vhost_dev *dev)
} }
EXPORT_SYMBOL_GPL(vhost_log_access_ok); EXPORT_SYMBOL_GPL(vhost_log_access_ok);
static bool vq_log_used_access_ok(struct vhost_virtqueue *vq,
void __user *log_base,
bool log_used,
u64 log_addr)
{
/* If an IOTLB device is present, log_addr is a GIOVA that
* will never be logged by log_used(). */
if (vq->iotlb)
return true;
return !log_used || log_access_ok(log_base, log_addr,
vhost_get_used_size(vq, vq->num));
}
/* Verify access for write logging. */ /* Verify access for write logging. */
/* Caller should have vq mutex and device mutex */ /* Caller should have vq mutex and device mutex */
static bool vq_log_access_ok(struct vhost_virtqueue *vq, static bool vq_log_access_ok(struct vhost_virtqueue *vq,
@ -1372,8 +1391,7 @@ static bool vq_log_access_ok(struct vhost_virtqueue *vq,
{ {
return vq_memory_access_ok(log_base, vq->umem, return vq_memory_access_ok(log_base, vq->umem,
vhost_has_feature(vq, VHOST_F_LOG_ALL)) && vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
(!vq->log_used || log_access_ok(log_base, vq->log_addr, vq_log_used_access_ok(vq, log_base, vq->log_used, vq->log_addr);
vhost_get_used_size(vq, vq->num)));
} }
/* Can we start vq? */ /* Can we start vq? */
@ -1383,10 +1401,6 @@ bool vhost_vq_access_ok(struct vhost_virtqueue *vq)
if (!vq_log_access_ok(vq, vq->log_base)) if (!vq_log_access_ok(vq, vq->log_base))
return false; return false;
/* Access validation occurs at prefetch time with IOTLB */
if (vq->iotlb)
return true;
return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
} }
EXPORT_SYMBOL_GPL(vhost_vq_access_ok); EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
@ -1516,10 +1530,9 @@ static long vhost_vring_set_addr(struct vhost_dev *d,
return -EINVAL; return -EINVAL;
/* Also validate log access for used ring if enabled. */ /* Also validate log access for used ring if enabled. */
if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) && if (!vq_log_used_access_ok(vq, vq->log_base,
!log_access_ok(vq->log_base, a.log_guest_addr, a.flags & (0x1 << VHOST_VRING_F_LOG),
sizeof *vq->used + a.log_guest_addr))
vq->num * sizeof *vq->used->ring))
return -EINVAL; return -EINVAL;
} }

View file

@ -35,12 +35,6 @@
#define FONT_DATA ((unsigned char *)font_vga_8x16.data) #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
/* borrowed from fbcon.c */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
#define FONT_EXTRA_WORDS 3
static unsigned char *font_data[MAX_NR_CONSOLES]; static unsigned char *font_data[MAX_NR_CONSOLES];
static struct newport_regs *npregs; static struct newport_regs *npregs;
@ -522,6 +516,7 @@ static int newport_set_font(int unit, struct console_font *op)
FNTSIZE(new_data) = size; FNTSIZE(new_data) = size;
FNTCHARCNT(new_data) = op->charcount; FNTCHARCNT(new_data) = op->charcount;
REFCOUNT(new_data) = 0; /* usage counter */ REFCOUNT(new_data) = 0; /* usage counter */
FNTSUM(new_data) = 0;
p = new_data; p = new_data;
for (i = 0; i < op->charcount; i++) { for (i = 0; i < op->charcount; i++) {

View file

@ -272,6 +272,26 @@ config FB_PM2_FIFO_DISCONNECT
help help
Support the Permedia2 FIFO disconnect feature. Support the Permedia2 FIFO disconnect feature.
config FB_ARMCLCD
tristate "ARM PrimeCell PL110 support"
depends on ARM || ARM64 || COMPILE_TEST
depends on FB && ARM_AMBA && HAS_IOMEM
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select FB_MODE_HELPERS if OF
select VIDEOMODE_HELPERS if OF
select BACKLIGHT_CLASS_DEVICE if OF
help
This framebuffer device driver is for the ARM PrimeCell PL110
Colour LCD controller. ARM PrimeCells provide the building
blocks for System on a Chip devices.
If you want to compile this as a module (=code which can be
inserted into and removed from the running kernel), say M
here and read <file:Documentation/kbuild/modules.rst>. The module
will be called amba-clcd.
config FB_ACORN config FB_ACORN
bool "Acorn VIDC support" bool "Acorn VIDC support"
depends on (FB = y) && ARM && ARCH_ACORN depends on (FB = y) && ARM && ARCH_ACORN

View file

@ -75,6 +75,7 @@ obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
obj-$(CONFIG_FB_68328) += 68328fb.o obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_GBE) += gbefb.o obj-$(CONFIG_FB_GBE) += gbefb.o

View file

@ -0,0 +1,986 @@
/*
* linux/drivers/video/amba-clcd.c
*
* Copyright (C) 2001 ARM Limited, by David A Rusling
* Updated to 2.5, Deep Blue Solutions Ltd.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
* ARM PrimeCell PL110 Color LCD Controller
*/
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/backlight.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <video/display_timing.h>
#include <video/of_display_timing.h>
#include <video/videomode.h>
#define to_clcd(info) container_of(info, struct clcd_fb, fb)
/* This is limited to 16 characters when displayed by X startup */
static const char *clcd_name = "CLCD FB";
/*
* Unfortunately, the enable/disable functions may be called either from
* process or IRQ context, and we _need_ to delay. This is _not_ good.
*/
static inline void clcdfb_sleep(unsigned int ms)
{
if (in_atomic()) {
mdelay(ms);
} else {
msleep(ms);
}
}
static inline void clcdfb_set_start(struct clcd_fb *fb)
{
unsigned long ustart = fb->fb.fix.smem_start;
unsigned long lstart;
ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
writel(ustart, fb->regs + CLCD_UBAS);
writel(lstart, fb->regs + CLCD_LBAS);
}
static void clcdfb_disable(struct clcd_fb *fb)
{
u32 val;
if (fb->board->disable)
fb->board->disable(fb);
if (fb->panel->backlight) {
fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
backlight_update_status(fb->panel->backlight);
}
val = readl(fb->regs + fb->off_cntl);
if (val & CNTL_LCDPWR) {
val &= ~CNTL_LCDPWR;
writel(val, fb->regs + fb->off_cntl);
clcdfb_sleep(20);
}
if (val & CNTL_LCDEN) {
val &= ~CNTL_LCDEN;
writel(val, fb->regs + fb->off_cntl);
}
/*
* Disable CLCD clock source.
*/
if (fb->clk_enabled) {
fb->clk_enabled = false;
clk_disable(fb->clk);
}
}
static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
{
/*
* Enable the CLCD clock source.
*/
if (!fb->clk_enabled) {
fb->clk_enabled = true;
clk_enable(fb->clk);
}
/*
* Bring up by first enabling..
*/
cntl |= CNTL_LCDEN;
writel(cntl, fb->regs + fb->off_cntl);
clcdfb_sleep(20);
/*
* and now apply power.
*/
cntl |= CNTL_LCDPWR;
writel(cntl, fb->regs + fb->off_cntl);
/*
* Turn on backlight
*/
if (fb->panel->backlight) {
fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
backlight_update_status(fb->panel->backlight);
}
/*
* finally, enable the interface.
*/
if (fb->board->enable)
fb->board->enable(fb);
}
static int
clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
{
u32 caps;
int ret = 0;
if (fb->panel->caps && fb->board->caps)
caps = fb->panel->caps & fb->board->caps;
else {
/* Old way of specifying what can be used */
caps = fb->panel->cntl & CNTL_BGR ?
CLCD_CAP_BGR : CLCD_CAP_RGB;
/* But mask out 444 modes as they weren't supported */
caps &= ~CLCD_CAP_444;
}
/* Only TFT panels can do RGB888/BGR888 */
if (!(fb->panel->cntl & CNTL_LCDTFT))
caps &= ~CLCD_CAP_888;
memset(&var->transp, 0, sizeof(var->transp));
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
switch (var->bits_per_pixel) {
case 1:
case 2:
case 4:
case 8:
/* If we can't do 5551, reject */
caps &= CLCD_CAP_5551;
if (!caps) {
ret = -EINVAL;
break;
}
var->red.length = var->bits_per_pixel;
var->red.offset = 0;
var->green.length = var->bits_per_pixel;
var->green.offset = 0;
var->blue.length = var->bits_per_pixel;
var->blue.offset = 0;
break;
case 16:
/* If we can't do 444, 5551 or 565, reject */
if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
ret = -EINVAL;
break;
}
/*
* Green length can be 4, 5 or 6 depending whether
* we're operating in 444, 5551 or 565 mode.
*/
if (var->green.length == 4 && caps & CLCD_CAP_444)
caps &= CLCD_CAP_444;
if (var->green.length == 5 && caps & CLCD_CAP_5551)
caps &= CLCD_CAP_5551;
else if (var->green.length == 6 && caps & CLCD_CAP_565)
caps &= CLCD_CAP_565;
else {
/*
* PL110 officially only supports RGB555,
* but may be wired up to allow RGB565.
*/
if (caps & CLCD_CAP_565) {
var->green.length = 6;
caps &= CLCD_CAP_565;
} else if (caps & CLCD_CAP_5551) {
var->green.length = 5;
caps &= CLCD_CAP_5551;
} else {
var->green.length = 4;
caps &= CLCD_CAP_444;
}
}
if (var->green.length >= 5) {
var->red.length = 5;
var->blue.length = 5;
} else {
var->red.length = 4;
var->blue.length = 4;
}
break;
case 32:
/* If we can't do 888, reject */
caps &= CLCD_CAP_888;
if (!caps) {
ret = -EINVAL;
break;
}
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
break;
default:
ret = -EINVAL;
break;
}
/*
* >= 16bpp displays have separate colour component bitfields
* encoded in the pixel data. Calculate their position from
* the bitfield length defined above.
*/
if (ret == 0 && var->bits_per_pixel >= 16) {
bool bgr, rgb;
bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
if (!bgr && !rgb)
/*
* The requested format was not possible, try just
* our capabilities. One of BGR or RGB must be
* supported.
*/
bgr = caps & CLCD_CAP_BGR;
if (bgr) {
var->blue.offset = 0;
var->green.offset = var->blue.offset + var->blue.length;
var->red.offset = var->green.offset + var->green.length;
} else {
var->red.offset = 0;
var->green.offset = var->red.offset + var->red.length;
var->blue.offset = var->green.offset + var->green.length;
}
}
return ret;
}
static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
int ret = -EINVAL;
if (fb->board->check)
ret = fb->board->check(fb, var);
if (ret == 0 &&
var->xres_virtual * var->bits_per_pixel / 8 *
var->yres_virtual > fb->fb.fix.smem_len)
ret = -EINVAL;
if (ret == 0)
ret = clcdfb_set_bitfields(fb, var);
return ret;
}
static int clcdfb_set_par(struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
struct clcd_regs regs;
fb->fb.fix.line_length = fb->fb.var.xres_virtual *
fb->fb.var.bits_per_pixel / 8;
if (fb->fb.var.bits_per_pixel <= 8)
fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
else
fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
fb->board->decode(fb, &regs);
clcdfb_disable(fb);
writel(regs.tim0, fb->regs + CLCD_TIM0);
writel(regs.tim1, fb->regs + CLCD_TIM1);
writel(regs.tim2, fb->regs + CLCD_TIM2);
writel(regs.tim3, fb->regs + CLCD_TIM3);
clcdfb_set_start(fb);
clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
fb->clcd_cntl = regs.cntl;
clcdfb_enable(fb, regs.cntl);
#ifdef DEBUG
printk(KERN_INFO
"CLCD: Registers set to\n"
" %08x %08x %08x %08x\n"
" %08x %08x %08x %08x\n",
readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
#endif
return 0;
}
static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
{
unsigned int mask = (1 << bf->length) - 1;
return (val >> (16 - bf->length) & mask) << bf->offset;
}
/*
* Set a single color register. The values supplied have a 16 bit
* magnitude. Return != 0 for invalid regno.
*/
static int
clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
unsigned int blue, unsigned int transp, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
if (regno < 16)
fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
convert_bitfield(blue, &fb->fb.var.blue) |
convert_bitfield(green, &fb->fb.var.green) |
convert_bitfield(red, &fb->fb.var.red);
if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
u32 val, mask, newval;
newval = (red >> 11) & 0x001f;
newval |= (green >> 6) & 0x03e0;
newval |= (blue >> 1) & 0x7c00;
/*
* 3.2.11: if we're configured for big endian
* byte order, the palette entries are swapped.
*/
if (fb->clcd_cntl & CNTL_BEBO)
regno ^= 1;
if (regno & 1) {
newval <<= 16;
mask = 0x0000ffff;
} else {
mask = 0xffff0000;
}
val = readl(fb->regs + hw_reg) & mask;
writel(val | newval, fb->regs + hw_reg);
}
return regno > 255;
}
/*
* Blank the screen if blank_mode != 0, else unblank. If blank == NULL
* then the caller blanks by setting the CLUT (Color Look Up Table) to all
* black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
* to e.g. a video mode which doesn't support it. Implements VESA suspend
* and powerdown modes on hardware that supports disabling hsync/vsync:
* blank_mode == 2: suspend vsync
* blank_mode == 3: suspend hsync
* blank_mode == 4: powerdown
*/
static int clcdfb_blank(int blank_mode, struct fb_info *info)
{
struct clcd_fb *fb = to_clcd(info);
if (blank_mode != 0) {
clcdfb_disable(fb);
} else {
clcdfb_enable(fb, fb->clcd_cntl);
}
return 0;
}
static int clcdfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct clcd_fb *fb = to_clcd(info);
unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
int ret = -EINVAL;
len = info->fix.smem_len;
if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
fb->board->mmap)
ret = fb->board->mmap(fb, vma);
return ret;
}
static const struct fb_ops clcdfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = clcdfb_check_var,
.fb_set_par = clcdfb_set_par,
.fb_setcolreg = clcdfb_setcolreg,
.fb_blank = clcdfb_blank,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_mmap = clcdfb_mmap,
};
static int clcdfb_register(struct clcd_fb *fb)
{
int ret;
/*
* ARM PL111 always has IENB at 0x1c; it's only PL110
* which is reversed on some platforms.
*/
if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
fb->off_ienb = CLCD_PL111_IENB;
fb->off_cntl = CLCD_PL111_CNTL;
} else {
fb->off_ienb = CLCD_PL110_IENB;
fb->off_cntl = CLCD_PL110_CNTL;
}
fb->clk = clk_get(&fb->dev->dev, NULL);
if (IS_ERR(fb->clk)) {
ret = PTR_ERR(fb->clk);
goto out;
}
ret = clk_prepare(fb->clk);
if (ret)
goto free_clk;
fb->fb.device = &fb->dev->dev;
fb->fb.fix.mmio_start = fb->dev->res.start;
fb->fb.fix.mmio_len = resource_size(&fb->dev->res);
fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
if (!fb->regs) {
printk(KERN_ERR "CLCD: unable to remap registers\n");
ret = -ENOMEM;
goto clk_unprep;
}
fb->fb.fbops = &clcdfb_ops;
fb->fb.flags = FBINFO_FLAG_DEFAULT;
fb->fb.pseudo_palette = fb->cmap;
strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
fb->fb.fix.type_aux = 0;
fb->fb.fix.xpanstep = 0;
fb->fb.fix.ypanstep = 0;
fb->fb.fix.ywrapstep = 0;
fb->fb.fix.accel = FB_ACCEL_NONE;
fb->fb.var.xres = fb->panel->mode.xres;
fb->fb.var.yres = fb->panel->mode.yres;
fb->fb.var.xres_virtual = fb->panel->mode.xres;
fb->fb.var.yres_virtual = fb->panel->mode.yres;
fb->fb.var.bits_per_pixel = fb->panel->bpp;
fb->fb.var.grayscale = fb->panel->grayscale;
fb->fb.var.pixclock = fb->panel->mode.pixclock;
fb->fb.var.left_margin = fb->panel->mode.left_margin;
fb->fb.var.right_margin = fb->panel->mode.right_margin;
fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
fb->fb.var.sync = fb->panel->mode.sync;
fb->fb.var.vmode = fb->panel->mode.vmode;
fb->fb.var.activate = FB_ACTIVATE_NOW;
fb->fb.var.nonstd = 0;
fb->fb.var.height = fb->panel->height;
fb->fb.var.width = fb->panel->width;
fb->fb.var.accel_flags = 0;
fb->fb.monspecs.hfmin = 0;
fb->fb.monspecs.hfmax = 100000;
fb->fb.monspecs.vfmin = 0;
fb->fb.monspecs.vfmax = 400;
fb->fb.monspecs.dclkmin = 1000000;
fb->fb.monspecs.dclkmax = 100000000;
/*
* Make sure that the bitfields are set appropriately.
*/
clcdfb_set_bitfields(fb, &fb->fb.var);
/*
* Allocate colourmap.
*/
ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
if (ret)
goto unmap;
/*
* Ensure interrupts are disabled.
*/
writel(0, fb->regs + fb->off_ienb);
fb_set_var(&fb->fb, &fb->fb.var);
dev_info(&fb->dev->dev, "%s hardware, %s display\n",
fb->board->name, fb->panel->mode.name);
ret = register_framebuffer(&fb->fb);
if (ret == 0)
goto out;
printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
fb_dealloc_cmap(&fb->fb.cmap);
unmap:
iounmap(fb->regs);
clk_unprep:
clk_unprepare(fb->clk);
free_clk:
clk_put(fb->clk);
out:
return ret;
}
#ifdef CONFIG_OF
static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
struct clcd_panel *clcd_panel)
{
int err;
struct display_timing timing;
struct videomode video;
err = of_get_display_timing(node, "panel-timing", &timing);
if (err) {
pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
return err;
}
videomode_from_timing(&timing, &video);
err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
if (err)
return err;
/* Set up some inversion flags */
if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
clcd_panel->tim2 |= TIM2_IPC;
else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
/*
* To preserve backwards compatibility, the IPC (inverted
* pixel clock) flag needs to be set on any display that
* doesn't explicitly specify that the pixel clock is
* active on the negative or positive edge.
*/
clcd_panel->tim2 |= TIM2_IPC;
if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
clcd_panel->tim2 |= TIM2_IHS;
if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
clcd_panel->tim2 |= TIM2_IVS;
if (timing.flags & DISPLAY_FLAGS_DE_LOW)
clcd_panel->tim2 |= TIM2_IOE;
return 0;
}
static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
{
return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
mode->refresh);
}
static int clcdfb_of_get_backlight(struct device *dev,
struct clcd_panel *clcd_panel)
{
struct backlight_device *backlight;
/* Look up the optional backlight device */
backlight = devm_of_find_backlight(dev);
if (IS_ERR(backlight))
return PTR_ERR(backlight);
clcd_panel->backlight = backlight;
return 0;
}
static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
struct clcd_panel *clcd_panel)
{
int err;
struct fb_videomode *mode;
char *name;
int len;
/* Only directly connected DPI panels supported for now */
if (of_device_is_compatible(panel, "panel-dpi"))
err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
else
err = -ENOENT;
if (err)
return err;
mode = &clcd_panel->mode;
len = clcdfb_snprintf_mode(NULL, 0, mode);
name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
if (!name)
return -ENOMEM;
clcdfb_snprintf_mode(name, len + 1, mode);
mode->name = name;
return 0;
}
static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
{
static struct {
unsigned int part;
u32 r0, g0, b0;
u32 caps;
} panels[] = {
{ 0x110, 1, 7, 13, CLCD_CAP_5551 },
{ 0x110, 0, 8, 16, CLCD_CAP_888 },
{ 0x110, 16, 8, 0, CLCD_CAP_888 },
{ 0x111, 4, 14, 20, CLCD_CAP_444 },
{ 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
{ 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
CLCD_CAP_565 },
{ 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
CLCD_CAP_565 | CLCD_CAP_888 },
};
int i;
/* Bypass pixel clock divider */
fb->panel->tim2 |= TIM2_BCD;
/* TFT display, vert. comp. interrupt at the start of the back porch */
fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
fb->panel->caps = 0;
/* Match the setup with known variants */
for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
if (amba_part(fb->dev) != panels[i].part)
continue;
if (g0 != panels[i].g0)
continue;
if (r0 == panels[i].r0 && b0 == panels[i].b0)
fb->panel->caps = panels[i].caps;
}
/*
* If we actually physically connected the R lines to B and
* vice versa
*/
if (r0 != 0 && b0 == 0)
fb->panel->bgr_connection = true;
return fb->panel->caps ? 0 : -EINVAL;
}
static int clcdfb_of_init_display(struct clcd_fb *fb)
{
struct device_node *endpoint, *panel;
int err;
unsigned int bpp;
u32 max_bandwidth;
u32 tft_r0b0g0[3];
fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
if (!fb->panel)
return -ENOMEM;
/*
* Fetch the panel endpoint.
*/
endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
if (!endpoint)
return -ENODEV;
panel = of_graph_get_remote_port_parent(endpoint);
if (!panel)
return -ENODEV;
err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
if (err)
return err;
err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
if (err)
return err;
err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
&max_bandwidth);
if (!err) {
/*
* max_bandwidth is in bytes per second and pixclock in
* pico-seconds, so the maximum allowed bits per pixel is
* 8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
* Rearrange this calculation to avoid overflow and then ensure
* result is a valid format.
*/
bpp = max_bandwidth / (1000 / 8)
/ PICOS2KHZ(fb->panel->mode.pixclock);
bpp = rounddown_pow_of_two(bpp);
if (bpp > 32)
bpp = 32;
} else
bpp = 32;
fb->panel->bpp = bpp;
#ifdef CONFIG_CPU_BIG_ENDIAN
fb->panel->cntl |= CNTL_BEBO;
#endif
fb->panel->width = -1;
fb->panel->height = -1;
if (of_property_read_u32_array(endpoint,
"arm,pl11x,tft-r0g0b0-pads",
tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
return -ENOENT;
return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
tft_r0b0g0[1], tft_r0b0g0[2]);
}
static int clcdfb_of_vram_setup(struct clcd_fb *fb)
{
int err;
struct device_node *memory;
u64 size;
err = clcdfb_of_init_display(fb);
if (err)
return err;
memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
if (!memory)
return -ENODEV;
fb->fb.screen_base = of_iomap(memory, 0);
if (!fb->fb.screen_base)
return -ENOMEM;
fb->fb.fix.smem_start = of_translate_address(memory,
of_get_address(memory, 0, &size, NULL));
fb->fb.fix.smem_len = size;
return 0;
}
static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
unsigned long off, user_size, kernel_size;
off = vma->vm_pgoff << PAGE_SHIFT;
user_size = vma->vm_end - vma->vm_start;
kernel_size = fb->fb.fix.smem_len;
if (off >= kernel_size || user_size > (kernel_size - off))
return -ENXIO;
return remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
user_size,
pgprot_writecombine(vma->vm_page_prot));
}
static void clcdfb_of_vram_remove(struct clcd_fb *fb)
{
iounmap(fb->fb.screen_base);
}
static int clcdfb_of_dma_setup(struct clcd_fb *fb)
{
unsigned long framesize;
dma_addr_t dma;
int err;
err = clcdfb_of_init_display(fb);
if (err)
return err;
framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
fb->panel->bpp / 8);
fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
&dma, GFP_KERNEL);
if (!fb->fb.screen_base)
return -ENOMEM;
fb->fb.fix.smem_start = dma;
fb->fb.fix.smem_len = framesize;
return 0;
}
static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
{
return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
fb->fb.fix.smem_start, fb->fb.fix.smem_len);
}
static void clcdfb_of_dma_remove(struct clcd_fb *fb)
{
dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
fb->fb.screen_base, fb->fb.fix.smem_start);
}
static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
{
struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
GFP_KERNEL);
struct device_node *node = dev->dev.of_node;
if (!board)
return NULL;
board->name = of_node_full_name(node);
board->caps = CLCD_CAP_ALL;
board->check = clcdfb_check;
board->decode = clcdfb_decode;
if (of_find_property(node, "memory-region", NULL)) {
board->setup = clcdfb_of_vram_setup;
board->mmap = clcdfb_of_vram_mmap;
board->remove = clcdfb_of_vram_remove;
} else {
board->setup = clcdfb_of_dma_setup;
board->mmap = clcdfb_of_dma_mmap;
board->remove = clcdfb_of_dma_remove;
}
return board;
}
#else
static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
{
return NULL;
}
#endif
static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
{
struct clcd_board *board = dev_get_platdata(&dev->dev);
struct clcd_fb *fb;
int ret;
if (!board)
board = clcdfb_of_get_board(dev);
if (!board)
return -EINVAL;
ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
if (ret)
goto out;
ret = amba_request_regions(dev, NULL);
if (ret) {
printk(KERN_ERR "CLCD: unable to reserve regs region\n");
goto out;
}
fb = kzalloc(sizeof(*fb), GFP_KERNEL);
if (!fb) {
ret = -ENOMEM;
goto free_region;
}
fb->dev = dev;
fb->board = board;
dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
amba_part(dev), amba_manf(dev), amba_rev(dev),
(unsigned long long)dev->res.start);
ret = fb->board->setup(fb);
if (ret)
goto free_fb;
ret = clcdfb_register(fb);
if (ret == 0) {
amba_set_drvdata(dev, fb);
goto out;
}
fb->board->remove(fb);
free_fb:
kfree(fb);
free_region:
amba_release_regions(dev);
out:
return ret;
}
static int clcdfb_remove(struct amba_device *dev)
{
struct clcd_fb *fb = amba_get_drvdata(dev);
clcdfb_disable(fb);
unregister_framebuffer(&fb->fb);
if (fb->fb.cmap.len)
fb_dealloc_cmap(&fb->fb.cmap);
iounmap(fb->regs);
clk_unprepare(fb->clk);
clk_put(fb->clk);
fb->board->remove(fb);
kfree(fb);
amba_release_regions(dev);
return 0;
}
static const struct amba_id clcdfb_id_table[] = {
{
.id = 0x00041110,
.mask = 0x000ffffe,
},
{ 0, 0 },
};
MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
static struct amba_driver clcd_driver = {
.drv = {
.name = "clcd-pl11x",
},
.probe = clcdfb_probe,
.remove = clcdfb_remove,
.id_table = clcdfb_id_table,
};
static int __init amba_clcdfb_init(void)
{
if (fb_get_options("ambafb", NULL))
return -ENODEV;
return amba_driver_register(&clcd_driver);
}
module_init(amba_clcdfb_init);
static void __exit amba_clcdfb_exit(void)
{
amba_driver_unregister(&clcd_driver);
}
module_exit(amba_clcdfb_exit);
MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
MODULE_LICENSE("GPL");

View file

@ -2299,6 +2299,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
if (font->width <= 8) { if (font->width <= 8) {
j = vc->vc_font.height; j = vc->vc_font.height;
if (font->charcount * j > FNTSIZE(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) { for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j); memcpy(data, fontdata, j);
memset(data + j, 0, 32 - j); memset(data + j, 0, 32 - j);
@ -2307,6 +2310,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
} }
} else if (font->width <= 16) { } else if (font->width <= 16) {
j = vc->vc_font.height * 2; j = vc->vc_font.height * 2;
if (font->charcount * j > FNTSIZE(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) { for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j); memcpy(data, fontdata, j);
memset(data + j, 0, 64 - j); memset(data + j, 0, 64 - j);
@ -2314,6 +2320,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
fontdata += j; fontdata += j;
} }
} else if (font->width <= 24) { } else if (font->width <= 24) {
if (font->charcount * (vc->vc_font.height * sizeof(u32)) > FNTSIZE(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) { for (i = 0; i < font->charcount; i++) {
for (j = 0; j < vc->vc_font.height; j++) { for (j = 0; j < vc->vc_font.height; j++) {
*data++ = fontdata[0]; *data++ = fontdata[0];
@ -2326,6 +2335,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
} }
} else { } else {
j = vc->vc_font.height * 4; j = vc->vc_font.height * 4;
if (font->charcount * j > FNTSIZE(fontdata))
return -EINVAL;
for (i = 0; i < font->charcount; i++) { for (i = 0; i < font->charcount; i++) {
memcpy(data, fontdata, j); memcpy(data, fontdata, j);
memset(data + j, 0, 128 - j); memset(data + j, 0, 128 - j);

View file

@ -152,13 +152,6 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)
/* Font */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
#define FNTSUM(fd) (((int *)(fd))[-4])
#define FONT_EXTRA_WORDS 4
/* /*
* Scroll Method * Scroll Method
*/ */

View file

@ -14,6 +14,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/vt_kern.h> #include <linux/vt_kern.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/font.h>
#include <asm/types.h> #include <asm/types.h>
#include "fbcon.h" #include "fbcon.h"
#include "fbcon_rotate.h" #include "fbcon_rotate.h"

View file

@ -13,6 +13,7 @@
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/vt_kern.h> #include <linux/vt_kern.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/font.h>
#include <asm/types.h> #include <asm/types.h>
#include "fbcon.h" #include "fbcon.h"

View file

@ -810,14 +810,32 @@ void afs_evict_inode(struct inode *inode)
static void afs_setattr_success(struct afs_operation *op) static void afs_setattr_success(struct afs_operation *op)
{ {
struct inode *inode = &op->file[0].vnode->vfs_inode; struct afs_vnode_param *vp = &op->file[0];
struct inode *inode = &vp->vnode->vfs_inode;
loff_t old_i_size = i_size_read(inode);
op->setattr.old_i_size = old_i_size;
afs_vnode_commit_status(op, vp);
/* inode->i_size has now been changed. */
afs_vnode_commit_status(op, &op->file[0]);
if (op->setattr.attr->ia_valid & ATTR_SIZE) { if (op->setattr.attr->ia_valid & ATTR_SIZE) {
loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size; loff_t size = op->setattr.attr->ia_size;
if (size > i_size) if (size > old_i_size)
pagecache_isize_extended(inode, i_size, size); pagecache_isize_extended(inode, old_i_size, size);
truncate_pagecache(inode, size); }
}
static void afs_setattr_edit_file(struct afs_operation *op)
{
struct afs_vnode_param *vp = &op->file[0];
struct inode *inode = &vp->vnode->vfs_inode;
if (op->setattr.attr->ia_valid & ATTR_SIZE) {
loff_t size = op->setattr.attr->ia_size;
loff_t i_size = op->setattr.old_i_size;
if (size < i_size)
truncate_pagecache(inode, size);
} }
} }
@ -825,6 +843,7 @@ static const struct afs_operation_ops afs_setattr_operation = {
.issue_afs_rpc = afs_fs_setattr, .issue_afs_rpc = afs_fs_setattr,
.issue_yfs_rpc = yfs_fs_setattr, .issue_yfs_rpc = yfs_fs_setattr,
.success = afs_setattr_success, .success = afs_setattr_success,
.edit_dir = afs_setattr_edit_file,
}; };
/* /*
@ -863,11 +882,16 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
if (S_ISREG(vnode->vfs_inode.i_mode)) if (S_ISREG(vnode->vfs_inode.i_mode))
filemap_write_and_wait(vnode->vfs_inode.i_mapping); filemap_write_and_wait(vnode->vfs_inode.i_mapping);
/* Prevent any new writebacks from starting whilst we do this. */
down_write(&vnode->validate_lock);
op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ? op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?
afs_file_key(attr->ia_file) : NULL), afs_file_key(attr->ia_file) : NULL),
vnode->volume); vnode->volume);
if (IS_ERR(op)) if (IS_ERR(op)) {
return PTR_ERR(op); ret = PTR_ERR(op);
goto out_unlock;
}
afs_op_set_vnode(op, 0, vnode); afs_op_set_vnode(op, 0, vnode);
op->setattr.attr = attr; op->setattr.attr = attr;
@ -880,5 +904,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
op->file[0].update_ctime = 1; op->file[0].update_ctime = 1;
op->ops = &afs_setattr_operation; op->ops = &afs_setattr_operation;
return afs_do_sync_operation(op); ret = afs_do_sync_operation(op);
out_unlock:
up_write(&vnode->validate_lock);
_leave(" = %d", ret);
return ret;
} }

View file

@ -812,6 +812,7 @@ struct afs_operation {
} store; } store;
struct { struct {
struct iattr *attr; struct iattr *attr;
loff_t old_i_size;
} setattr; } setattr;
struct afs_acl *acl; struct afs_acl *acl;
struct yfs_acl *yacl; struct yfs_acl *yacl;

View file

@ -738,11 +738,21 @@ static int afs_writepages_region(struct address_space *mapping,
int afs_writepages(struct address_space *mapping, int afs_writepages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
struct afs_vnode *vnode = AFS_FS_I(mapping->host);
pgoff_t start, end, next; pgoff_t start, end, next;
int ret; int ret;
_enter(""); _enter("");
/* We have to be careful as we can end up racing with setattr()
* truncating the pagecache since the caller doesn't take a lock here
* to prevent it.
*/
if (wbc->sync_mode == WB_SYNC_ALL)
down_read(&vnode->validate_lock);
else if (!down_read_trylock(&vnode->validate_lock))
return 0;
if (wbc->range_cyclic) { if (wbc->range_cyclic) {
start = mapping->writeback_index; start = mapping->writeback_index;
end = -1; end = -1;
@ -762,6 +772,7 @@ int afs_writepages(struct address_space *mapping,
ret = afs_writepages_region(mapping, wbc, start, end, &next); ret = afs_writepages_region(mapping, wbc, start, end, &next);
} }
up_read(&vnode->validate_lock);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret; return ret;
} }

View file

@ -17,7 +17,6 @@
#include "exfat_raw.h" #include "exfat_raw.h"
#include "exfat_fs.h" #include "exfat_fs.h"
#define EXFAT_CACHE_VALID 0
#define EXFAT_MAX_CACHE 16 #define EXFAT_MAX_CACHE 16
struct exfat_cache { struct exfat_cache {
@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
kmem_cache_destroy(exfat_cachep); kmem_cache_destroy(exfat_cachep);
} }
void exfat_cache_init_inode(struct inode *inode)
{
struct exfat_inode_info *ei = EXFAT_I(inode);
spin_lock_init(&ei->cache_lru_lock);
ei->nr_caches = 0;
ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
INIT_LIST_HEAD(&ei->cache_lru);
}
static inline struct exfat_cache *exfat_cache_alloc(void) static inline struct exfat_cache *exfat_cache_alloc(void)
{ {
return kmem_cache_alloc(exfat_cachep, GFP_NOFS); return kmem_cache_alloc(exfat_cachep, GFP_NOFS);

View file

@ -248,6 +248,8 @@ struct exfat_sb_info {
struct rcu_head rcu; struct rcu_head rcu;
}; };
#define EXFAT_CACHE_VALID 0
/* /*
* EXFAT file system inode in-memory data * EXFAT file system inode in-memory data
*/ */
@ -428,7 +430,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops;
/* cache.c */ /* cache.c */
int exfat_cache_init(void); int exfat_cache_init(void);
void exfat_cache_shutdown(void); void exfat_cache_shutdown(void);
void exfat_cache_init_inode(struct inode *inode);
void exfat_cache_inval_inode(struct inode *inode); void exfat_cache_inval_inode(struct inode *inode);
int exfat_get_cluster(struct inode *inode, unsigned int cluster, int exfat_get_cluster(struct inode *inode, unsigned int cluster,
unsigned int *fclus, unsigned int *dclus, unsigned int *fclus, unsigned int *dclus,

View file

@ -611,8 +611,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
ei->i_crtime = info->crtime; ei->i_crtime = info->crtime;
inode->i_atime = info->atime; inode->i_atime = info->atime;
exfat_cache_init_inode(inode);
return 0; return 0;
} }

View file

@ -578,7 +578,8 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
i_pos = exfat_make_i_pos(&info); i_pos = exfat_make_i_pos(&info);
inode = exfat_build_inode(sb, &info, i_pos); inode = exfat_build_inode(sb, &info, i_pos);
if (IS_ERR(inode)) err = PTR_ERR_OR_ZERO(inode);
if (err)
goto unlock; goto unlock;
inode_inc_iversion(inode); inode_inc_iversion(inode);
@ -745,10 +746,9 @@ static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
i_pos = exfat_make_i_pos(&info); i_pos = exfat_make_i_pos(&info);
inode = exfat_build_inode(sb, &info, i_pos); inode = exfat_build_inode(sb, &info, i_pos);
if (IS_ERR(inode)) { err = PTR_ERR_OR_ZERO(inode);
err = PTR_ERR(inode); if (err)
goto unlock; goto unlock;
}
i_mode = inode->i_mode; i_mode = inode->i_mode;
alias = d_find_alias(inode); alias = d_find_alias(inode);
@ -890,10 +890,9 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
i_pos = exfat_make_i_pos(&info); i_pos = exfat_make_i_pos(&info);
inode = exfat_build_inode(sb, &info, i_pos); inode = exfat_build_inode(sb, &info, i_pos);
if (IS_ERR(inode)) { err = PTR_ERR_OR_ZERO(inode);
err = PTR_ERR(inode); if (err)
goto unlock; goto unlock;
}
inode_inc_iversion(inode); inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime = inode->i_ctime =

View file

@ -376,7 +376,6 @@ static int exfat_read_root(struct inode *inode)
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
current_time(inode); current_time(inode);
exfat_truncate_atime(&inode->i_atime); exfat_truncate_atime(&inode->i_atime);
exfat_cache_init_inode(inode);
return 0; return 0;
} }
@ -763,6 +762,10 @@ static void exfat_inode_init_once(void *foo)
{ {
struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;
spin_lock_init(&ei->cache_lru_lock);
ei->nr_caches = 0;
ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
INIT_LIST_HEAD(&ei->cache_lru);
INIT_HLIST_NODE(&ei->i_hash_fat); INIT_HLIST_NODE(&ei->i_hash_fat);
inode_init_once(&ei->vfs_inode); inode_init_once(&ei->vfs_inode);
} }

View file

@ -526,6 +526,22 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
return 1; return 1;
} }
/* We know we have a pipe buffer, but maybe it's empty? */
static inline bool eat_empty_buffer(struct pipe_inode_info *pipe)
{
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
if (unlikely(!buf->len)) {
pipe_buf_release(pipe, buf);
pipe->tail = tail+1;
return true;
}
return false;
}
/** /**
* splice_from_pipe_next - wait for some data to splice from * splice_from_pipe_next - wait for some data to splice from
* @pipe: pipe to splice from * @pipe: pipe to splice from
@ -545,6 +561,7 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
if (signal_pending(current)) if (signal_pending(current))
return -ERESTARTSYS; return -ERESTARTSYS;
repeat:
while (pipe_empty(pipe->head, pipe->tail)) { while (pipe_empty(pipe->head, pipe->tail)) {
if (!pipe->writers) if (!pipe->writers)
return 0; return 0;
@ -566,6 +583,9 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
pipe_wait_readable(pipe); pipe_wait_readable(pipe);
} }
if (eat_empty_buffer(pipe))
goto repeat;
return 1; return 1;
} }

View file

@ -588,7 +588,7 @@ struct drm_dsc_picture_parameter_set {
* This structure represents the DSC PPS infoframe required to send the Picture * This structure represents the DSC PPS infoframe required to send the Picture
* Parameter Set metadata required before enabling VESA Display Stream * Parameter Set metadata required before enabling VESA Display Stream
* Compression. This is based on the DP Secondary Data Packet structure and * Compression. This is based on the DP Secondary Data Packet structure and
* comprises of SDP Header as defined &struct struct dp_sdp_header in drm_dp_helper.h * comprises of SDP Header as defined &struct dp_sdp_header in drm_dp_helper.h
* and PPS payload defined in &struct drm_dsc_picture_parameter_set. * and PPS payload defined in &struct drm_dsc_picture_parameter_set.
* *
* @pps_header: Header for PPS as per DP SDP header format of type * @pps_header: Header for PPS as per DP SDP header format of type

View file

@ -0,0 +1,87 @@
/*
* David A Rusling
*
* Copyright (C) 2001 ARM Limited
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef AMBA_CLCD_REGS_H
#define AMBA_CLCD_REGS_H
/*
* CLCD Controller Internal Register addresses
*/
#define CLCD_TIM0 0x00000000
#define CLCD_TIM1 0x00000004
#define CLCD_TIM2 0x00000008
#define CLCD_TIM3 0x0000000c
#define CLCD_UBAS 0x00000010
#define CLCD_LBAS 0x00000014
#define CLCD_PL110_IENB 0x00000018
#define CLCD_PL110_CNTL 0x0000001c
#define CLCD_PL110_STAT 0x00000020
#define CLCD_PL110_INTR 0x00000024
#define CLCD_PL110_UCUR 0x00000028
#define CLCD_PL110_LCUR 0x0000002C
#define CLCD_PL111_CNTL 0x00000018
#define CLCD_PL111_IENB 0x0000001c
#define CLCD_PL111_RIS 0x00000020
#define CLCD_PL111_MIS 0x00000024
#define CLCD_PL111_ICR 0x00000028
#define CLCD_PL111_UCUR 0x0000002c
#define CLCD_PL111_LCUR 0x00000030
#define CLCD_PALL 0x00000200
#define CLCD_PALETTE 0x00000200
#define TIM2_PCD_LO_MASK GENMASK(4, 0)
#define TIM2_PCD_LO_BITS 5
#define TIM2_CLKSEL (1 << 5)
#define TIM2_ACB_MASK GENMASK(10, 6)
#define TIM2_IVS (1 << 11)
#define TIM2_IHS (1 << 12)
#define TIM2_IPC (1 << 13)
#define TIM2_IOE (1 << 14)
#define TIM2_BCD (1 << 26)
#define TIM2_PCD_HI_MASK GENMASK(31, 27)
#define TIM2_PCD_HI_BITS 5
#define TIM2_PCD_HI_SHIFT 27
#define CNTL_LCDEN (1 << 0)
#define CNTL_LCDBPP1 (0 << 1)
#define CNTL_LCDBPP2 (1 << 1)
#define CNTL_LCDBPP4 (2 << 1)
#define CNTL_LCDBPP8 (3 << 1)
#define CNTL_LCDBPP16 (4 << 1)
#define CNTL_LCDBPP16_565 (6 << 1)
#define CNTL_LCDBPP16_444 (7 << 1)
#define CNTL_LCDBPP24 (5 << 1)
#define CNTL_LCDBW (1 << 4)
#define CNTL_LCDTFT (1 << 5)
#define CNTL_LCDMONO8 (1 << 6)
#define CNTL_LCDDUAL (1 << 7)
#define CNTL_BGR (1 << 8)
#define CNTL_BEBO (1 << 9)
#define CNTL_BEPO (1 << 10)
#define CNTL_LCDPWR (1 << 11)
#define CNTL_LCDVCOMP(x) ((x) << 12)
#define CNTL_LDMAFIFOTIME (1 << 15)
#define CNTL_WATERMARK (1 << 16)
/* ST Microelectronics variant bits */
#define CNTL_ST_1XBPP_444 0x0
#define CNTL_ST_1XBPP_5551 (1 << 17)
#define CNTL_ST_1XBPP_565 (1 << 18)
#define CNTL_ST_CDWID_12 0x0
#define CNTL_ST_CDWID_16 (1 << 19)
#define CNTL_ST_CDWID_18 (1 << 20)
#define CNTL_ST_CDWID_24 ((1 << 19)|(1 << 20))
#define CNTL_ST_CEAEN (1 << 21)
#define CNTL_ST_LCDBPP24_PACKED (6 << 1)
#endif /* AMBA_CLCD_REGS_H */

290
include/linux/amba/clcd.h Normal file
View file

@ -0,0 +1,290 @@
/*
* linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
*
* David A Rusling
*
* Copyright (C) 2001 ARM Limited
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/fb.h>
#include <linux/amba/clcd-regs.h>
enum {
/* individual formats */
CLCD_CAP_RGB444 = (1 << 0),
CLCD_CAP_RGB5551 = (1 << 1),
CLCD_CAP_RGB565 = (1 << 2),
CLCD_CAP_RGB888 = (1 << 3),
CLCD_CAP_BGR444 = (1 << 4),
CLCD_CAP_BGR5551 = (1 << 5),
CLCD_CAP_BGR565 = (1 << 6),
CLCD_CAP_BGR888 = (1 << 7),
/* connection layouts */
CLCD_CAP_444 = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
CLCD_CAP_5551 = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
CLCD_CAP_565 = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
CLCD_CAP_888 = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
/* red/blue ordering */
CLCD_CAP_RGB = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
CLCD_CAP_BGR = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
CLCD_CAP_ALL = CLCD_CAP_BGR | CLCD_CAP_RGB,
};
struct backlight_device;
struct clcd_panel {
struct fb_videomode mode;
signed short width; /* width in mm */
signed short height; /* height in mm */
u32 tim2;
u32 tim3;
u32 cntl;
u32 caps;
unsigned int bpp:8,
fixedtimings:1,
grayscale:1;
unsigned int connector;
struct backlight_device *backlight;
/*
* If the B/R lines are switched between the CLCD
* and the panel we need to know this and not try to
* compensate with the BGR bit in the control register.
*/
bool bgr_connection;
};
struct clcd_regs {
u32 tim0;
u32 tim1;
u32 tim2;
u32 tim3;
u32 cntl;
unsigned long pixclock;
};
struct clcd_fb;
/*
* the board-type specific routines
*/
struct clcd_board {
const char *name;
/*
* Optional. Hardware capability flags.
*/
u32 caps;
/*
* Optional. Check whether the var structure is acceptable
* for this display.
*/
int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
/*
* Compulsory. Decode fb->fb.var into regs->*. In the case of
* fixed timing, set regs->* to the register values required.
*/
void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
/*
* Optional. Disable any extra display hardware.
*/
void (*disable)(struct clcd_fb *);
/*
* Optional. Enable any extra display hardware.
*/
void (*enable)(struct clcd_fb *);
/*
* Setup platform specific parts of CLCD driver
*/
int (*setup)(struct clcd_fb *);
/*
* mmap the framebuffer memory
*/
int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
/*
* Remove platform specific parts of CLCD driver
*/
void (*remove)(struct clcd_fb *);
};
struct amba_device;
struct clk;
/* this data structure describes each frame buffer device we find */
struct clcd_fb {
struct fb_info fb;
struct amba_device *dev;
struct clk *clk;
struct clcd_panel *panel;
struct clcd_board *board;
void *board_data;
void __iomem *regs;
u16 off_ienb;
u16 off_cntl;
u32 clcd_cntl;
u32 cmap[16];
bool clk_enabled;
};
static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
{
struct fb_var_screeninfo *var = &fb->fb.var;
u32 val, cpl;
/*
* Program the CLCD controller registers and start the CLCD
*/
val = ((var->xres / 16) - 1) << 2;
val |= (var->hsync_len - 1) << 8;
val |= (var->right_margin - 1) << 16;
val |= (var->left_margin - 1) << 24;
regs->tim0 = val;
val = var->yres;
if (fb->panel->cntl & CNTL_LCDDUAL)
val /= 2;
val -= 1;
val |= (var->vsync_len - 1) << 10;
val |= var->lower_margin << 16;
val |= var->upper_margin << 24;
regs->tim1 = val;
val = fb->panel->tim2;
val |= var->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS;
val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
cpl = var->xres_virtual;
if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */
/* / 1 */;
else if (!var->grayscale) /* STN color */
cpl = cpl * 8 / 3;
else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
cpl /= 8;
else /* STN monochrome, 4bit */
cpl /= 4;
regs->tim2 = val | ((cpl - 1) << 16);
regs->tim3 = fb->panel->tim3;
val = fb->panel->cntl;
if (var->grayscale)
val |= CNTL_LCDBW;
if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) {
/*
* if board and panel supply capabilities, we can support
* changing BGR/RGB depending on supplied parameters. Here
* we switch to what the framebuffer is providing if need
* be, so if the framebuffer is BGR but the display connection
* is RGB (first case) we switch it around. Vice versa mutatis
* mutandis if the framebuffer is RGB but the display connection
* is BGR, we flip it around.
*/
if (var->red.offset == 0)
val &= ~CNTL_BGR;
else
val |= CNTL_BGR;
if (fb->panel->bgr_connection)
val ^= CNTL_BGR;
}
switch (var->bits_per_pixel) {
case 1:
val |= CNTL_LCDBPP1;
break;
case 2:
val |= CNTL_LCDBPP2;
break;
case 4:
val |= CNTL_LCDBPP4;
break;
case 8:
val |= CNTL_LCDBPP8;
break;
case 16:
/*
* PL110 cannot choose between 5551 and 565 modes in its
* control register. It is possible to use 565 with
* custom external wiring.
*/
if (amba_part(fb->dev) == 0x110 ||
var->green.length == 5)
val |= CNTL_LCDBPP16;
else if (var->green.length == 6)
val |= CNTL_LCDBPP16_565;
else
val |= CNTL_LCDBPP16_444;
break;
case 32:
val |= CNTL_LCDBPP24;
break;
}
regs->cntl = val;
regs->pixclock = var->pixclock;
}
static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
{
var->xres_virtual = var->xres = (var->xres + 15) & ~15;
var->yres_virtual = var->yres = (var->yres + 1) & ~1;
#define CHECK(e,l,h) (var->e < l || var->e > h)
if (CHECK(right_margin, (5+1), 256) || /* back porch */
CHECK(left_margin, (5+1), 256) || /* front porch */
CHECK(hsync_len, (5+1), 256) ||
var->xres > 4096 ||
var->lower_margin > 255 || /* back porch */
var->upper_margin > 255 || /* front porch */
var->vsync_len > 32 ||
var->yres > 1024)
return -EINVAL;
#undef CHECK
/* single panel mode: PCD = max(PCD, 1) */
/* dual panel mode: PCD = max(PCD, 5) */
/*
* You can't change the grayscale setting, and
* we can only do non-interlaced video.
*/
if (var->grayscale != fb->fb.var.grayscale ||
(var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
return -EINVAL;
#define CHECK(e) (var->e != fb->fb.var.e)
if (fb->panel->fixedtimings &&
(CHECK(xres) ||
CHECK(yres) ||
CHECK(bits_per_pixel) ||
CHECK(pixclock) ||
CHECK(left_margin) ||
CHECK(right_margin) ||
CHECK(upper_margin) ||
CHECK(lower_margin) ||
CHECK(hsync_len) ||
CHECK(vsync_len) ||
CHECK(sync)))
return -EINVAL;
#undef CHECK
var->nonstd = 0;
var->accel_flags = 0;
return 0;
}

View file

@ -59,4 +59,17 @@ extern const struct font_desc *get_default_font(int xres, int yres,
/* Max. length for the name of a predefined font */ /* Max. length for the name of a predefined font */
#define MAX_FONT_NAME 32 #define MAX_FONT_NAME 32
/* Extra word getters */
#define REFCOUNT(fd) (((int *)(fd))[-1])
#define FNTSIZE(fd) (((int *)(fd))[-2])
#define FNTCHARCNT(fd) (((int *)(fd))[-3])
#define FNTSUM(fd) (((int *)(fd))[-4])
#define FONT_EXTRA_WORDS 4
struct font_data {
unsigned int extra[FONT_EXTRA_WORDS];
const unsigned char data[];
} __packed;
#endif /* _VIDEO_FONT_H */ #endif /* _VIDEO_FONT_H */

View file

@ -51,11 +51,11 @@ enum rxrpc_cmsg_type {
RXRPC_BUSY = 6, /* -r: server busy received [terminal] */ RXRPC_BUSY = 6, /* -r: server busy received [terminal] */
RXRPC_LOCAL_ERROR = 7, /* -r: local error generated [terminal] */ RXRPC_LOCAL_ERROR = 7, /* -r: local error generated [terminal] */
RXRPC_NEW_CALL = 8, /* -r: [Service] new incoming call notification */ RXRPC_NEW_CALL = 8, /* -r: [Service] new incoming call notification */
RXRPC_ACCEPT = 9, /* s-: [Service] accept request */
RXRPC_EXCLUSIVE_CALL = 10, /* s-: Call should be on exclusive connection */ RXRPC_EXCLUSIVE_CALL = 10, /* s-: Call should be on exclusive connection */
RXRPC_UPGRADE_SERVICE = 11, /* s-: Request service upgrade for client call */ RXRPC_UPGRADE_SERVICE = 11, /* s-: Request service upgrade for client call */
RXRPC_TX_LENGTH = 12, /* s-: Total length of Tx data */ RXRPC_TX_LENGTH = 12, /* s-: Total length of Tx data */
RXRPC_SET_CALL_TIMEOUT = 13, /* s-: Set one or more call timeouts */ RXRPC_SET_CALL_TIMEOUT = 13, /* s-: Set one or more call timeouts */
RXRPC_CHARGE_ACCEPT = 14, /* s-: Charge the accept pool with a user call ID */
RXRPC__SUPPORTED RXRPC__SUPPORTED
}; };

View file

@ -83,6 +83,9 @@ static inline unsigned long bfn_to_pfn(unsigned long bfn)
}) })
#define gfn_to_virt(m) (__va(gfn_to_pfn(m) << XEN_PAGE_SHIFT)) #define gfn_to_virt(m) (__va(gfn_to_pfn(m) << XEN_PAGE_SHIFT))
#define percpu_to_gfn(v) \
(pfn_to_gfn(per_cpu_ptr_to_phys(v) >> XEN_PAGE_SHIFT))
/* Only used in PV code. But ARM guests are always HVM. */ /* Only used in PV code. But ARM guests are always HVM. */
static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr) static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
{ {

View file

@ -5880,8 +5880,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
bool src_known = tnum_subreg_is_const(src_reg->var_off); bool src_known = tnum_subreg_is_const(src_reg->var_off);
bool dst_known = tnum_subreg_is_const(dst_reg->var_off); bool dst_known = tnum_subreg_is_const(dst_reg->var_off);
struct tnum var32_off = tnum_subreg(dst_reg->var_off); struct tnum var32_off = tnum_subreg(dst_reg->var_off);
s32 smin_val = src_reg->smin_value; s32 smin_val = src_reg->s32_min_value;
u32 umin_val = src_reg->umin_value; u32 umin_val = src_reg->u32_min_value;
/* Assuming scalar64_min_max_or will be called so it is safe /* Assuming scalar64_min_max_or will be called so it is safe
* to skip updating register for known case. * to skip updating register for known case.
@ -5904,8 +5904,8 @@ static void scalar32_min_max_or(struct bpf_reg_state *dst_reg,
/* ORing two positives gives a positive, so safe to /* ORing two positives gives a positive, so safe to
* cast result into s64. * cast result into s64.
*/ */
dst_reg->s32_min_value = dst_reg->umin_value; dst_reg->s32_min_value = dst_reg->u32_min_value;
dst_reg->s32_max_value = dst_reg->umax_value; dst_reg->s32_max_value = dst_reg->u32_max_value;
} }
} }

View file

@ -14,6 +14,7 @@
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/fdtable.h> #include <linux/fdtable.h>
#include <linux/fs_struct.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/mount.h> #include <linux/mount.h>
@ -71,6 +72,14 @@ static int call_usermodehelper_exec_async(void *data)
flush_signal_handlers(current, 1); flush_signal_handlers(current, 1);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
/*
* Initial kernel threads share ther FS with init, in order to
* get the init root directory. But we've now created a new
* thread that is going to execve a user process and has its own
* 'struct fs_struct'. Reset umask to the default.
*/
current->fs->umask = 0022;
/* /*
* Our parent (unbound workqueue) runs with elevated scheduling * Our parent (unbound workqueue) runs with elevated scheduling
* priority. Avoid propagating that into the userspace child. * priority. Avoid propagating that into the userspace child.

View file

@ -8,8 +8,8 @@
#define FONTDATAMAX 9216 #define FONTDATAMAX 9216
static const unsigned char fontdata_10x18[FONTDATAMAX] = { static struct font_data fontdata_10x18 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, 0x00, /* 0000000000 */ 0x00, 0x00, /* 0000000000 */
0x00, 0x00, /* 0000000000 */ 0x00, 0x00, /* 0000000000 */
@ -5129,8 +5129,7 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = {
0x00, 0x00, /* 0000000000 */ 0x00, 0x00, /* 0000000000 */
0x00, 0x00, /* 0000000000 */ 0x00, 0x00, /* 0000000000 */
0x00, 0x00, /* 0000000000 */ 0x00, 0x00, /* 0000000000 */
} };
};
const struct font_desc font_10x18 = { const struct font_desc font_10x18 = {
@ -5138,7 +5137,7 @@ const struct font_desc font_10x18 = {
.name = "10x18", .name = "10x18",
.width = 10, .width = 10,
.height = 18, .height = 18,
.data = fontdata_10x18, .data = fontdata_10x18.data,
#ifdef __sparc__ #ifdef __sparc__
.pref = 5, .pref = 5,
#else #else

View file

@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/font.h> #include <linux/font.h>
static const unsigned char fontdata_6x10[] = { #define FONTDATAMAX 2560
static struct font_data fontdata_6x10 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
@ -3074,14 +3076,13 @@ static const unsigned char fontdata_6x10[] = {
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
} };
};
const struct font_desc font_6x10 = { const struct font_desc font_6x10 = {
.idx = FONT6x10_IDX, .idx = FONT6x10_IDX,
.name = "6x10", .name = "6x10",
.width = 6, .width = 6,
.height = 10, .height = 10,
.data = fontdata_6x10, .data = fontdata_6x10.data,
.pref = 0, .pref = 0,
}; };

View file

@ -9,8 +9,8 @@
#define FONTDATAMAX (11*256) #define FONTDATAMAX (11*256)
static const unsigned char fontdata_6x11[FONTDATAMAX] = { static struct font_data fontdata_6x11 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
@ -3338,8 +3338,7 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = {
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
} };
};
const struct font_desc font_vga_6x11 = { const struct font_desc font_vga_6x11 = {
@ -3347,7 +3346,7 @@ const struct font_desc font_vga_6x11 = {
.name = "ProFont6x11", .name = "ProFont6x11",
.width = 6, .width = 6,
.height = 11, .height = 11,
.data = fontdata_6x11, .data = fontdata_6x11.data,
/* Try avoiding this font if possible unless on MAC */ /* Try avoiding this font if possible unless on MAC */
.pref = -2000, .pref = -2000,
}; };

View file

@ -8,8 +8,8 @@
#define FONTDATAMAX 3584 #define FONTDATAMAX 3584
static const unsigned char fontdata_7x14[FONTDATAMAX] = { static struct font_data fontdata_7x14 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 0000000 */ 0x00, /* 0000000 */
0x00, /* 0000000 */ 0x00, /* 0000000 */
@ -4105,8 +4105,7 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = {
0x00, /* 0000000 */ 0x00, /* 0000000 */
0x00, /* 0000000 */ 0x00, /* 0000000 */
0x00, /* 0000000 */ 0x00, /* 0000000 */
} };
};
const struct font_desc font_7x14 = { const struct font_desc font_7x14 = {
@ -4114,6 +4113,6 @@ const struct font_desc font_7x14 = {
.name = "7x14", .name = "7x14",
.width = 7, .width = 7,
.height = 14, .height = 14,
.data = fontdata_7x14, .data = fontdata_7x14.data,
.pref = 0, .pref = 0,
}; };

View file

@ -10,8 +10,8 @@
#define FONTDATAMAX 4096 #define FONTDATAMAX 4096
static const unsigned char fontdata_8x16[FONTDATAMAX] = { static struct font_data fontdata_8x16 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
@ -4619,8 +4619,7 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = {
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
} };
};
const struct font_desc font_vga_8x16 = { const struct font_desc font_vga_8x16 = {
@ -4628,7 +4627,7 @@ const struct font_desc font_vga_8x16 = {
.name = "VGA8x16", .name = "VGA8x16",
.width = 8, .width = 8,
.height = 16, .height = 16,
.data = fontdata_8x16, .data = fontdata_8x16.data,
.pref = 0, .pref = 0,
}; };
EXPORT_SYMBOL(font_vga_8x16); EXPORT_SYMBOL(font_vga_8x16);

View file

@ -9,8 +9,8 @@
#define FONTDATAMAX 2048 #define FONTDATAMAX 2048
static const unsigned char fontdata_8x8[FONTDATAMAX] = { static struct font_data fontdata_8x8 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
@ -2570,8 +2570,7 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = {
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
} };
};
const struct font_desc font_vga_8x8 = { const struct font_desc font_vga_8x8 = {
@ -2579,6 +2578,6 @@ const struct font_desc font_vga_8x8 = {
.name = "VGA8x8", .name = "VGA8x8",
.width = 8, .width = 8,
.height = 8, .height = 8,
.data = fontdata_8x8, .data = fontdata_8x8.data,
.pref = 0, .pref = 0,
}; };

View file

@ -3,7 +3,10 @@
#include <linux/font.h> #include <linux/font.h>
static const unsigned char acorndata_8x8[] = { #define FONTDATAMAX 2048
static struct font_data acorndata_8x8 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */
/* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */ /* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
/* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */ /* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */
@ -260,14 +263,14 @@ static const unsigned char acorndata_8x8[] = {
/* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00, /* FD */ 0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
/* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, /* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
/* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; } };
const struct font_desc font_acorn_8x8 = { const struct font_desc font_acorn_8x8 = {
.idx = ACORN8x8_IDX, .idx = ACORN8x8_IDX,
.name = "Acorn8x8", .name = "Acorn8x8",
.width = 8, .width = 8,
.height = 8, .height = 8,
.data = acorndata_8x8, .data = acorndata_8x8.data,
#ifdef CONFIG_ARCH_ACORN #ifdef CONFIG_ARCH_ACORN
.pref = 20, .pref = 20,
#else #else

View file

@ -43,8 +43,8 @@ __END__;
#define FONTDATAMAX 1536 #define FONTDATAMAX 1536
static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { static struct font_data fontdata_mini_4x6 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/*{*/ /*{*/
/* Char 0: ' ' */ /* Char 0: ' ' */
0xee, /*= [*** ] */ 0xee, /*= [*** ] */
@ -2145,14 +2145,14 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
0xee, /*= [*** ] */ 0xee, /*= [*** ] */
0x00, /*= [ ] */ 0x00, /*= [ ] */
/*}*/ /*}*/
}; } };
const struct font_desc font_mini_4x6 = { const struct font_desc font_mini_4x6 = {
.idx = MINI4x6_IDX, .idx = MINI4x6_IDX,
.name = "MINI4x6", .name = "MINI4x6",
.width = 4, .width = 4,
.height = 6, .height = 6,
.data = fontdata_mini_4x6, .data = fontdata_mini_4x6.data,
.pref = 3, .pref = 3,
}; };

View file

@ -14,8 +14,8 @@
#define FONTDATAMAX 2048 #define FONTDATAMAX 2048
static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = { static struct font_data fontdata_pearl8x8 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
@ -2575,14 +2575,13 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
0x00, /* 00000000 */ 0x00, /* 00000000 */
} };
};
const struct font_desc font_pearl_8x8 = { const struct font_desc font_pearl_8x8 = {
.idx = PEARL8x8_IDX, .idx = PEARL8x8_IDX,
.name = "PEARL8x8", .name = "PEARL8x8",
.width = 8, .width = 8,
.height = 8, .height = 8,
.data = fontdata_pearl8x8, .data = fontdata_pearl8x8.data,
.pref = 2, .pref = 2,
}; };

View file

@ -3,8 +3,8 @@
#define FONTDATAMAX 11264 #define FONTDATAMAX 11264
static const unsigned char fontdata_sun12x22[FONTDATAMAX] = { static struct font_data fontdata_sun12x22 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* 0 0x00 '^@' */ /* 0 0x00 '^@' */
0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */
@ -6148,8 +6148,7 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */
0x00, 0x00, /* 000000000000 */ 0x00, 0x00, /* 000000000000 */
} };
};
const struct font_desc font_sun_12x22 = { const struct font_desc font_sun_12x22 = {
@ -6157,7 +6156,7 @@ const struct font_desc font_sun_12x22 = {
.name = "SUN12x22", .name = "SUN12x22",
.width = 12, .width = 12,
.height = 22, .height = 22,
.data = fontdata_sun12x22, .data = fontdata_sun12x22.data,
#ifdef __sparc__ #ifdef __sparc__
.pref = 5, .pref = 5,
#else #else

View file

@ -3,7 +3,8 @@
#define FONTDATAMAX 4096 #define FONTDATAMAX 4096
static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { static struct font_data fontdata_sun8x16 = {
{ 0, 0, FONTDATAMAX, 0 }, {
/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
@ -260,14 +261,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
/* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
}; } };
const struct font_desc font_sun_8x16 = { const struct font_desc font_sun_8x16 = {
.idx = SUN8x16_IDX, .idx = SUN8x16_IDX,
.name = "SUN8x16", .name = "SUN8x16",
.width = 8, .width = 8,
.height = 16, .height = 16,
.data = fontdata_sun8x16, .data = fontdata_sun8x16.data,
#ifdef __sparc__ #ifdef __sparc__
.pref = 10, .pref = 10,
#else #else

View file

@ -4,8 +4,8 @@
#define FONTDATAMAX 16384 #define FONTDATAMAX 16384
static const unsigned char fontdata_ter16x32[FONTDATAMAX] = { static struct font_data fontdata_ter16x32 = {
{ 0, 0, FONTDATAMAX, 0 }, {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x7f, 0xfc,
0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c, 0x70, 0x1c,
@ -2054,8 +2054,7 @@ static const unsigned char fontdata_ter16x32[FONTDATAMAX] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 255 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 255 */
} };
};
const struct font_desc font_ter_16x32 = { const struct font_desc font_ter_16x32 = {
@ -2063,7 +2062,7 @@ const struct font_desc font_ter_16x32 = {
.name = "TER16x32", .name = "TER16x32",
.width = 16, .width = 16,
.height = 32, .height = 32,
.data = fontdata_ter16x32, .data = fontdata_ter16x32.data,
#ifdef __sparc__ #ifdef __sparc__
.pref = 5, .pref = 5,
#else #else

View file

@ -806,8 +806,6 @@ copy_present_page(struct mm_struct *dst_mm, struct mm_struct *src_mm,
return 1; return 1;
/* /*
* The trick starts.
*
* What we want to do is to check whether this page may * What we want to do is to check whether this page may
* have been pinned by the parent process. If so, * have been pinned by the parent process. If so,
* instead of wrprotect the pte on both sides, we copy * instead of wrprotect the pte on both sides, we copy
@ -815,47 +813,16 @@ copy_present_page(struct mm_struct *dst_mm, struct mm_struct *src_mm,
* the pinned page won't be randomly replaced in the * the pinned page won't be randomly replaced in the
* future. * future.
* *
* To achieve this, we do the following: * The page pinning checks are just "has this mm ever
* * seen pinning", along with the (inexact) check of
* 1. Write-protect the pte if it's writable. This is * the page count. That might give false positives for
* to protect concurrent write fast-gup with * for pinning, but it will work correctly.
* FOLL_PIN, so that we'll fail the fast-gup with
* the write bit removed.
*
* 2. Check page_maybe_dma_pinned() to see whether this
* page may have been pinned.
*
* The order of these steps is important to serialize
* against the fast-gup code (gup_pte_range()) on the
* pte check and try_grab_compound_head(), so that
* we'll make sure either we'll capture that fast-gup
* so we'll copy the pinned page here, or we'll fail
* that fast-gup.
*
* NOTE! Even if we don't end up copying the page,
* we won't undo this wrprotect(), because the normal
* reference copy will need it anyway.
*/
if (pte_write(pte))
ptep_set_wrprotect(src_mm, addr, src_pte);
/*
* These are the "normally we can just copy by reference"
* checks.
*/ */
if (likely(!atomic_read(&src_mm->has_pinned))) if (likely(!atomic_read(&src_mm->has_pinned)))
return 1; return 1;
if (likely(!page_maybe_dma_pinned(page))) if (likely(!page_maybe_dma_pinned(page)))
return 1; return 1;
/*
* Uhhuh. It looks like the page might be a pinned page,
* and we actually need to copy it. Now we can set the
* source pte back to being writable.
*/
if (pte_write(pte))
set_pte_at(src_mm, addr, src_pte, pte);
new_page = *prealloc; new_page = *prealloc;
if (!new_page) if (!new_page)
return -EAGAIN; return -EAGAIN;

View file

@ -380,6 +380,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
u32 filter_mask, const struct net_device *dev) u32 filter_mask, const struct net_device *dev)
{ {
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
struct nlattr *af = NULL;
struct net_bridge *br; struct net_bridge *br;
struct ifinfomsg *hdr; struct ifinfomsg *hdr;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
@ -423,11 +424,18 @@ static int br_fill_ifinfo(struct sk_buff *skb,
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
} }
if (filter_mask & (RTEXT_FILTER_BRVLAN |
RTEXT_FILTER_BRVLAN_COMPRESSED |
RTEXT_FILTER_MRP)) {
af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
if (!af)
goto nla_put_failure;
}
/* Check if the VID information is requested */ /* Check if the VID information is requested */
if ((filter_mask & RTEXT_FILTER_BRVLAN) || if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
struct net_bridge_vlan_group *vg; struct net_bridge_vlan_group *vg;
struct nlattr *af;
int err; int err;
/* RCU needed because of the VLAN locking rules (rcu || rtnl) */ /* RCU needed because of the VLAN locking rules (rcu || rtnl) */
@ -441,11 +449,6 @@ static int br_fill_ifinfo(struct sk_buff *skb,
rcu_read_unlock(); rcu_read_unlock();
goto done; goto done;
} }
af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
if (!af) {
rcu_read_unlock();
goto nla_put_failure;
}
if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
err = br_fill_ifvlaninfo_compressed(skb, vg); err = br_fill_ifvlaninfo_compressed(skb, vg);
else else
@ -456,32 +459,25 @@ static int br_fill_ifinfo(struct sk_buff *skb,
rcu_read_unlock(); rcu_read_unlock();
if (err) if (err)
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, af);
} }
if (filter_mask & RTEXT_FILTER_MRP) { if (filter_mask & RTEXT_FILTER_MRP) {
struct nlattr *af;
int err; int err;
if (!br_mrp_enabled(br) || port) if (!br_mrp_enabled(br) || port)
goto done; goto done;
af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
if (!af)
goto nla_put_failure;
rcu_read_lock(); rcu_read_lock();
err = br_mrp_fill_info(skb, br); err = br_mrp_fill_info(skb, br);
rcu_read_unlock(); rcu_read_unlock();
if (err) if (err)
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, af);
} }
done: done:
if (af)
nla_nest_end(skb, af);
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
return 0; return 0;

View file

@ -10203,6 +10203,12 @@ const struct bpf_func_proto bpf_skc_to_tcp_sock_proto = {
BPF_CALL_1(bpf_skc_to_tcp_timewait_sock, struct sock *, sk) BPF_CALL_1(bpf_skc_to_tcp_timewait_sock, struct sock *, sk)
{ {
/* BTF types for tcp_timewait_sock and inet_timewait_sock are not
* generated if CONFIG_INET=n. Trigger an explicit generation here.
*/
BTF_TYPE_EMIT(struct inet_timewait_sock);
BTF_TYPE_EMIT(struct tcp_timewait_sock);
#ifdef CONFIG_INET #ifdef CONFIG_INET
if (sk && sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT) if (sk && sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT)
return (unsigned long)sk; return (unsigned long)sk;

View file

@ -1798,12 +1798,12 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
__skb_pull(skb, hdrlen); __skb_pull(skb, hdrlen);
if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) { if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) {
thtail->window = th->window;
TCP_SKB_CB(tail)->end_seq = TCP_SKB_CB(skb)->end_seq; TCP_SKB_CB(tail)->end_seq = TCP_SKB_CB(skb)->end_seq;
if (after(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq)) if (likely(!before(TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(tail)->ack_seq))) {
TCP_SKB_CB(tail)->ack_seq = TCP_SKB_CB(skb)->ack_seq; TCP_SKB_CB(tail)->ack_seq = TCP_SKB_CB(skb)->ack_seq;
thtail->window = th->window;
}
/* We have to update both TCP_SKB_CB(tail)->tcp_flags and /* We have to update both TCP_SKB_CB(tail)->tcp_flags and
* thtail->fin, so that the fast path in tcp_rcv_established() * thtail->fin, so that the fast path in tcp_rcv_established()

View file

@ -452,7 +452,10 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,
static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
struct sk_buff *skb, struct mptcp_ext *ext) struct sk_buff *skb, struct mptcp_ext *ext)
{ {
u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq); /* The write_seq value has already been incremented, so the actual
* sequence number for the DATA_FIN is one less.
*/
u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq) - 1;
if (!ext->use_map || !skb->len) { if (!ext->use_map || !skb->len) {
/* RFC6824 requires a DSS mapping with specific values /* RFC6824 requires a DSS mapping with specific values
@ -461,10 +464,7 @@ static void mptcp_write_data_fin(struct mptcp_subflow_context *subflow,
ext->data_fin = 1; ext->data_fin = 1;
ext->use_map = 1; ext->use_map = 1;
ext->dsn64 = 1; ext->dsn64 = 1;
/* The write_seq value has already been incremented, so ext->data_seq = data_fin_tx_seq;
* the actual sequence number for the DATA_FIN is one less.
*/
ext->data_seq = data_fin_tx_seq - 1;
ext->subflow_seq = 0; ext->subflow_seq = 0;
ext->data_len = 1; ext->data_len = 1;
} else if (ext->data_seq + ext->data_len == data_fin_tx_seq) { } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {

View file

@ -750,7 +750,7 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
return MAPPING_DATA_FIN; return MAPPING_DATA_FIN;
} }
} else { } else {
u64 data_fin_seq = mpext->data_seq + data_len; u64 data_fin_seq = mpext->data_seq + data_len - 1;
/* If mpext->data_seq is a 32-bit value, data_fin_seq /* If mpext->data_seq is a 32-bit value, data_fin_seq
* must also be limited to 32 bits. * must also be limited to 32 bits.

View file

@ -905,15 +905,19 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
} }
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
if (err == NF_ACCEPT && if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) { if (ct->status & IPS_SRC_NAT) {
if (maniptype == NF_NAT_MANIP_SRC) if (maniptype == NF_NAT_MANIP_SRC)
maniptype = NF_NAT_MANIP_DST; maniptype = NF_NAT_MANIP_DST;
else else
maniptype = NF_NAT_MANIP_SRC; maniptype = NF_NAT_MANIP_SRC;
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
maniptype); maniptype);
} else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL,
NF_NAT_MANIP_SRC);
}
} }
/* Mark NAT done if successful and update the flow key. */ /* Mark NAT done if successful and update the flow key. */

View file

@ -193,7 +193,7 @@ static int announce_servers(struct sockaddr_qrtr *sq)
struct qrtr_server *srv; struct qrtr_server *srv;
struct qrtr_node *node; struct qrtr_node *node;
void __rcu **slot; void __rcu **slot;
int ret = 0; int ret;
node = node_get(qrtr_ns.local_node); node = node_get(qrtr_ns.local_node);
if (!node) if (!node)
@ -203,18 +203,27 @@ static int announce_servers(struct sockaddr_qrtr *sq)
/* Announce the list of servers registered in this node */ /* Announce the list of servers registered in this node */
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
srv = radix_tree_deref_slot(slot); srv = radix_tree_deref_slot(slot);
if (!srv)
continue;
if (radix_tree_deref_retry(srv)) {
slot = radix_tree_iter_retry(&iter);
continue;
}
slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
ret = service_announce_new(sq, srv); ret = service_announce_new(sq, srv);
if (ret < 0) { if (ret < 0) {
pr_err("failed to announce new service\n"); pr_err("failed to announce new service\n");
goto err_out; return ret;
} }
rcu_read_lock();
} }
err_out:
rcu_read_unlock(); rcu_read_unlock();
return ret; return 0;
} }
static struct qrtr_server *server_add(unsigned int service, static struct qrtr_server *server_add(unsigned int service,
@ -339,7 +348,7 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
struct qrtr_node *node; struct qrtr_node *node;
void __rcu **slot; void __rcu **slot;
struct kvec iv; struct kvec iv;
int ret = 0; int ret;
iv.iov_base = &pkt; iv.iov_base = &pkt;
iv.iov_len = sizeof(pkt); iv.iov_len = sizeof(pkt);
@ -352,7 +361,16 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
/* Advertise removal of this client to all servers of remote node */ /* Advertise removal of this client to all servers of remote node */
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
srv = radix_tree_deref_slot(slot); srv = radix_tree_deref_slot(slot);
if (!srv)
continue;
if (radix_tree_deref_retry(srv)) {
slot = radix_tree_iter_retry(&iter);
continue;
}
slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
server_del(node, srv->port); server_del(node, srv->port);
rcu_read_lock();
} }
rcu_read_unlock(); rcu_read_unlock();
@ -368,6 +386,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
rcu_read_lock(); rcu_read_lock();
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
srv = radix_tree_deref_slot(slot); srv = radix_tree_deref_slot(slot);
if (!srv)
continue;
if (radix_tree_deref_retry(srv)) {
slot = radix_tree_iter_retry(&iter);
continue;
}
slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
sq.sq_family = AF_QIPCRTR; sq.sq_family = AF_QIPCRTR;
sq.sq_node = srv->node; sq.sq_node = srv->node;
@ -379,14 +405,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
if (ret < 0) { if (ret < 0) {
pr_err("failed to send bye cmd\n"); pr_err("failed to send bye cmd\n");
goto err_out; return ret;
} }
rcu_read_lock();
} }
err_out:
rcu_read_unlock(); rcu_read_unlock();
return ret; return 0;
} }
static int ctrl_cmd_del_client(struct sockaddr_qrtr *from, static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
@ -404,7 +430,7 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
struct list_head *li; struct list_head *li;
void __rcu **slot; void __rcu **slot;
struct kvec iv; struct kvec iv;
int ret = 0; int ret;
iv.iov_base = &pkt; iv.iov_base = &pkt;
iv.iov_len = sizeof(pkt); iv.iov_len = sizeof(pkt);
@ -447,6 +473,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
rcu_read_lock(); rcu_read_lock();
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
srv = radix_tree_deref_slot(slot); srv = radix_tree_deref_slot(slot);
if (!srv)
continue;
if (radix_tree_deref_retry(srv)) {
slot = radix_tree_iter_retry(&iter);
continue;
}
slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
sq.sq_family = AF_QIPCRTR; sq.sq_family = AF_QIPCRTR;
sq.sq_node = srv->node; sq.sq_node = srv->node;
@ -458,14 +492,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt));
if (ret < 0) { if (ret < 0) {
pr_err("failed to send del client cmd\n"); pr_err("failed to send del client cmd\n");
goto err_out; return ret;
} }
rcu_read_lock();
} }
err_out:
rcu_read_unlock(); rcu_read_unlock();
return ret; return 0;
} }
static int ctrl_cmd_new_server(struct sockaddr_qrtr *from, static int ctrl_cmd_new_server(struct sockaddr_qrtr *from,
@ -571,16 +605,34 @@ static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from,
rcu_read_lock(); rcu_read_lock();
radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) { radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
node = radix_tree_deref_slot(node_slot); node = radix_tree_deref_slot(node_slot);
if (!node)
continue;
if (radix_tree_deref_retry(node)) {
node_slot = radix_tree_iter_retry(&node_iter);
continue;
}
node_slot = radix_tree_iter_resume(node_slot, &node_iter);
radix_tree_for_each_slot(srv_slot, &node->servers, radix_tree_for_each_slot(srv_slot, &node->servers,
&srv_iter, 0) { &srv_iter, 0) {
struct qrtr_server *srv; struct qrtr_server *srv;
srv = radix_tree_deref_slot(srv_slot); srv = radix_tree_deref_slot(srv_slot);
if (!srv)
continue;
if (radix_tree_deref_retry(srv)) {
srv_slot = radix_tree_iter_retry(&srv_iter);
continue;
}
if (!server_match(srv, &filter)) if (!server_match(srv, &filter))
continue; continue;
srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
rcu_read_unlock();
lookup_notify(from, srv, true); lookup_notify(from, srv, true);
rcu_read_lock();
} }
} }
rcu_read_unlock(); rcu_read_unlock();

View file

@ -514,7 +514,6 @@ enum rxrpc_call_state {
RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */ RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */
RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */ RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */
RXRPC_CALL_SERVER_SECURING, /* - server securing request connection */ RXRPC_CALL_SERVER_SECURING, /* - server securing request connection */
RXRPC_CALL_SERVER_ACCEPTING, /* - server accepting request */
RXRPC_CALL_SERVER_RECV_REQUEST, /* - server receiving request */ RXRPC_CALL_SERVER_RECV_REQUEST, /* - server receiving request */
RXRPC_CALL_SERVER_ACK_REQUEST, /* - server pending ACK of request */ RXRPC_CALL_SERVER_ACK_REQUEST, /* - server pending ACK of request */
RXRPC_CALL_SERVER_SEND_REPLY, /* - server sending reply */ RXRPC_CALL_SERVER_SEND_REPLY, /* - server sending reply */
@ -710,8 +709,8 @@ struct rxrpc_ack_summary {
enum rxrpc_command { enum rxrpc_command {
RXRPC_CMD_SEND_DATA, /* send data message */ RXRPC_CMD_SEND_DATA, /* send data message */
RXRPC_CMD_SEND_ABORT, /* request abort generation */ RXRPC_CMD_SEND_ABORT, /* request abort generation */
RXRPC_CMD_ACCEPT, /* [server] accept incoming call */
RXRPC_CMD_REJECT_BUSY, /* [server] reject a call as busy */ RXRPC_CMD_REJECT_BUSY, /* [server] reject a call as busy */
RXRPC_CMD_CHARGE_ACCEPT, /* [server] charge accept preallocation */
}; };
struct rxrpc_call_params { struct rxrpc_call_params {
@ -752,9 +751,7 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *,
struct rxrpc_sock *, struct rxrpc_sock *,
struct sk_buff *); struct sk_buff *);
void rxrpc_accept_incoming_calls(struct rxrpc_local *); void rxrpc_accept_incoming_calls(struct rxrpc_local *);
struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, unsigned long, int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long);
rxrpc_notify_rx_t);
int rxrpc_reject_call(struct rxrpc_sock *);
/* /*
* call_event.c * call_event.c

View file

@ -39,8 +39,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
unsigned int debug_id) unsigned int debug_id)
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
struct rxrpc_call *call; struct rxrpc_call *call, *xcall;
struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk)); struct rxrpc_net *rxnet = rxrpc_net(sock_net(&rx->sk));
struct rb_node *parent, **pp;
int max, tmp; int max, tmp;
unsigned int size = RXRPC_BACKLOG_MAX; unsigned int size = RXRPC_BACKLOG_MAX;
unsigned int head, tail, call_head, call_tail; unsigned int head, tail, call_head, call_tail;
@ -94,7 +95,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
} }
/* Now it gets complicated, because calls get registered with the /* Now it gets complicated, because calls get registered with the
* socket here, particularly if a user ID is preassigned by the user. * socket here, with a user ID preassigned by the user.
*/ */
call = rxrpc_alloc_call(rx, gfp, debug_id); call = rxrpc_alloc_call(rx, gfp, debug_id);
if (!call) if (!call)
@ -107,34 +108,33 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
here, (const void *)user_call_ID); here, (const void *)user_call_ID);
write_lock(&rx->call_lock); write_lock(&rx->call_lock);
/* Check the user ID isn't already in use */
pp = &rx->calls.rb_node;
parent = NULL;
while (*pp) {
parent = *pp;
xcall = rb_entry(parent, struct rxrpc_call, sock_node);
if (user_call_ID < xcall->user_call_ID)
pp = &(*pp)->rb_left;
else if (user_call_ID > xcall->user_call_ID)
pp = &(*pp)->rb_right;
else
goto id_in_use;
}
call->user_call_ID = user_call_ID;
call->notify_rx = notify_rx;
if (user_attach_call) { if (user_attach_call) {
struct rxrpc_call *xcall;
struct rb_node *parent, **pp;
/* Check the user ID isn't already in use */
pp = &rx->calls.rb_node;
parent = NULL;
while (*pp) {
parent = *pp;
xcall = rb_entry(parent, struct rxrpc_call, sock_node);
if (user_call_ID < xcall->user_call_ID)
pp = &(*pp)->rb_left;
else if (user_call_ID > xcall->user_call_ID)
pp = &(*pp)->rb_right;
else
goto id_in_use;
}
call->user_call_ID = user_call_ID;
call->notify_rx = notify_rx;
rxrpc_get_call(call, rxrpc_call_got_kernel); rxrpc_get_call(call, rxrpc_call_got_kernel);
user_attach_call(call, user_call_ID); user_attach_call(call, user_call_ID);
rxrpc_get_call(call, rxrpc_call_got_userid);
rb_link_node(&call->sock_node, parent, pp);
rb_insert_color(&call->sock_node, &rx->calls);
set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
} }
rxrpc_get_call(call, rxrpc_call_got_userid);
rb_link_node(&call->sock_node, parent, pp);
rb_insert_color(&call->sock_node, &rx->calls);
set_bit(RXRPC_CALL_HAS_USERID, &call->flags);
list_add(&call->sock_link, &rx->sock_calls); list_add(&call->sock_link, &rx->sock_calls);
write_unlock(&rx->call_lock); write_unlock(&rx->call_lock);
@ -157,11 +157,8 @@ id_in_use:
} }
/* /*
* Preallocate sufficient service connections, calls and peers to cover the * Allocate the preallocation buffers for incoming service calls. These must
* entire backlog of a socket. When a new call comes in, if we don't have * be charged manually.
* sufficient of each available, the call gets rejected as busy or ignored.
*
* The backlog is replenished when a connection is accepted or rejected.
*/ */
int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp) int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
{ {
@ -174,13 +171,6 @@ int rxrpc_service_prealloc(struct rxrpc_sock *rx, gfp_t gfp)
rx->backlog = b; rx->backlog = b;
} }
if (rx->discard_new_call)
return 0;
while (rxrpc_service_prealloc_one(rx, b, NULL, NULL, 0, gfp,
atomic_inc_return(&rxrpc_debug_id)) == 0)
;
return 0; return 0;
} }
@ -333,6 +323,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
rxrpc_see_call(call); rxrpc_see_call(call);
call->conn = conn; call->conn = conn;
call->security = conn->security; call->security = conn->security;
call->security_ix = conn->security_ix;
call->peer = rxrpc_get_peer(conn->params.peer); call->peer = rxrpc_get_peer(conn->params.peer);
call->cong_cwnd = call->peer->cong_cwnd; call->cong_cwnd = call->peer->cong_cwnd;
return call; return call;
@ -402,8 +393,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
if (rx->notify_new_call) if (rx->notify_new_call)
rx->notify_new_call(&rx->sk, call, call->user_call_ID); rx->notify_new_call(&rx->sk, call, call->user_call_ID);
else
sk_acceptq_added(&rx->sk);
spin_lock(&conn->state_lock); spin_lock(&conn->state_lock);
switch (conn->state) { switch (conn->state) {
@ -415,12 +404,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
case RXRPC_CONN_SERVICE: case RXRPC_CONN_SERVICE:
write_lock(&call->state_lock); write_lock(&call->state_lock);
if (call->state < RXRPC_CALL_COMPLETE) { if (call->state < RXRPC_CALL_COMPLETE)
if (rx->discard_new_call) call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
else
call->state = RXRPC_CALL_SERVER_ACCEPTING;
}
write_unlock(&call->state_lock); write_unlock(&call->state_lock);
break; break;
@ -440,9 +425,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
rxrpc_send_ping(call, skb); rxrpc_send_ping(call, skb);
if (call->state == RXRPC_CALL_SERVER_ACCEPTING)
rxrpc_notify_socket(call);
/* We have to discard the prealloc queue's ref here and rely on a /* We have to discard the prealloc queue's ref here and rely on a
* combination of the RCU read lock and refs held either by the socket * combination of the RCU read lock and refs held either by the socket
* (recvmsg queue, to-be-accepted queue or user ID tree) or the kernel * (recvmsg queue, to-be-accepted queue or user ID tree) or the kernel
@ -460,187 +442,18 @@ no_call:
} }
/* /*
* handle acceptance of a call by userspace * Charge up socket with preallocated calls, attaching user call IDs.
* - assign the user call ID to the call at the front of the queue
* - called with the socket locked.
*/ */
struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx, int rxrpc_user_charge_accept(struct rxrpc_sock *rx, unsigned long user_call_ID)
unsigned long user_call_ID,
rxrpc_notify_rx_t notify_rx)
__releases(&rx->sk.sk_lock.slock)
__acquires(call->user_mutex)
{ {
struct rxrpc_call *call; struct rxrpc_backlog *b = rx->backlog;
struct rb_node *parent, **pp;
int ret;
_enter(",%lx", user_call_ID); if (rx->sk.sk_state == RXRPC_CLOSE)
return -ESHUTDOWN;
ASSERT(!irqs_disabled()); return rxrpc_service_prealloc_one(rx, b, NULL, NULL, user_call_ID,
GFP_KERNEL,
write_lock(&rx->call_lock); atomic_inc_return(&rxrpc_debug_id));
if (list_empty(&rx->to_be_accepted)) {
write_unlock(&rx->call_lock);
release_sock(&rx->sk);
kleave(" = -ENODATA [empty]");
return ERR_PTR(-ENODATA);
}
/* check the user ID isn't already in use */
pp = &rx->calls.rb_node;
parent = NULL;
while (*pp) {
parent = *pp;
call = rb_entry(parent, struct rxrpc_call, sock_node);
if (user_call_ID < call->user_call_ID)
pp = &(*pp)->rb_left;
else if (user_call_ID > call->user_call_ID)
pp = &(*pp)->rb_right;
else
goto id_in_use;
}
/* Dequeue the first call and check it's still valid. We gain
* responsibility for the queue's reference.
*/
call = list_entry(rx->to_be_accepted.next,
struct rxrpc_call, accept_link);
write_unlock(&rx->call_lock);
/* We need to gain the mutex from the interrupt handler without
* upsetting lockdep, so we have to release it there and take it here.
* We are, however, still holding the socket lock, so other accepts
* must wait for us and no one can add the user ID behind our backs.
*/
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
release_sock(&rx->sk);
kleave(" = -ERESTARTSYS");
return ERR_PTR(-ERESTARTSYS);
}
write_lock(&rx->call_lock);
list_del_init(&call->accept_link);
sk_acceptq_removed(&rx->sk);
rxrpc_see_call(call);
/* Find the user ID insertion point. */
pp = &rx->calls.rb_node;
parent = NULL;
while (*pp) {
parent = *pp;
call = rb_entry(parent, struct rxrpc_call, sock_node);
if (user_call_ID < call->user_call_ID)
pp = &(*pp)->rb_left;
else if (user_call_ID > call->user_call_ID)
pp = &(*pp)->rb_right;
else
BUG();
}
write_lock_bh(&call->state_lock);
switch (call->state) {
case RXRPC_CALL_SERVER_ACCEPTING:
call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
break;
case RXRPC_CALL_COMPLETE:
ret = call->error;
goto out_release;
default:
BUG();
}
/* formalise the acceptance */
call->notify_rx = notify_rx;
call->user_call_ID = user_call_ID;
rxrpc_get_call(call, rxrpc_call_got_userid);
rb_link_node(&call->sock_node, parent, pp);
rb_insert_color(&call->sock_node, &rx->calls);
if (test_and_set_bit(RXRPC_CALL_HAS_USERID, &call->flags))
BUG();
write_unlock_bh(&call->state_lock);
write_unlock(&rx->call_lock);
rxrpc_notify_socket(call);
rxrpc_service_prealloc(rx, GFP_KERNEL);
release_sock(&rx->sk);
_leave(" = %p{%d}", call, call->debug_id);
return call;
out_release:
_debug("release %p", call);
write_unlock_bh(&call->state_lock);
write_unlock(&rx->call_lock);
rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put);
goto out;
id_in_use:
ret = -EBADSLT;
write_unlock(&rx->call_lock);
out:
rxrpc_service_prealloc(rx, GFP_KERNEL);
release_sock(&rx->sk);
_leave(" = %d", ret);
return ERR_PTR(ret);
}
/*
* Handle rejection of a call by userspace
* - reject the call at the front of the queue
*/
int rxrpc_reject_call(struct rxrpc_sock *rx)
{
struct rxrpc_call *call;
bool abort = false;
int ret;
_enter("");
ASSERT(!irqs_disabled());
write_lock(&rx->call_lock);
if (list_empty(&rx->to_be_accepted)) {
write_unlock(&rx->call_lock);
return -ENODATA;
}
/* Dequeue the first call and check it's still valid. We gain
* responsibility for the queue's reference.
*/
call = list_entry(rx->to_be_accepted.next,
struct rxrpc_call, accept_link);
list_del_init(&call->accept_link);
sk_acceptq_removed(&rx->sk);
rxrpc_see_call(call);
write_lock_bh(&call->state_lock);
switch (call->state) {
case RXRPC_CALL_SERVER_ACCEPTING:
__rxrpc_abort_call("REJ", call, 1, RX_USER_ABORT, -ECONNABORTED);
abort = true;
fallthrough;
case RXRPC_CALL_COMPLETE:
ret = call->error;
goto out_discard;
default:
BUG();
}
out_discard:
write_unlock_bh(&call->state_lock);
write_unlock(&rx->call_lock);
if (abort) {
rxrpc_send_abort_packet(call);
rxrpc_release_call(rx, call);
rxrpc_put_call(call, rxrpc_call_put);
}
rxrpc_service_prealloc(rx, GFP_KERNEL);
_leave(" = %d", ret);
return ret;
} }
/* /*

View file

@ -23,7 +23,6 @@ const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
[RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl", [RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl",
[RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc", [RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc",
[RXRPC_CALL_SERVER_SECURING] = "SvSecure", [RXRPC_CALL_SERVER_SECURING] = "SvSecure",
[RXRPC_CALL_SERVER_ACCEPTING] = "SvAccept",
[RXRPC_CALL_SERVER_RECV_REQUEST] = "SvRcvReq", [RXRPC_CALL_SERVER_RECV_REQUEST] = "SvRcvReq",
[RXRPC_CALL_SERVER_ACK_REQUEST] = "SvAckReq", [RXRPC_CALL_SERVER_ACK_REQUEST] = "SvAckReq",
[RXRPC_CALL_SERVER_SEND_REPLY] = "SvSndRpl", [RXRPC_CALL_SERVER_SEND_REPLY] = "SvSndRpl",
@ -393,9 +392,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
call->call_id = sp->hdr.callNumber; call->call_id = sp->hdr.callNumber;
call->service_id = sp->hdr.serviceId; call->service_id = sp->hdr.serviceId;
call->cid = sp->hdr.cid; call->cid = sp->hdr.cid;
call->state = RXRPC_CALL_SERVER_ACCEPTING; call->state = RXRPC_CALL_SERVER_SECURING;
if (sp->hdr.securityIndex > 0)
call->state = RXRPC_CALL_SERVER_SECURING;
call->cong_tstamp = skb->tstamp; call->cong_tstamp = skb->tstamp;
/* Set the channel for this call. We don't get channel_lock as we're /* Set the channel for this call. We don't get channel_lock as we're

View file

@ -270,7 +270,7 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
if (call) { if (call) {
write_lock_bh(&call->state_lock); write_lock_bh(&call->state_lock);
if (call->state == RXRPC_CALL_SERVER_SECURING) { if (call->state == RXRPC_CALL_SERVER_SECURING) {
call->state = RXRPC_CALL_SERVER_ACCEPTING; call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
rxrpc_notify_socket(call); rxrpc_notify_socket(call);
} }
write_unlock_bh(&call->state_lock); write_unlock_bh(&call->state_lock);
@ -342,18 +342,18 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret; return ret;
spin_lock(&conn->bundle->channel_lock); spin_lock(&conn->bundle->channel_lock);
spin_lock(&conn->state_lock); spin_lock_bh(&conn->state_lock);
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) { if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE; conn->state = RXRPC_CONN_SERVICE;
spin_unlock(&conn->state_lock); spin_unlock_bh(&conn->state_lock);
for (loop = 0; loop < RXRPC_MAXCALLS; loop++) for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
rxrpc_call_is_secure( rxrpc_call_is_secure(
rcu_dereference_protected( rcu_dereference_protected(
conn->channels[loop].call, conn->channels[loop].call,
lockdep_is_held(&conn->bundle->channel_lock))); lockdep_is_held(&conn->bundle->channel_lock)));
} else { } else {
spin_unlock(&conn->state_lock); spin_unlock_bh(&conn->state_lock);
} }
spin_unlock(&conn->bundle->channel_lock); spin_unlock(&conn->bundle->channel_lock);

View file

@ -903,7 +903,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
_enter(""); _enter("");
if (optlen <= 0 || optlen > PAGE_SIZE - 1) if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
return -EINVAL; return -EINVAL;
description = memdup_sockptr_nul(optval, optlen); description = memdup_sockptr_nul(optval, optlen);
@ -940,7 +940,7 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
if (IS_ERR(description)) if (IS_ERR(description))
return PTR_ERR(description); return PTR_ERR(description);
key = request_key_net(&key_type_keyring, description, sock_net(&rx->sk), NULL); key = request_key(&key_type_keyring, description, NULL);
if (IS_ERR(key)) { if (IS_ERR(key)) {
kfree(description); kfree(description);
_leave(" = %ld", PTR_ERR(key)); _leave(" = %ld", PTR_ERR(key));
@ -1072,7 +1072,7 @@ static long rxrpc_read(const struct key *key,
switch (token->security_index) { switch (token->security_index) {
case RXRPC_SECURITY_RXKAD: case RXRPC_SECURITY_RXKAD:
toksize += 9 * 4; /* viceid, kvno, key*2 + len, begin, toksize += 8 * 4; /* viceid, kvno, key*2, begin,
* end, primary, tktlen */ * end, primary, tktlen */
toksize += RND(token->kad->ticket_len); toksize += RND(token->kad->ticket_len);
break; break;
@ -1107,7 +1107,8 @@ static long rxrpc_read(const struct key *key,
break; break;
default: /* we have a ticket we can't encode */ default: /* we have a ticket we can't encode */
BUG(); pr_err("Unsupported key token type (%u)\n",
token->security_index);
continue; continue;
} }
@ -1138,6 +1139,14 @@ static long rxrpc_read(const struct key *key,
memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \ memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
xdr += (_l + 3) >> 2; \ xdr += (_l + 3) >> 2; \
} while(0) } while(0)
#define ENCODE_BYTES(l, s) \
do { \
u32 _l = (l); \
memcpy(xdr, (s), _l); \
if (_l & 3) \
memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
xdr += (_l + 3) >> 2; \
} while(0)
#define ENCODE64(x) \ #define ENCODE64(x) \
do { \ do { \
__be64 y = cpu_to_be64(x); \ __be64 y = cpu_to_be64(x); \
@ -1165,7 +1174,7 @@ static long rxrpc_read(const struct key *key,
case RXRPC_SECURITY_RXKAD: case RXRPC_SECURITY_RXKAD:
ENCODE(token->kad->vice_id); ENCODE(token->kad->vice_id);
ENCODE(token->kad->kvno); ENCODE(token->kad->kvno);
ENCODE_DATA(8, token->kad->session_key); ENCODE_BYTES(8, token->kad->session_key);
ENCODE(token->kad->start); ENCODE(token->kad->start);
ENCODE(token->kad->expiry); ENCODE(token->kad->expiry);
ENCODE(token->kad->primary_flag); ENCODE(token->kad->primary_flag);
@ -1215,7 +1224,6 @@ static long rxrpc_read(const struct key *key,
break; break;
default: default:
BUG();
break; break;
} }

View file

@ -178,37 +178,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
return ret; return ret;
} }
/*
* Pass back notification of a new call. The call is added to the
* to-be-accepted list. This means that the next call to be accepted might not
* be the last call seen awaiting acceptance, but unless we leave this on the
* front of the queue and block all other messages until someone gives us a
* user_ID for it, there's not a lot we can do.
*/
static int rxrpc_recvmsg_new_call(struct rxrpc_sock *rx,
struct rxrpc_call *call,
struct msghdr *msg, int flags)
{
int tmp = 0, ret;
ret = put_cmsg(msg, SOL_RXRPC, RXRPC_NEW_CALL, 0, &tmp);
if (ret == 0 && !(flags & MSG_PEEK)) {
_debug("to be accepted");
write_lock_bh(&rx->recvmsg_lock);
list_del_init(&call->recvmsg_link);
write_unlock_bh(&rx->recvmsg_lock);
rxrpc_get_call(call, rxrpc_call_got);
write_lock(&rx->call_lock);
list_add_tail(&call->accept_link, &rx->to_be_accepted);
write_unlock(&rx->call_lock);
}
trace_rxrpc_recvmsg(call, rxrpc_recvmsg_to_be_accepted, 1, 0, 0, ret);
return ret;
}
/* /*
* End the packet reception phase. * End the packet reception phase.
*/ */
@ -630,9 +599,6 @@ try_again:
} }
switch (READ_ONCE(call->state)) { switch (READ_ONCE(call->state)) {
case RXRPC_CALL_SERVER_ACCEPTING:
ret = rxrpc_recvmsg_new_call(rx, call, msg, flags);
break;
case RXRPC_CALL_CLIENT_RECV_REPLY: case RXRPC_CALL_CLIENT_RECV_REPLY:
case RXRPC_CALL_SERVER_RECV_REQUEST: case RXRPC_CALL_SERVER_RECV_REQUEST:
case RXRPC_CALL_SERVER_ACK_REQUEST: case RXRPC_CALL_SERVER_ACK_REQUEST:
@ -728,7 +694,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
call->debug_id, rxrpc_call_states[call->state], call->debug_id, rxrpc_call_states[call->state],
iov_iter_count(iter), want_more); iov_iter_count(iter), want_more);
ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_ACCEPTING); ASSERTCMP(call->state, !=, RXRPC_CALL_SERVER_SECURING);
mutex_lock(&call->user_mutex); mutex_lock(&call->user_mutex);

View file

@ -530,10 +530,10 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
return -EINVAL; return -EINVAL;
break; break;
case RXRPC_ACCEPT: case RXRPC_CHARGE_ACCEPT:
if (p->command != RXRPC_CMD_SEND_DATA) if (p->command != RXRPC_CMD_SEND_DATA)
return -EINVAL; return -EINVAL;
p->command = RXRPC_CMD_ACCEPT; p->command = RXRPC_CMD_CHARGE_ACCEPT;
if (len != 0) if (len != 0)
return -EINVAL; return -EINVAL;
break; break;
@ -659,16 +659,12 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
if (ret < 0) if (ret < 0)
goto error_release_sock; goto error_release_sock;
if (p.command == RXRPC_CMD_ACCEPT) { if (p.command == RXRPC_CMD_CHARGE_ACCEPT) {
ret = -EINVAL; ret = -EINVAL;
if (rx->sk.sk_state != RXRPC_SERVER_LISTENING) if (rx->sk.sk_state != RXRPC_SERVER_LISTENING)
goto error_release_sock; goto error_release_sock;
call = rxrpc_accept_call(rx, p.call.user_call_ID, NULL); ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID);
/* The socket is now unlocked. */ goto error_release_sock;
if (IS_ERR(call))
return PTR_ERR(call);
ret = 0;
goto out_put_unlock;
} }
call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID); call = rxrpc_find_call_by_user_ID(rx, p.call.user_call_ID);
@ -690,7 +686,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
case RXRPC_CALL_CLIENT_AWAIT_CONN: case RXRPC_CALL_CLIENT_AWAIT_CONN:
case RXRPC_CALL_SERVER_PREALLOC: case RXRPC_CALL_SERVER_PREALLOC:
case RXRPC_CALL_SERVER_SECURING: case RXRPC_CALL_SERVER_SECURING:
case RXRPC_CALL_SERVER_ACCEPTING:
rxrpc_put_call(call, rxrpc_call_put); rxrpc_put_call(call, rxrpc_call_put);
ret = -EBUSY; ret = -EBUSY;
goto error_release_sock; goto error_release_sock;

View file

@ -494,6 +494,7 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
out_err: out_err:
/* Clean up any successful allocations */ /* Clean up any successful allocations */
sctp_auth_destroy_hmacs(ep->auth_hmacs); sctp_auth_destroy_hmacs(ep->auth_hmacs);
ep->auth_hmacs = NULL;
return -ENOMEM; return -ENOMEM;
} }

View file

@ -4259,6 +4259,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
return err; return err;
if (key.idx < 0)
return -EINVAL;
if (info->attrs[NL80211_ATTR_MAC]) if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);