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:
commit
9d49aea13f
|
@ -1460,6 +1460,11 @@ S: Odd Fixes
|
|||
F: drivers/amba/
|
||||
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
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
S: Odd Fixes
|
||||
|
|
|
@ -150,7 +150,7 @@ static int xen_starting_cpu(unsigned int cpu)
|
|||
pr_info("Xen: initializing cpu%d\n", 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);
|
||||
|
||||
err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu),
|
||||
|
|
|
@ -788,7 +788,7 @@ SYM_FUNC_START_LOCAL(__xts_crypt8)
|
|||
|
||||
0: mov bskey, x21
|
||||
mov rounds, x22
|
||||
br x7
|
||||
br x16
|
||||
SYM_FUNC_END(__xts_crypt8)
|
||||
|
||||
.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
|
||||
ld1 {v25.16b}, [x24]
|
||||
|
||||
99: adr x7, \do8
|
||||
99: adr x16, \do8
|
||||
bl __xts_crypt8
|
||||
|
||||
ldp q16, q17, [sp, #.Lframe_local_offset]
|
||||
|
|
|
@ -176,6 +176,8 @@ void
|
|||
nouveau_mem_del(struct ttm_mem_reg *reg)
|
||||
{
|
||||
struct nouveau_mem *mem = nouveau_mem(reg);
|
||||
if (!mem)
|
||||
return;
|
||||
nouveau_mem_fini(mem);
|
||||
kfree(reg->mm_node);
|
||||
reg->mm_node = NULL;
|
||||
|
|
|
@ -3149,6 +3149,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
|
|||
case 0x168: device->chip = &nv168_chipset; break;
|
||||
default:
|
||||
nvdev_error(device, "unknown chipset (%08x)\n", boot0);
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
@ -998,6 +998,8 @@ static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port,
|
|||
*/
|
||||
static u16 vsc9959_wm_enc(u16 value)
|
||||
{
|
||||
WARN_ON(value >= 16 * BIT(8));
|
||||
|
||||
if (value >= BIT(8))
|
||||
return BIT(8) | (value / 16);
|
||||
|
||||
|
|
|
@ -1049,6 +1049,8 @@ static int vsc9953_prevalidate_phy_mode(struct ocelot *ocelot, int port,
|
|||
*/
|
||||
static u16 vsc9953_wm_enc(u16 value)
|
||||
{
|
||||
WARN_ON(value >= 16 * BIT(9));
|
||||
|
||||
if (value >= BIT(9))
|
||||
return BIT(9) | (value / 16);
|
||||
|
||||
|
|
|
@ -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];
|
||||
int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
|
||||
int pause_start, pause_stop;
|
||||
int atop_wm;
|
||||
int atop, atop_tot;
|
||||
|
||||
if (port == ocelot->npi) {
|
||||
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,
|
||||
pause_stop);
|
||||
|
||||
/* Tail dropping watermark */
|
||||
atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) /
|
||||
/* Tail dropping watermarks */
|
||||
atop_tot = (ocelot->shared_queue_sz - 9 * maxlen) /
|
||||
OCELOT_BUFFER_CELL_SZ;
|
||||
ocelot_write_rix(ocelot, ocelot->ops->wm_enc(9 * maxlen),
|
||||
SYS_ATOP, port);
|
||||
ocelot_write(ocelot, ocelot->ops->wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
|
||||
atop = (9 * maxlen) / OCELOT_BUFFER_CELL_SZ;
|
||||
ocelot_write_rix(ocelot, ocelot->ops->wm_enc(atop), SYS_ATOP, port);
|
||||
ocelot_write(ocelot, ocelot->ops->wm_enc(atop_tot), SYS_ATOP_TOT_CFG);
|
||||
}
|
||||
EXPORT_SYMBOL(ocelot_port_set_maxlen);
|
||||
|
||||
|
|
|
@ -754,6 +754,8 @@ static int ocelot_reset(struct ocelot *ocelot)
|
|||
*/
|
||||
static u16 ocelot_wm_enc(u16 value)
|
||||
{
|
||||
WARN_ON(value >= 16 * BIT(8));
|
||||
|
||||
if (value >= BIT(8))
|
||||
return BIT(8) | (value / 16);
|
||||
|
||||
|
|
|
@ -2055,11 +2055,18 @@ static void rtl_release_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. */
|
||||
if (tp->rtl_fw) {
|
||||
rtl_fw_write_firmware(tp, tp->rtl_fw);
|
||||
/* At least one firmware doesn't reset tp->ocp_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1077,6 +1077,7 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
|
|||
struct macsec_rx_sa *rx_sa;
|
||||
struct macsec_rxh_data *rxd;
|
||||
struct macsec_dev *macsec;
|
||||
unsigned int len;
|
||||
sci_t sci;
|
||||
u32 hdr_pn;
|
||||
bool cbit;
|
||||
|
@ -1232,9 +1233,10 @@ deliver:
|
|||
macsec_rxsc_put(rx_sc);
|
||||
|
||||
skb_orphan(skb);
|
||||
len = skb->len;
|
||||
ret = gro_cells_receive(&macsec->gro_cells, skb);
|
||||
if (ret == NET_RX_SUCCESS)
|
||||
count_rx(dev, skb->len);
|
||||
count_rx(dev, len);
|
||||
else
|
||||
macsec->secy.netdev->stats.rx_dropped++;
|
||||
|
||||
|
|
|
@ -1375,6 +1375,7 @@ static const struct usb_device_id products[] = {
|
|||
{QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */
|
||||
{QMI_FIXED_INTF(0x0489, 0xe0b4, 0)}, /* Foxconn T77W968 LTE */
|
||||
{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 */
|
||||
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
|
||||
|
|
|
@ -274,12 +274,20 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
|
|||
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);
|
||||
memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
|
||||
ret = get_registers(dev, IDR, sizeof(node_id), 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)
|
||||
|
|
|
@ -115,6 +115,10 @@ static struct quirk_entry quirk_asus_vendor_backlight = {
|
|||
.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)
|
||||
{
|
||||
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,
|
||||
},
|
||||
{
|
||||
.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,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
@ -365,6 +365,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
|
|||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
if (asus->driver->quirks->use_kbd_dock_devid) {
|
||||
result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
|
||||
if (result >= 0) {
|
||||
input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
|
||||
|
@ -372,6 +373,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
|
|||
} else if (result != -ENODEV) {
|
||||
pr_err("Error checking for keyboard-dock: %d\n", result);
|
||||
}
|
||||
}
|
||||
|
||||
err = input_register_device(asus->inputdev);
|
||||
if (err)
|
||||
|
@ -2115,7 +2117,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
|
|||
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,
|
||||
ASUS_WMI_DEVID_KBD_DOCK);
|
||||
if (result >= 0) {
|
||||
|
|
|
@ -33,6 +33,7 @@ struct quirk_entry {
|
|||
bool wmi_backlight_native;
|
||||
bool wmi_backlight_set_devstate;
|
||||
bool wmi_force_als_set;
|
||||
bool use_kbd_dock_devid;
|
||||
int wapf;
|
||||
/*
|
||||
* For machines with AMD graphic chips, it will send out WMI event
|
||||
|
|
|
@ -30,9 +30,7 @@ config IFCVF
|
|||
be called ifcvf.
|
||||
|
||||
config MLX5_VDPA
|
||||
bool "MLX5 VDPA support library for ConnectX devices"
|
||||
depends on MLX5_CORE
|
||||
default n
|
||||
bool
|
||||
help
|
||||
Support library for Mellanox VDPA drivers. Provides code that is
|
||||
common for all types of VDPA drivers. The following drivers are planned:
|
||||
|
@ -40,7 +38,8 @@ config MLX5_VDPA
|
|||
|
||||
config MLX5_VDPA_NET
|
||||
tristate "vDPA driver for ConnectX devices"
|
||||
depends on MLX5_VDPA
|
||||
select MLX5_VDPA
|
||||
depends on MLX5_CORE
|
||||
default n
|
||||
help
|
||||
VDPA network driver for ConnectX6 and newer. Provides offloading
|
||||
|
|
|
@ -1133,15 +1133,17 @@ static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
|
|||
if (!mvq->initialized)
|
||||
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)
|
||||
return;
|
||||
|
||||
if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
|
||||
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)
|
||||
|
@ -1411,8 +1413,14 @@ static int mlx5_vdpa_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa
|
|||
struct mlx5_virtq_attr attr;
|
||||
int err;
|
||||
|
||||
if (!mvq->initialized)
|
||||
return -EAGAIN;
|
||||
/* If the virtq object was destroyed, use the value saved at
|
||||
* 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);
|
||||
if (err) {
|
||||
|
|
|
@ -565,6 +565,9 @@ static int vhost_vdpa_map(struct vhost_vdpa *v,
|
|||
perm_to_iommu_flags(perm));
|
||||
}
|
||||
|
||||
if (r)
|
||||
vhost_iotlb_del_range(dev->iotlb, iova, iova + size - 1);
|
||||
|
||||
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_iotlb *iotlb = dev->iotlb;
|
||||
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 long npages, cur_base, map_pfn, last_pfn = 0;
|
||||
unsigned long locked, lock_limit, pinned, i;
|
||||
unsigned long map_pfn, last_pfn = 0;
|
||||
unsigned long npages, lock_limit;
|
||||
unsigned long i, nmap = 0;
|
||||
u64 iova = msg->iova;
|
||||
long pinned;
|
||||
int ret = 0;
|
||||
|
||||
if (vhost_iotlb_itree_first(iotlb, msg->iova,
|
||||
msg->iova + msg->size - 1))
|
||||
return -EEXIST;
|
||||
|
||||
page_list = (struct page **) __get_free_page(GFP_KERNEL);
|
||||
if (!page_list)
|
||||
return -ENOMEM;
|
||||
|
||||
if (msg->perm & VHOST_ACCESS_WO)
|
||||
gup_flags |= FOLL_WRITE;
|
||||
|
||||
|
@ -614,61 +615,86 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v,
|
|||
if (!npages)
|
||||
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);
|
||||
|
||||
locked = atomic64_add_return(npages, &dev->mm->pinned_vm);
|
||||
lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
|
||||
|
||||
if (locked > lock_limit) {
|
||||
if (npages + atomic64_read(&dev->mm->pinned_vm) > lock_limit) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
pinned = pin_user_pages(msg->uaddr & PAGE_MASK, npages, gup_flags,
|
||||
page_list, vmas);
|
||||
if (npages != pinned) {
|
||||
if (pinned < 0) {
|
||||
ret = pinned;
|
||||
} else {
|
||||
unpin_user_pages(page_list, pinned);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
cur_base = msg->uaddr & PAGE_MASK;
|
||||
iova &= PAGE_MASK;
|
||||
|
||||
while (npages) {
|
||||
pinned = min_t(unsigned long, npages, list_size);
|
||||
ret = pin_user_pages(cur_base, pinned,
|
||||
gup_flags, page_list, NULL);
|
||||
if (ret != pinned)
|
||||
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]);
|
||||
/* One more iteration to avoid extra vdpa_map() call out of loop. */
|
||||
for (i = 0; i <= npages; i++) {
|
||||
unsigned long this_pfn;
|
||||
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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
cur_base += ret << PAGE_SHIFT;
|
||||
npages -= ret;
|
||||
}
|
||||
|
||||
/* Pin the rest chunk */
|
||||
ret = vhost_vdpa_map(v, iova, (last_pfn - map_pfn + 1) << PAGE_SHIFT,
|
||||
map_pfn << PAGE_SHIFT, msg->perm);
|
||||
WARN_ON(nmap != npages);
|
||||
out:
|
||||
if (ret) {
|
||||
if (ret)
|
||||
vhost_vdpa_unmap(v, msg->iova, msg->size);
|
||||
atomic64_sub(npages, &dev->mm->pinned_vm);
|
||||
}
|
||||
unlock:
|
||||
mmap_read_unlock(dev->mm);
|
||||
free_page((unsigned long)page_list);
|
||||
free:
|
||||
kvfree(vmas);
|
||||
kvfree(page_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -810,6 +836,7 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
|
|||
|
||||
err_init_iotlb:
|
||||
vhost_dev_cleanup(&v->vdev);
|
||||
kfree(vqs);
|
||||
err:
|
||||
atomic_dec(&v->opened);
|
||||
return r;
|
||||
|
|
|
@ -1290,6 +1290,11 @@ static bool vq_access_ok(struct vhost_virtqueue *vq, unsigned int num,
|
|||
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)) &&
|
||||
access_ok(avail, vhost_get_avail_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);
|
||||
|
||||
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. */
|
||||
/* Caller should have vq mutex and device mutex */
|
||||
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,
|
||||
vhost_has_feature(vq, VHOST_F_LOG_ALL)) &&
|
||||
(!vq->log_used || log_access_ok(log_base, vq->log_addr,
|
||||
vhost_get_used_size(vq, vq->num)));
|
||||
vq_log_used_access_ok(vq, log_base, vq->log_used, vq->log_addr);
|
||||
}
|
||||
|
||||
/* 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))
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
|
||||
|
@ -1516,10 +1530,9 @@ static long vhost_vring_set_addr(struct vhost_dev *d,
|
|||
return -EINVAL;
|
||||
|
||||
/* Also validate log access for used ring if enabled. */
|
||||
if ((a.flags & (0x1 << VHOST_VRING_F_LOG)) &&
|
||||
!log_access_ok(vq->log_base, a.log_guest_addr,
|
||||
sizeof *vq->used +
|
||||
vq->num * sizeof *vq->used->ring))
|
||||
if (!vq_log_used_access_ok(vq, vq->log_base,
|
||||
a.flags & (0x1 << VHOST_VRING_F_LOG),
|
||||
a.log_guest_addr))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,12 +35,6 @@
|
|||
|
||||
#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 struct newport_regs *npregs;
|
||||
|
@ -522,6 +516,7 @@ static int newport_set_font(int unit, struct console_font *op)
|
|||
FNTSIZE(new_data) = size;
|
||||
FNTCHARCNT(new_data) = op->charcount;
|
||||
REFCOUNT(new_data) = 0; /* usage counter */
|
||||
FNTSUM(new_data) = 0;
|
||||
|
||||
p = new_data;
|
||||
for (i = 0; i < op->charcount; i++) {
|
||||
|
|
|
@ -272,6 +272,26 @@ config FB_PM2_FIFO_DISCONNECT
|
|||
help
|
||||
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
|
||||
bool "Acorn VIDC support"
|
||||
depends on (FB = y) && ARM && ARCH_ACORN
|
||||
|
|
|
@ -75,6 +75,7 @@ obj-$(CONFIG_FB_HIT) += hitfb.o
|
|||
obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
|
||||
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
|
||||
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
|
||||
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
|
||||
obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
|
||||
obj-$(CONFIG_FB_68328) += 68328fb.o
|
||||
obj-$(CONFIG_FB_GBE) += gbefb.o
|
||||
|
|
|
@ -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, ®s);
|
||||
|
||||
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");
|
|
@ -2299,6 +2299,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
|||
|
||||
if (font->width <= 8) {
|
||||
j = vc->vc_font.height;
|
||||
if (font->charcount * j > FNTSIZE(fontdata))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, 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) {
|
||||
j = vc->vc_font.height * 2;
|
||||
if (font->charcount * j > FNTSIZE(fontdata))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, 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;
|
||||
}
|
||||
} 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 (j = 0; j < vc->vc_font.height; j++) {
|
||||
*data++ = fontdata[0];
|
||||
|
@ -2326,6 +2335,9 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
|||
}
|
||||
} else {
|
||||
j = vc->vc_font.height * 4;
|
||||
if (font->charcount * j > FNTSIZE(fontdata))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, j);
|
||||
memset(data + j, 0, 128 - j);
|
||||
|
|
|
@ -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_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
|
||||
*/
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/font.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
#include "fbcon_rotate.h"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/fb.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/font.h>
|
||||
#include <asm/types.h>
|
||||
#include "fbcon.h"
|
||||
|
||||
|
|
|
@ -810,13 +810,31 @@ void afs_evict_inode(struct inode *inode)
|
|||
|
||||
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) {
|
||||
loff_t i_size = inode->i_size, size = op->setattr.attr->ia_size;
|
||||
if (size > i_size)
|
||||
pagecache_isize_extended(inode, i_size, size);
|
||||
loff_t size = op->setattr.attr->ia_size;
|
||||
if (size > old_i_size)
|
||||
pagecache_isize_extended(inode, old_i_size, 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_yfs_rpc = yfs_fs_setattr,
|
||||
.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))
|
||||
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) ?
|
||||
afs_file_key(attr->ia_file) : NULL),
|
||||
vnode->volume);
|
||||
if (IS_ERR(op))
|
||||
return PTR_ERR(op);
|
||||
if (IS_ERR(op)) {
|
||||
ret = PTR_ERR(op);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
afs_op_set_vnode(op, 0, vnode);
|
||||
op->setattr.attr = attr;
|
||||
|
@ -880,5 +904,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
op->file[0].update_ctime = 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -812,6 +812,7 @@ struct afs_operation {
|
|||
} store;
|
||||
struct {
|
||||
struct iattr *attr;
|
||||
loff_t old_i_size;
|
||||
} setattr;
|
||||
struct afs_acl *acl;
|
||||
struct yfs_acl *yacl;
|
||||
|
|
|
@ -738,11 +738,21 @@ static int afs_writepages_region(struct address_space *mapping,
|
|||
int afs_writepages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
struct afs_vnode *vnode = AFS_FS_I(mapping->host);
|
||||
pgoff_t start, end, next;
|
||||
int ret;
|
||||
|
||||
_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) {
|
||||
start = mapping->writeback_index;
|
||||
end = -1;
|
||||
|
@ -762,6 +772,7 @@ int afs_writepages(struct address_space *mapping,
|
|||
ret = afs_writepages_region(mapping, wbc, start, end, &next);
|
||||
}
|
||||
|
||||
up_read(&vnode->validate_lock);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "exfat_raw.h"
|
||||
#include "exfat_fs.h"
|
||||
|
||||
#define EXFAT_CACHE_VALID 0
|
||||
#define EXFAT_MAX_CACHE 16
|
||||
|
||||
struct exfat_cache {
|
||||
|
@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
|
|||
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)
|
||||
{
|
||||
return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
|
||||
|
|
|
@ -248,6 +248,8 @@ struct exfat_sb_info {
|
|||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#define EXFAT_CACHE_VALID 0
|
||||
|
||||
/*
|
||||
* EXFAT file system inode in-memory data
|
||||
*/
|
||||
|
@ -428,7 +430,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops;
|
|||
/* cache.c */
|
||||
int exfat_cache_init(void);
|
||||
void exfat_cache_shutdown(void);
|
||||
void exfat_cache_init_inode(struct inode *inode);
|
||||
void exfat_cache_inval_inode(struct inode *inode);
|
||||
int exfat_get_cluster(struct inode *inode, unsigned int cluster,
|
||||
unsigned int *fclus, unsigned int *dclus,
|
||||
|
|
|
@ -611,8 +611,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
|||
ei->i_crtime = info->crtime;
|
||||
inode->i_atime = info->atime;
|
||||
|
||||
exfat_cache_init_inode(inode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -578,7 +578,8 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
|
||||
i_pos = exfat_make_i_pos(&info);
|
||||
inode = exfat_build_inode(sb, &info, i_pos);
|
||||
if (IS_ERR(inode))
|
||||
err = PTR_ERR_OR_ZERO(inode);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
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);
|
||||
inode = exfat_build_inode(sb, &info, i_pos);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
err = PTR_ERR_OR_ZERO(inode);
|
||||
if (err)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
i_mode = inode->i_mode;
|
||||
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);
|
||||
inode = exfat_build_inode(sb, &info, i_pos);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
err = PTR_ERR_OR_ZERO(inode);
|
||||
if (err)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
inode_inc_iversion(inode);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||
|
|
|
@ -376,7 +376,6 @@ static int exfat_read_root(struct inode *inode)
|
|||
inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
|
||||
current_time(inode);
|
||||
exfat_truncate_atime(&inode->i_atime);
|
||||
exfat_cache_init_inode(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -763,6 +762,10 @@ static void exfat_inode_init_once(void *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);
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
}
|
||||
|
|
20
fs/splice.c
20
fs/splice.c
|
@ -526,6 +526,22 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
|
|||
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
|
||||
* @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))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
repeat:
|
||||
while (pipe_empty(pipe->head, pipe->tail)) {
|
||||
if (!pipe->writers)
|
||||
return 0;
|
||||
|
@ -566,6 +583,9 @@ static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_des
|
|||
pipe_wait_readable(pipe);
|
||||
}
|
||||
|
||||
if (eat_empty_buffer(pipe))
|
||||
goto repeat;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -588,7 +588,7 @@ struct drm_dsc_picture_parameter_set {
|
|||
* This structure represents the DSC PPS infoframe required to send the Picture
|
||||
* Parameter Set metadata required before enabling VESA Display Stream
|
||||
* 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.
|
||||
*
|
||||
* @pps_header: Header for PPS as per DP SDP header format of type
|
||||
|
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
#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 */
|
||||
|
|
|
@ -51,11 +51,11 @@ enum rxrpc_cmsg_type {
|
|||
RXRPC_BUSY = 6, /* -r: server busy received [terminal] */
|
||||
RXRPC_LOCAL_ERROR = 7, /* -r: local error generated [terminal] */
|
||||
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_UPGRADE_SERVICE = 11, /* s-: Request service upgrade for client call */
|
||||
RXRPC_TX_LENGTH = 12, /* s-: Total length of Tx data */
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -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 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. */
|
||||
static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr)
|
||||
{
|
||||
|
|
|
@ -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 dst_known = tnum_subreg_is_const(dst_reg->var_off);
|
||||
struct tnum var32_off = tnum_subreg(dst_reg->var_off);
|
||||
s32 smin_val = src_reg->smin_value;
|
||||
u32 umin_val = src_reg->umin_value;
|
||||
s32 smin_val = src_reg->s32_min_value;
|
||||
u32 umin_val = src_reg->u32_min_value;
|
||||
|
||||
/* Assuming scalar64_min_max_or will be called so it is safe
|
||||
* 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
|
||||
* cast result into s64.
|
||||
*/
|
||||
dst_reg->s32_min_value = dst_reg->umin_value;
|
||||
dst_reg->s32_max_value = dst_reg->umax_value;
|
||||
dst_reg->s32_min_value = dst_reg->u32_min_value;
|
||||
dst_reg->s32_max_value = dst_reg->u32_max_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/cred.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/fs_struct.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/mount.h>
|
||||
|
@ -71,6 +72,14 @@ static int call_usermodehelper_exec_async(void *data)
|
|||
flush_signal_handlers(current, 1);
|
||||
spin_unlock_irq(¤t->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
|
||||
* priority. Avoid propagating that into the userspace child.
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#define FONTDATAMAX 9216
|
||||
|
||||
static const unsigned char fontdata_10x18[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_10x18 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
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 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_10x18 = {
|
||||
|
@ -5138,7 +5137,7 @@ const struct font_desc font_10x18 = {
|
|||
.name = "10x18",
|
||||
.width = 10,
|
||||
.height = 18,
|
||||
.data = fontdata_10x18,
|
||||
.data = fontdata_10x18.data,
|
||||
#ifdef __sparc__
|
||||
.pref = 5,
|
||||
#else
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#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 '^@' */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
@ -3074,14 +3076,13 @@ static const unsigned char fontdata_6x10[] = {
|
|||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
const struct font_desc font_6x10 = {
|
||||
.idx = FONT6x10_IDX,
|
||||
.name = "6x10",
|
||||
.width = 6,
|
||||
.height = 10,
|
||||
.data = fontdata_6x10,
|
||||
.data = fontdata_6x10.data,
|
||||
.pref = 0,
|
||||
};
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#define FONTDATAMAX (11*256)
|
||||
|
||||
static const unsigned char fontdata_6x11[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_6x11 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
@ -3338,8 +3338,7 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = {
|
|||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_vga_6x11 = {
|
||||
|
@ -3347,7 +3346,7 @@ const struct font_desc font_vga_6x11 = {
|
|||
.name = "ProFont6x11",
|
||||
.width = 6,
|
||||
.height = 11,
|
||||
.data = fontdata_6x11,
|
||||
.data = fontdata_6x11.data,
|
||||
/* Try avoiding this font if possible unless on MAC */
|
||||
.pref = -2000,
|
||||
};
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#define FONTDATAMAX 3584
|
||||
|
||||
static const unsigned char fontdata_7x14[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_7x14 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
0x00, /* 0000000 */
|
||||
0x00, /* 0000000 */
|
||||
|
@ -4105,8 +4105,7 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = {
|
|||
0x00, /* 0000000 */
|
||||
0x00, /* 0000000 */
|
||||
0x00, /* 0000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_7x14 = {
|
||||
|
@ -4114,6 +4113,6 @@ const struct font_desc font_7x14 = {
|
|||
.name = "7x14",
|
||||
.width = 7,
|
||||
.height = 14,
|
||||
.data = fontdata_7x14,
|
||||
.data = fontdata_7x14.data,
|
||||
.pref = 0,
|
||||
};
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
#define FONTDATAMAX 4096
|
||||
|
||||
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_8x16 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
@ -4619,8 +4619,7 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = {
|
|||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_vga_8x16 = {
|
||||
|
@ -4628,7 +4627,7 @@ const struct font_desc font_vga_8x16 = {
|
|||
.name = "VGA8x16",
|
||||
.width = 8,
|
||||
.height = 16,
|
||||
.data = fontdata_8x16,
|
||||
.data = fontdata_8x16.data,
|
||||
.pref = 0,
|
||||
};
|
||||
EXPORT_SYMBOL(font_vga_8x16);
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
static const unsigned char fontdata_8x8[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_8x8 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
@ -2570,8 +2570,7 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = {
|
|||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_vga_8x8 = {
|
||||
|
@ -2579,6 +2578,6 @@ const struct font_desc font_vga_8x8 = {
|
|||
.name = "VGA8x8",
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
.data = fontdata_8x8,
|
||||
.data = fontdata_8x8.data,
|
||||
.pref = 0,
|
||||
};
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
#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, /* ^@ */
|
||||
/* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */
|
||||
/* 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,
|
||||
/* FE */ 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
|
||||
/* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
} };
|
||||
|
||||
const struct font_desc font_acorn_8x8 = {
|
||||
.idx = ACORN8x8_IDX,
|
||||
.name = "Acorn8x8",
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
.data = acorndata_8x8,
|
||||
.data = acorndata_8x8.data,
|
||||
#ifdef CONFIG_ARCH_ACORN
|
||||
.pref = 20,
|
||||
#else
|
||||
|
|
|
@ -43,8 +43,8 @@ __END__;
|
|||
|
||||
#define FONTDATAMAX 1536
|
||||
|
||||
static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_mini_4x6 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/*{*/
|
||||
/* Char 0: ' ' */
|
||||
0xee, /*= [*** ] */
|
||||
|
@ -2145,14 +2145,14 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
|
|||
0xee, /*= [*** ] */
|
||||
0x00, /*= [ ] */
|
||||
/*}*/
|
||||
};
|
||||
} };
|
||||
|
||||
const struct font_desc font_mini_4x6 = {
|
||||
.idx = MINI4x6_IDX,
|
||||
.name = "MINI4x6",
|
||||
.width = 4,
|
||||
.height = 6,
|
||||
.data = fontdata_mini_4x6,
|
||||
.data = fontdata_mini_4x6.data,
|
||||
.pref = 3,
|
||||
};
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
#define FONTDATAMAX 2048
|
||||
|
||||
static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_pearl8x8 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
@ -2575,14 +2575,13 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
|
|||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
0x00, /* 00000000 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
const struct font_desc font_pearl_8x8 = {
|
||||
.idx = PEARL8x8_IDX,
|
||||
.name = "PEARL8x8",
|
||||
.width = 8,
|
||||
.height = 8,
|
||||
.data = fontdata_pearl8x8,
|
||||
.data = fontdata_pearl8x8.data,
|
||||
.pref = 2,
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
#define FONTDATAMAX 11264
|
||||
|
||||
static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
|
||||
|
||||
static struct font_data fontdata_sun12x22 = {
|
||||
{ 0, 0, FONTDATAMAX, 0 }, {
|
||||
/* 0 0x00 '^@' */
|
||||
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 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_sun_12x22 = {
|
||||
|
@ -6157,7 +6156,7 @@ const struct font_desc font_sun_12x22 = {
|
|||
.name = "SUN12x22",
|
||||
.width = 12,
|
||||
.height = 22,
|
||||
.data = fontdata_sun12x22,
|
||||
.data = fontdata_sun12x22.data,
|
||||
#ifdef __sparc__
|
||||
.pref = 5,
|
||||
#else
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#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,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,
|
||||
|
@ -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,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,
|
||||
};
|
||||
} };
|
||||
|
||||
const struct font_desc font_sun_8x16 = {
|
||||
.idx = SUN8x16_IDX,
|
||||
.name = "SUN8x16",
|
||||
.width = 8,
|
||||
.height = 16,
|
||||
.data = fontdata_sun8x16,
|
||||
.data = fontdata_sun8x16.data,
|
||||
#ifdef __sparc__
|
||||
.pref = 10,
|
||||
#else
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#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, 0x7f, 0xfc, 0x7f, 0xfc,
|
||||
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, /* 255 */
|
||||
|
||||
};
|
||||
} };
|
||||
|
||||
|
||||
const struct font_desc font_ter_16x32 = {
|
||||
|
@ -2063,7 +2062,7 @@ const struct font_desc font_ter_16x32 = {
|
|||
.name = "TER16x32",
|
||||
.width = 16,
|
||||
.height = 32,
|
||||
.data = fontdata_ter16x32,
|
||||
.data = fontdata_ter16x32.data,
|
||||
#ifdef __sparc__
|
||||
.pref = 5,
|
||||
#else
|
||||
|
|
41
mm/memory.c
41
mm/memory.c
|
@ -806,8 +806,6 @@ copy_present_page(struct mm_struct *dst_mm, struct mm_struct *src_mm,
|
|||
return 1;
|
||||
|
||||
/*
|
||||
* The trick starts.
|
||||
*
|
||||
* What we want to do is to check whether this page may
|
||||
* have been pinned by the parent process. If so,
|
||||
* 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
|
||||
* future.
|
||||
*
|
||||
* To achieve this, we do the following:
|
||||
*
|
||||
* 1. Write-protect the pte if it's writable. This is
|
||||
* to protect concurrent write fast-gup with
|
||||
* 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.
|
||||
* The page pinning checks are just "has this mm ever
|
||||
* seen pinning", along with the (inexact) check of
|
||||
* the page count. That might give false positives for
|
||||
* for pinning, but it will work correctly.
|
||||
*/
|
||||
if (likely(!atomic_read(&src_mm->has_pinned)))
|
||||
return 1;
|
||||
if (likely(!page_maybe_dma_pinned(page)))
|
||||
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;
|
||||
if (!new_page)
|
||||
return -EAGAIN;
|
||||
|
|
|
@ -380,6 +380,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
|
|||
u32 filter_mask, const struct net_device *dev)
|
||||
{
|
||||
u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
|
||||
struct nlattr *af = NULL;
|
||||
struct net_bridge *br;
|
||||
struct ifinfomsg *hdr;
|
||||
struct nlmsghdr *nlh;
|
||||
|
@ -423,11 +424,18 @@ static int br_fill_ifinfo(struct sk_buff *skb,
|
|||
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 */
|
||||
if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
|
||||
(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
|
||||
struct net_bridge_vlan_group *vg;
|
||||
struct nlattr *af;
|
||||
int err;
|
||||
|
||||
/* 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();
|
||||
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)
|
||||
err = br_fill_ifvlaninfo_compressed(skb, vg);
|
||||
else
|
||||
|
@ -456,32 +459,25 @@ static int br_fill_ifinfo(struct sk_buff *skb,
|
|||
rcu_read_unlock();
|
||||
if (err)
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(skb, af);
|
||||
}
|
||||
|
||||
if (filter_mask & RTEXT_FILTER_MRP) {
|
||||
struct nlattr *af;
|
||||
int err;
|
||||
|
||||
if (!br_mrp_enabled(br) || port)
|
||||
goto done;
|
||||
|
||||
af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
|
||||
if (!af)
|
||||
goto nla_put_failure;
|
||||
|
||||
rcu_read_lock();
|
||||
err = br_mrp_fill_info(skb, br);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (err)
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(skb, af);
|
||||
}
|
||||
|
||||
done:
|
||||
if (af)
|
||||
nla_nest_end(skb, af);
|
||||
nlmsg_end(skb, nlh);
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
/* 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
|
||||
if (sk && sk->sk_prot == &tcp_prot && sk->sk_state == TCP_TIME_WAIT)
|
||||
return (unsigned long)sk;
|
||||
|
|
|
@ -1798,12 +1798,12 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb)
|
|||
|
||||
__skb_pull(skb, hdrlen);
|
||||
if (skb_try_coalesce(tail, skb, &fragstolen, &delta)) {
|
||||
thtail->window = th->window;
|
||||
|
||||
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;
|
||||
thtail->window = th->window;
|
||||
}
|
||||
|
||||
/* We have to update both TCP_SKB_CB(tail)->tcp_flags and
|
||||
* thtail->fin, so that the fast path in tcp_rcv_established()
|
||||
|
|
|
@ -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,
|
||||
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) {
|
||||
/* 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->use_map = 1;
|
||||
ext->dsn64 = 1;
|
||||
/* The write_seq value has already been incremented, so
|
||||
* the actual sequence number for the DATA_FIN is one less.
|
||||
*/
|
||||
ext->data_seq = data_fin_tx_seq - 1;
|
||||
ext->data_seq = data_fin_tx_seq;
|
||||
ext->subflow_seq = 0;
|
||||
ext->data_len = 1;
|
||||
} else if (ext->data_seq + ext->data_len == data_fin_tx_seq) {
|
||||
|
|
|
@ -750,7 +750,7 @@ static enum mapping_status get_mapping_status(struct sock *ssk,
|
|||
return MAPPING_DATA_FIN;
|
||||
}
|
||||
} 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
|
||||
* must also be limited to 32 bits.
|
||||
|
|
|
@ -905,8 +905,8 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
|
|||
}
|
||||
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
|
||||
|
||||
if (err == NF_ACCEPT &&
|
||||
ct->status & IPS_SRC_NAT && ct->status & IPS_DST_NAT) {
|
||||
if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
|
||||
if (ct->status & IPS_SRC_NAT) {
|
||||
if (maniptype == NF_NAT_MANIP_SRC)
|
||||
maniptype = NF_NAT_MANIP_DST;
|
||||
else
|
||||
|
@ -914,6 +914,10 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
|
|||
|
||||
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
|
||||
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. */
|
||||
|
|
|
@ -193,7 +193,7 @@ static int announce_servers(struct sockaddr_qrtr *sq)
|
|||
struct qrtr_server *srv;
|
||||
struct qrtr_node *node;
|
||||
void __rcu **slot;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
node = node_get(qrtr_ns.local_node);
|
||||
if (!node)
|
||||
|
@ -203,18 +203,27 @@ static int announce_servers(struct sockaddr_qrtr *sq)
|
|||
/* Announce the list of servers registered in this node */
|
||||
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
|
||||
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);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to announce new service\n");
|
||||
goto err_out;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
}
|
||||
|
||||
err_out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
void __rcu **slot;
|
||||
struct kvec iv;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
iv.iov_base = &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 */
|
||||
radix_tree_for_each_slot(slot, &node->servers, &iter, 0) {
|
||||
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);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -368,6 +386,14 @@ static int ctrl_cmd_bye(struct sockaddr_qrtr *from)
|
|||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
|
||||
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_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));
|
||||
if (ret < 0) {
|
||||
pr_err("failed to send bye cmd\n");
|
||||
goto err_out;
|
||||
return ret;
|
||||
}
|
||||
rcu_read_lock();
|
||||
}
|
||||
|
||||
err_out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
void __rcu **slot;
|
||||
struct kvec iv;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
iv.iov_base = &pkt;
|
||||
iv.iov_len = sizeof(pkt);
|
||||
|
@ -447,6 +473,14 @@ static int ctrl_cmd_del_client(struct sockaddr_qrtr *from,
|
|||
rcu_read_lock();
|
||||
radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) {
|
||||
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_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));
|
||||
if (ret < 0) {
|
||||
pr_err("failed to send del client cmd\n");
|
||||
goto err_out;
|
||||
return ret;
|
||||
}
|
||||
rcu_read_lock();
|
||||
}
|
||||
|
||||
err_out:
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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();
|
||||
radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) {
|
||||
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,
|
||||
&srv_iter, 0) {
|
||||
struct qrtr_server *srv;
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
srv_slot = radix_tree_iter_resume(srv_slot, &srv_iter);
|
||||
|
||||
rcu_read_unlock();
|
||||
lookup_notify(from, srv, true);
|
||||
rcu_read_lock();
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -514,7 +514,6 @@ enum rxrpc_call_state {
|
|||
RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */
|
||||
RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */
|
||||
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_ACK_REQUEST, /* - server pending ACK of request */
|
||||
RXRPC_CALL_SERVER_SEND_REPLY, /* - server sending reply */
|
||||
|
@ -710,8 +709,8 @@ struct rxrpc_ack_summary {
|
|||
enum rxrpc_command {
|
||||
RXRPC_CMD_SEND_DATA, /* send data message */
|
||||
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_CHARGE_ACCEPT, /* [server] charge accept preallocation */
|
||||
};
|
||||
|
||||
struct rxrpc_call_params {
|
||||
|
@ -752,9 +751,7 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *,
|
|||
struct rxrpc_sock *,
|
||||
struct sk_buff *);
|
||||
void rxrpc_accept_incoming_calls(struct rxrpc_local *);
|
||||
struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, unsigned long,
|
||||
rxrpc_notify_rx_t);
|
||||
int rxrpc_reject_call(struct rxrpc_sock *);
|
||||
int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long);
|
||||
|
||||
/*
|
||||
* call_event.c
|
||||
|
|
|
@ -39,8 +39,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
|
|||
unsigned int debug_id)
|
||||
{
|
||||
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 rb_node *parent, **pp;
|
||||
int max, tmp;
|
||||
unsigned int size = RXRPC_BACKLOG_MAX;
|
||||
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
|
||||
* 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);
|
||||
if (!call)
|
||||
|
@ -107,9 +108,6 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
|
|||
here, (const void *)user_call_ID);
|
||||
|
||||
write_lock(&rx->call_lock);
|
||||
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;
|
||||
|
@ -127,13 +125,15 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
|
|||
|
||||
call->user_call_ID = user_call_ID;
|
||||
call->notify_rx = notify_rx;
|
||||
if (user_attach_call) {
|
||||
rxrpc_get_call(call, rxrpc_call_got_kernel);
|
||||
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);
|
||||
}
|
||||
|
||||
list_add(&call->sock_link, &rx->sock_calls);
|
||||
|
||||
|
@ -157,11 +157,8 @@ id_in_use:
|
|||
}
|
||||
|
||||
/*
|
||||
* Preallocate sufficient service connections, calls and peers to cover the
|
||||
* entire backlog of a socket. When a new call comes in, if we don't have
|
||||
* sufficient of each available, the call gets rejected as busy or ignored.
|
||||
*
|
||||
* The backlog is replenished when a connection is accepted or rejected.
|
||||
* Allocate the preallocation buffers for incoming service calls. These must
|
||||
* be charged manually.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -333,6 +323,7 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
|
|||
rxrpc_see_call(call);
|
||||
call->conn = conn;
|
||||
call->security = conn->security;
|
||||
call->security_ix = conn->security_ix;
|
||||
call->peer = rxrpc_get_peer(conn->params.peer);
|
||||
call->cong_cwnd = call->peer->cong_cwnd;
|
||||
return call;
|
||||
|
@ -402,8 +393,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
|
||||
if (rx->notify_new_call)
|
||||
rx->notify_new_call(&rx->sk, call, call->user_call_ID);
|
||||
else
|
||||
sk_acceptq_added(&rx->sk);
|
||||
|
||||
spin_lock(&conn->state_lock);
|
||||
switch (conn->state) {
|
||||
|
@ -415,12 +404,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
|
||||
case RXRPC_CONN_SERVICE:
|
||||
write_lock(&call->state_lock);
|
||||
if (call->state < RXRPC_CALL_COMPLETE) {
|
||||
if (rx->discard_new_call)
|
||||
if (call->state < RXRPC_CALL_COMPLETE)
|
||||
call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
|
||||
else
|
||||
call->state = RXRPC_CALL_SERVER_ACCEPTING;
|
||||
}
|
||||
write_unlock(&call->state_lock);
|
||||
break;
|
||||
|
||||
|
@ -440,9 +425,6 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
|
|||
|
||||
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
|
||||
* 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
|
||||
|
@ -460,187 +442,18 @@ no_call:
|
|||
}
|
||||
|
||||
/*
|
||||
* handle acceptance of a call by userspace
|
||||
* - assign the user call ID to the call at the front of the queue
|
||||
* - called with the socket locked.
|
||||
* Charge up socket with preallocated calls, attaching user call IDs.
|
||||
*/
|
||||
struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *rx,
|
||||
unsigned long user_call_ID,
|
||||
rxrpc_notify_rx_t notify_rx)
|
||||
__releases(&rx->sk.sk_lock.slock)
|
||||
__acquires(call->user_mutex)
|
||||
int rxrpc_user_charge_accept(struct rxrpc_sock *rx, unsigned long user_call_ID)
|
||||
{
|
||||
struct rxrpc_call *call;
|
||||
struct rb_node *parent, **pp;
|
||||
int ret;
|
||||
struct rxrpc_backlog *b = rx->backlog;
|
||||
|
||||
_enter(",%lx", user_call_ID);
|
||||
if (rx->sk.sk_state == RXRPC_CLOSE)
|
||||
return -ESHUTDOWN;
|
||||
|
||||
ASSERT(!irqs_disabled());
|
||||
|
||||
write_lock(&rx->call_lock);
|
||||
|
||||
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;
|
||||
return rxrpc_service_prealloc_one(rx, b, NULL, NULL, user_call_ID,
|
||||
GFP_KERNEL,
|
||||
atomic_inc_return(&rxrpc_debug_id));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,7 +23,6 @@ const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = {
|
|||
[RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl",
|
||||
[RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc",
|
||||
[RXRPC_CALL_SERVER_SECURING] = "SvSecure",
|
||||
[RXRPC_CALL_SERVER_ACCEPTING] = "SvAccept",
|
||||
[RXRPC_CALL_SERVER_RECV_REQUEST] = "SvRcvReq",
|
||||
[RXRPC_CALL_SERVER_ACK_REQUEST] = "SvAckReq",
|
||||
[RXRPC_CALL_SERVER_SEND_REPLY] = "SvSndRpl",
|
||||
|
@ -393,8 +392,6 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
|
|||
call->call_id = sp->hdr.callNumber;
|
||||
call->service_id = sp->hdr.serviceId;
|
||||
call->cid = sp->hdr.cid;
|
||||
call->state = RXRPC_CALL_SERVER_ACCEPTING;
|
||||
if (sp->hdr.securityIndex > 0)
|
||||
call->state = RXRPC_CALL_SERVER_SECURING;
|
||||
call->cong_tstamp = skb->tstamp;
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ static void rxrpc_call_is_secure(struct rxrpc_call *call)
|
|||
if (call) {
|
||||
write_lock_bh(&call->state_lock);
|
||||
if (call->state == RXRPC_CALL_SERVER_SECURING) {
|
||||
call->state = RXRPC_CALL_SERVER_ACCEPTING;
|
||||
call->state = RXRPC_CALL_SERVER_RECV_REQUEST;
|
||||
rxrpc_notify_socket(call);
|
||||
}
|
||||
write_unlock_bh(&call->state_lock);
|
||||
|
@ -342,18 +342,18 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
|
|||
return ret;
|
||||
|
||||
spin_lock(&conn->bundle->channel_lock);
|
||||
spin_lock(&conn->state_lock);
|
||||
spin_lock_bh(&conn->state_lock);
|
||||
|
||||
if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
|
||||
conn->state = RXRPC_CONN_SERVICE;
|
||||
spin_unlock(&conn->state_lock);
|
||||
spin_unlock_bh(&conn->state_lock);
|
||||
for (loop = 0; loop < RXRPC_MAXCALLS; loop++)
|
||||
rxrpc_call_is_secure(
|
||||
rcu_dereference_protected(
|
||||
conn->channels[loop].call,
|
||||
lockdep_is_held(&conn->bundle->channel_lock)));
|
||||
} else {
|
||||
spin_unlock(&conn->state_lock);
|
||||
spin_unlock_bh(&conn->state_lock);
|
||||
}
|
||||
|
||||
spin_unlock(&conn->bundle->channel_lock);
|
||||
|
|
|
@ -903,7 +903,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
|
|||
|
||||
_enter("");
|
||||
|
||||
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
|
||||
if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->securities)
|
||||
return -EINVAL;
|
||||
|
||||
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))
|
||||
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)) {
|
||||
kfree(description);
|
||||
_leave(" = %ld", PTR_ERR(key));
|
||||
|
@ -1072,7 +1072,7 @@ static long rxrpc_read(const struct key *key,
|
|||
|
||||
switch (token->security_index) {
|
||||
case RXRPC_SECURITY_RXKAD:
|
||||
toksize += 9 * 4; /* viceid, kvno, key*2 + len, begin,
|
||||
toksize += 8 * 4; /* viceid, kvno, key*2, begin,
|
||||
* end, primary, tktlen */
|
||||
toksize += RND(token->kad->ticket_len);
|
||||
break;
|
||||
|
@ -1107,7 +1107,8 @@ static long rxrpc_read(const struct key *key,
|
|||
break;
|
||||
|
||||
default: /* we have a ticket we can't encode */
|
||||
BUG();
|
||||
pr_err("Unsupported key token type (%u)\n",
|
||||
token->security_index);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1138,6 +1139,14 @@ static long rxrpc_read(const struct key *key,
|
|||
memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3)); \
|
||||
xdr += (_l + 3) >> 2; \
|
||||
} 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) \
|
||||
do { \
|
||||
__be64 y = cpu_to_be64(x); \
|
||||
|
@ -1165,7 +1174,7 @@ static long rxrpc_read(const struct key *key,
|
|||
case RXRPC_SECURITY_RXKAD:
|
||||
ENCODE(token->kad->vice_id);
|
||||
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->expiry);
|
||||
ENCODE(token->kad->primary_flag);
|
||||
|
@ -1215,7 +1224,6 @@ static long rxrpc_read(const struct key *key,
|
|||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -178,37 +178,6 @@ static int rxrpc_recvmsg_term(struct rxrpc_call *call, struct msghdr *msg)
|
|||
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.
|
||||
*/
|
||||
|
@ -630,9 +599,6 @@ try_again:
|
|||
}
|
||||
|
||||
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_SERVER_RECV_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],
|
||||
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);
|
||||
|
||||
|
|
|
@ -530,10 +530,10 @@ static int rxrpc_sendmsg_cmsg(struct msghdr *msg, struct rxrpc_send_params *p)
|
|||
return -EINVAL;
|
||||
break;
|
||||
|
||||
case RXRPC_ACCEPT:
|
||||
case RXRPC_CHARGE_ACCEPT:
|
||||
if (p->command != RXRPC_CMD_SEND_DATA)
|
||||
return -EINVAL;
|
||||
p->command = RXRPC_CMD_ACCEPT;
|
||||
p->command = RXRPC_CMD_CHARGE_ACCEPT;
|
||||
if (len != 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
@ -659,16 +659,12 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
|
|||
if (ret < 0)
|
||||
goto error_release_sock;
|
||||
|
||||
if (p.command == RXRPC_CMD_ACCEPT) {
|
||||
if (p.command == RXRPC_CMD_CHARGE_ACCEPT) {
|
||||
ret = -EINVAL;
|
||||
if (rx->sk.sk_state != RXRPC_SERVER_LISTENING)
|
||||
goto error_release_sock;
|
||||
call = rxrpc_accept_call(rx, p.call.user_call_ID, NULL);
|
||||
/* The socket is now unlocked. */
|
||||
if (IS_ERR(call))
|
||||
return PTR_ERR(call);
|
||||
ret = 0;
|
||||
goto out_put_unlock;
|
||||
ret = rxrpc_user_charge_accept(rx, p.call.user_call_ID);
|
||||
goto error_release_sock;
|
||||
}
|
||||
|
||||
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_SERVER_PREALLOC:
|
||||
case RXRPC_CALL_SERVER_SECURING:
|
||||
case RXRPC_CALL_SERVER_ACCEPTING:
|
||||
rxrpc_put_call(call, rxrpc_call_put);
|
||||
ret = -EBUSY;
|
||||
goto error_release_sock;
|
||||
|
|
|
@ -494,6 +494,7 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
|
|||
out_err:
|
||||
/* Clean up any successful allocations */
|
||||
sctp_auth_destroy_hmacs(ep->auth_hmacs);
|
||||
ep->auth_hmacs = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -4259,6 +4259,9 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (key.idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_MAC])
|
||||
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue