diff options
Diffstat (limited to 'drivers')
75 files changed, 503 insertions, 2953 deletions
diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig index c987c826daa3..0426d66660d1 100644 --- a/drivers/gpu/drm/shmobile/Kconfig +++ b/drivers/gpu/drm/shmobile/Kconfig @@ -2,7 +2,6 @@ config DRM_SHMOBILE tristate "DRM Support for SH Mobile" depends on DRM && ARM depends on ARCH_SHMOBILE || COMPILE_TEST - depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_LCD_SUPPORT select DRM_KMS_HELPER diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index e7738939a86d..40df8887fc17 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -21,8 +21,6 @@ #include <drm/drm_gem_cma_helper.h> #include <drm/drm_plane_helper.h> -#include <video/sh_mobile_meram.h> - #include "shmob_drm_backlight.h" #include "shmob_drm_crtc.h" #include "shmob_drm_drv.h" @@ -47,20 +45,12 @@ static int shmob_drm_clk_on(struct shmob_drm_device *sdev) if (ret < 0) return ret; } -#if 0 - if (sdev->meram_dev && sdev->meram_dev->pdev) - pm_runtime_get_sync(&sdev->meram_dev->pdev->dev); -#endif return 0; } static void shmob_drm_clk_off(struct shmob_drm_device *sdev) { -#if 0 - if (sdev->meram_dev && sdev->meram_dev->pdev) - pm_runtime_put_sync(&sdev->meram_dev->pdev->dev); -#endif if (sdev->clock) clk_disable_unprepare(sdev->clock); } @@ -269,12 +259,6 @@ static void shmob_drm_crtc_stop(struct shmob_drm_crtc *scrtc) if (!scrtc->started) return; - /* Disable the MERAM cache. */ - if (scrtc->cache) { - sh_mobile_meram_cache_free(sdev->meram, scrtc->cache); - scrtc->cache = NULL; - } - /* Stop the LCDC. */ shmob_drm_crtc_start_stop(scrtc, false); @@ -305,7 +289,6 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, { struct drm_crtc *crtc = &scrtc->crtc; struct drm_framebuffer *fb = crtc->primary->fb; - struct shmob_drm_device *sdev = crtc->dev->dev_private; struct drm_gem_cma_object *gem; unsigned int bpp; @@ -321,11 +304,6 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, + y / (bpp == 4 ? 2 : 1) * fb->pitches[1] + x * (bpp == 16 ? 2 : 1); } - - if (scrtc->cache) - sh_mobile_meram_cache_update(sdev->meram, scrtc->cache, - scrtc->dma[0], scrtc->dma[1], - &scrtc->dma[0], &scrtc->dma[1]); } static void shmob_drm_crtc_update_base(struct shmob_drm_crtc *scrtc) @@ -372,9 +350,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, { struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc); struct shmob_drm_device *sdev = crtc->dev->dev_private; - const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram; const struct shmob_drm_format_info *format; - void *cache; format = shmob_drm_format_info(crtc->primary->fb->format->format); if (format == NULL) { @@ -386,24 +362,6 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, scrtc->format = format; scrtc->line_size = crtc->primary->fb->pitches[0]; - if (sdev->meram) { - /* Enable MERAM cache if configured. We need to de-init - * configured ICBs before we can re-initialize them. - */ - if (scrtc->cache) { - sh_mobile_meram_cache_free(sdev->meram, scrtc->cache); - scrtc->cache = NULL; - } - - cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata, - crtc->primary->fb->pitches[0], - adjusted_mode->vdisplay, - format->meram, - &scrtc->line_size); - if (!IS_ERR(cache)) - scrtc->cache = cache; - } - shmob_drm_crtc_compute_base(scrtc, x, y); return 0; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.h b/drivers/gpu/drm/shmobile/shmob_drm_crtc.h index f152973df11c..c11f421737dc 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.h +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.h @@ -28,7 +28,6 @@ struct shmob_drm_crtc { int dpms; const struct shmob_drm_format_info *format; - void *cache; unsigned long dma[2]; unsigned int line_size; bool started; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.h b/drivers/gpu/drm/shmobile/shmob_drm_drv.h index 02ea315ba69a..088a6e55fa29 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.h +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.h @@ -23,7 +23,6 @@ struct clk; struct device; struct drm_device; -struct sh_mobile_meram_info; struct shmob_drm_device { struct device *dev; @@ -31,7 +30,6 @@ struct shmob_drm_device { void __iomem *mmio; struct clk *clock; - struct sh_mobile_meram_info *meram; u32 lddckr; u32 ldmt1r; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c index d36919b14da7..447638581c08 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c @@ -18,8 +18,6 @@ #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> -#include <video/sh_mobile_meram.h> - #include "shmob_drm_crtc.h" #include "shmob_drm_drv.h" #include "shmob_drm_kms.h" @@ -35,55 +33,46 @@ static const struct shmob_drm_format_info shmob_drm_format_infos[] = { .bpp = 16, .yuv = false, .lddfr = LDDFR_PKF_RGB16, - .meram = SH_MOBILE_MERAM_PF_RGB, }, { .fourcc = DRM_FORMAT_RGB888, .bpp = 24, .yuv = false, .lddfr = LDDFR_PKF_RGB24, - .meram = SH_MOBILE_MERAM_PF_RGB, }, { .fourcc = DRM_FORMAT_ARGB8888, .bpp = 32, .yuv = false, .lddfr = LDDFR_PKF_ARGB32, - .meram = SH_MOBILE_MERAM_PF_RGB, }, { .fourcc = DRM_FORMAT_NV12, .bpp = 12, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_420, - .meram = SH_MOBILE_MERAM_PF_NV, }, { .fourcc = DRM_FORMAT_NV21, .bpp = 12, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_420, - .meram = SH_MOBILE_MERAM_PF_NV, }, { .fourcc = DRM_FORMAT_NV16, .bpp = 16, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_422, - .meram = SH_MOBILE_MERAM_PF_NV, }, { .fourcc = DRM_FORMAT_NV61, .bpp = 16, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_422, - .meram = SH_MOBILE_MERAM_PF_NV, }, { .fourcc = DRM_FORMAT_NV24, .bpp = 24, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_444, - .meram = SH_MOBILE_MERAM_PF_NV24, }, { .fourcc = DRM_FORMAT_NV42, .bpp = 24, .yuv = true, .lddfr = LDDFR_CC | LDDFR_YF_444, - .meram = SH_MOBILE_MERAM_PF_NV24, }, }; diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.h b/drivers/gpu/drm/shmobile/shmob_drm_kms.h index 06d5b7caa026..753e2817dc2c 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.h +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.h @@ -24,7 +24,6 @@ struct shmob_drm_format_info { unsigned int bpp; bool yuv; u32 lddfr; - unsigned int meram; }; const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c index 97f6e4a3eb0d..1d0359f713ca 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c @@ -17,8 +17,6 @@ #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> -#include <video/sh_mobile_meram.h> - #include "shmob_drm_drv.h" #include "shmob_drm_kms.h" #include "shmob_drm_plane.h" diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index f01c3e813247..c8bb82fe0b9d 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -27,7 +27,12 @@ #include <linux/via-core.h> #include <linux/via-gpio.h> #include <linux/via_i2c.h> + +#ifdef CONFIG_X86 #include <asm/olpc.h> +#else +#define machine_is_olpc(x) 0 +#endif #include "via-camera.h" diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 448d1fafc827..f4d81765221e 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -325,6 +325,8 @@ struct nicvf { struct tasklet_struct qs_err_task; struct work_struct reset_task; struct nicvf_work rx_mode_work; + /* spinlock to protect workqueue arguments from concurrent access */ + spinlock_t rx_mode_wq_lock; /* PTP timestamp */ struct cavium_ptp *ptp_clock; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 7135db45927e..135766c4296b 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1923,17 +1923,12 @@ static int nicvf_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) } } -static void nicvf_set_rx_mode_task(struct work_struct *work_arg) +static void __nicvf_set_rx_mode_task(u8 mode, struct xcast_addr_list *mc_addrs, + struct nicvf *nic) { - struct nicvf_work *vf_work = container_of(work_arg, struct nicvf_work, - work.work); - struct nicvf *nic = container_of(vf_work, struct nicvf, rx_mode_work); union nic_mbx mbx = {}; int idx; - if (!vf_work) - return; - /* From the inside of VM code flow we have only 128 bits memory * available to send message to host's PF, so send all mc addrs * one by one, starting from flush command in case if kernel @@ -1944,7 +1939,7 @@ static void nicvf_set_rx_mode_task(struct work_struct *work_arg) mbx.xcast.msg = NIC_MBOX_MSG_RESET_XCAST; nicvf_send_msg_to_pf(nic, &mbx); - if (vf_work->mode & BGX_XCAST_MCAST_FILTER) { + if (mode & BGX_XCAST_MCAST_FILTER) { /* once enabling filtering, we need to signal to PF to add * its' own LMAC to the filter to accept packets for it. */ @@ -1954,23 +1949,46 @@ static void nicvf_set_rx_mode_task(struct work_struct *work_arg) } /* check if we have any specific MACs to be added to PF DMAC filter */ - if (vf_work->mc) { + if (mc_addrs) { /* now go through kernel list of MACs and add them one by one */ - for (idx = 0; idx < vf_work->mc->count; idx++) { + for (idx = 0; idx < mc_addrs->count; idx++) { mbx.xcast.msg = NIC_MBOX_MSG_ADD_MCAST; - mbx.xcast.data.mac = vf_work->mc->mc[idx]; + mbx.xcast.data.mac = mc_addrs->mc[idx]; nicvf_send_msg_to_pf(nic, &mbx); } - kfree(vf_work->mc); + kfree(mc_addrs); } /* and finally set rx mode for PF accordingly */ mbx.xcast.msg = NIC_MBOX_MSG_SET_XCAST; - mbx.xcast.data.mode = vf_work->mode; + mbx.xcast.data.mode = mode; nicvf_send_msg_to_pf(nic, &mbx); } +static void nicvf_set_rx_mode_task(struct work_struct *work_arg) +{ + struct nicvf_work *vf_work = container_of(work_arg, struct nicvf_work, + work.work); + struct nicvf *nic = container_of(vf_work, struct nicvf, rx_mode_work); + u8 mode; + struct xcast_addr_list *mc; + + if (!vf_work) + return; + + /* Save message data locally to prevent them from + * being overwritten by next ndo_set_rx_mode call(). + */ + spin_lock(&nic->rx_mode_wq_lock); + mode = vf_work->mode; + mc = vf_work->mc; + vf_work->mc = NULL; + spin_unlock(&nic->rx_mode_wq_lock); + + __nicvf_set_rx_mode_task(mode, mc, nic); +} + static void nicvf_set_rx_mode(struct net_device *netdev) { struct nicvf *nic = netdev_priv(netdev); @@ -2004,9 +2022,12 @@ static void nicvf_set_rx_mode(struct net_device *netdev) } } } + spin_lock(&nic->rx_mode_wq_lock); + kfree(nic->rx_mode_work.mc); nic->rx_mode_work.mc = mc_list; nic->rx_mode_work.mode = mode; - queue_delayed_work(nicvf_rx_mode_wq, &nic->rx_mode_work.work, 2 * HZ); + queue_delayed_work(nicvf_rx_mode_wq, &nic->rx_mode_work.work, 0); + spin_unlock(&nic->rx_mode_wq_lock); } static const struct net_device_ops nicvf_netdev_ops = { @@ -2163,6 +2184,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&nic->reset_task, nicvf_reset_task); INIT_DELAYED_WORK(&nic->rx_mode_work.work, nicvf_set_rx_mode_task); + spin_lock_init(&nic->rx_mode_wq_lock); err = register_netdev(netdev); if (err) { diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 2edfdbdaae48..7b795edd9d3a 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -3362,10 +3362,17 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) err = sysfs_create_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); + if (err) { + dev_err(&pdev->dev, "cannot create sysfs group\n"); + goto out_close_led; + } print_port_info(adapter, ai); return 0; +out_close_led: + t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0); + out_free_dev: iounmap(adapter->regs); for (i = ai->nports0 + ai->nports1 - 1; i >= 0; --i) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index fc534e91c6b2..144d5fe6b944 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -760,9 +760,9 @@ struct ixgbe_adapter { #define IXGBE_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */ u32 *rss_key; -#ifdef CONFIG_XFRM +#ifdef CONFIG_XFRM_OFFLOAD struct ixgbe_ipsec *ipsec; -#endif /* CONFIG_XFRM */ +#endif /* CONFIG_XFRM_OFFLOAD */ }; static inline u8 ixgbe_max_rss_indices(struct ixgbe_adapter *adapter) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c index 344a1f213a5f..c116f459945d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ipsec.c @@ -158,7 +158,16 @@ static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter) reg |= IXGBE_SECRXCTRL_RX_DIS; IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, reg); - IXGBE_WRITE_FLUSH(hw); + /* If both Tx and Rx are ready there are no packets + * that we need to flush so the loopback configuration + * below is not necessary. + */ + t_rdy = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) & + IXGBE_SECTXSTAT_SECTX_RDY; + r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) & + IXGBE_SECRXSTAT_SECRX_RDY; + if (t_rdy && r_rdy) + return; /* If the tx fifo doesn't have link, but still has data, * we can't clear the tx sec block. Set the MAC loopback @@ -185,7 +194,7 @@ static void ixgbe_ipsec_stop_data(struct ixgbe_adapter *adapter) IXGBE_SECTXSTAT_SECTX_RDY; r_rdy = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) & IXGBE_SECRXSTAT_SECRX_RDY; - } while (!t_rdy && !r_rdy && limit--); + } while (!(t_rdy && r_rdy) && limit--); /* undo loopback if we played with it earlier */ if (!link) { @@ -966,10 +975,22 @@ void ixgbe_ipsec_rx(struct ixgbe_ring *rx_ring, **/ void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) { + struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_ipsec *ipsec; + u32 t_dis, r_dis; size_t size; - if (adapter->hw.mac.type == ixgbe_mac_82598EB) + if (hw->mac.type == ixgbe_mac_82598EB) + return; + + /* If there is no support for either Tx or Rx offload + * we should not be advertising support for IPsec. + */ + t_dis = IXGBE_READ_REG(hw, IXGBE_SECTXSTAT) & + IXGBE_SECTXSTAT_SECTX_OFF_DIS; + r_dis = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT) & + IXGBE_SECRXSTAT_SECRX_OFF_DIS; + if (t_dis || r_dis) return; ipsec = kzalloc(sizeof(*ipsec), GFP_KERNEL); @@ -1001,13 +1022,6 @@ void ixgbe_init_ipsec_offload(struct ixgbe_adapter *adapter) adapter->netdev->xfrmdev_ops = &ixgbe_xfrmdev_ops; -#define IXGBE_ESP_FEATURES (NETIF_F_HW_ESP | \ - NETIF_F_HW_ESP_TX_CSUM | \ - NETIF_F_GSO_ESP) - - adapter->netdev->features |= IXGBE_ESP_FEATURES; - adapter->netdev->hw_enc_features |= IXGBE_ESP_FEATURES; - return; err2: diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index 893a9206e718..d361f570ca37 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -593,6 +593,14 @@ static bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter) } #endif + /* To support macvlan offload we have to use num_tc to + * restrict the queues that can be used by the device. + * By doing this we can avoid reporting a false number of + * queues. + */ + if (vmdq_i > 1) + netdev_set_num_tc(adapter->netdev, 1); + /* populate TC0 for use by pool 0 */ netdev_set_tc_queue(adapter->netdev, 0, adapter->num_rx_queues_per_pool, 0); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0b1ba3ae159c..3e87dbbc9024 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6117,6 +6117,7 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter, #ifdef CONFIG_IXGBE_DCB ixgbe_init_dcb(adapter); #endif + ixgbe_init_ipsec_offload(adapter); /* default flow control settings */ hw->fc.requested_mode = ixgbe_fc_full; @@ -8822,14 +8823,6 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) } else { netdev_reset_tc(dev); - /* To support macvlan offload we have to use num_tc to - * restrict the queues that can be used by the device. - * By doing this we can avoid reporting a false number of - * queues. - */ - if (!tc && adapter->num_rx_pools > 1) - netdev_set_num_tc(dev, 1); - if (adapter->hw.mac.type == ixgbe_mac_82598EB) adapter->hw.fc.requested_mode = adapter->last_lfc_mode; @@ -9904,7 +9897,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev, * the TSO, so it's the exception. */ if (skb->encapsulation && !(features & NETIF_F_TSO_MANGLEID)) { -#ifdef CONFIG_XFRM +#ifdef CONFIG_XFRM_OFFLOAD if (!skb->sp) #endif features &= ~NETIF_F_TSO; @@ -10437,6 +10430,14 @@ skip_sriov: if (hw->mac.type >= ixgbe_mac_82599EB) netdev->features |= NETIF_F_SCTP_CRC; +#ifdef CONFIG_XFRM_OFFLOAD +#define IXGBE_ESP_FEATURES (NETIF_F_HW_ESP | \ + NETIF_F_HW_ESP_TX_CSUM | \ + NETIF_F_GSO_ESP) + + if (adapter->ipsec) + netdev->features |= IXGBE_ESP_FEATURES; +#endif /* copy netdev features into list of user selectable features */ netdev->hw_features |= netdev->features | NETIF_F_HW_VLAN_CTAG_FILTER | @@ -10499,8 +10500,6 @@ skip_sriov: NETIF_F_FCOE_MTU; } #endif /* IXGBE_FCOE */ - ixgbe_init_ipsec_offload(adapter); - if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) netdev->hw_features |= NETIF_F_LRO; if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index e8ed37749ab1..44cfb2021145 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -599,13 +599,15 @@ struct ixgbe_nvm_version { #define IXGBE_SECTXCTRL_STORE_FORWARD 0x00000004 #define IXGBE_SECTXSTAT_SECTX_RDY 0x00000001 -#define IXGBE_SECTXSTAT_ECC_TXERR 0x00000002 +#define IXGBE_SECTXSTAT_SECTX_OFF_DIS 0x00000002 +#define IXGBE_SECTXSTAT_ECC_TXERR 0x00000004 #define IXGBE_SECRXCTRL_SECRX_DIS 0x00000001 #define IXGBE_SECRXCTRL_RX_DIS 0x00000002 #define IXGBE_SECRXSTAT_SECRX_RDY 0x00000001 -#define IXGBE_SECRXSTAT_ECC_RXERR 0x00000002 +#define IXGBE_SECRXSTAT_SECRX_OFF_DIS 0x00000002 +#define IXGBE_SECRXSTAT_ECC_RXERR 0x00000004 /* LinkSec (MacSec) Registers */ #define IXGBE_LSECTXCAP 0x08A00 diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 77b2adb29341..6aaaf3d9ba31 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -4756,12 +4756,6 @@ static void mlxsw_sp_rt6_destroy(struct mlxsw_sp_rt6 *mlxsw_sp_rt6) kfree(mlxsw_sp_rt6); } -static bool mlxsw_sp_fib6_rt_can_mp(const struct fib6_info *rt) -{ - /* RTF_CACHE routes are ignored */ - return (rt->fib6_flags & (RTF_GATEWAY | RTF_ADDRCONF)) == RTF_GATEWAY; -} - static struct fib6_info * mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry) { @@ -4771,11 +4765,11 @@ mlxsw_sp_fib6_entry_rt(const struct mlxsw_sp_fib6_entry *fib6_entry) static struct mlxsw_sp_fib6_entry * mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, - const struct fib6_info *nrt, bool replace) + const struct fib6_info *nrt, bool append) { struct mlxsw_sp_fib6_entry *fib6_entry; - if (!mlxsw_sp_fib6_rt_can_mp(nrt) || replace) + if (!append) return NULL; list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { @@ -4790,8 +4784,7 @@ mlxsw_sp_fib6_node_mp_entry_find(const struct mlxsw_sp_fib_node *fib_node, break; if (rt->fib6_metric < nrt->fib6_metric) continue; - if (rt->fib6_metric == nrt->fib6_metric && - mlxsw_sp_fib6_rt_can_mp(rt)) + if (rt->fib6_metric == nrt->fib6_metric) return fib6_entry; if (rt->fib6_metric > nrt->fib6_metric) break; @@ -5170,7 +5163,7 @@ static struct mlxsw_sp_fib6_entry * mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, const struct fib6_info *nrt, bool replace) { - struct mlxsw_sp_fib6_entry *fib6_entry, *fallback = NULL; + struct mlxsw_sp_fib6_entry *fib6_entry; list_for_each_entry(fib6_entry, &fib_node->entry_list, common.list) { struct fib6_info *rt = mlxsw_sp_fib6_entry_rt(fib6_entry); @@ -5179,18 +5172,13 @@ mlxsw_sp_fib6_node_entry_find(const struct mlxsw_sp_fib_node *fib_node, continue; if (rt->fib6_table->tb6_id != nrt->fib6_table->tb6_id) break; - if (replace && rt->fib6_metric == nrt->fib6_metric) { - if (mlxsw_sp_fib6_rt_can_mp(rt) == - mlxsw_sp_fib6_rt_can_mp(nrt)) - return fib6_entry; - if (mlxsw_sp_fib6_rt_can_mp(nrt)) - fallback = fallback ?: fib6_entry; - } + if (replace && rt->fib6_metric == nrt->fib6_metric) + return fib6_entry; if (rt->fib6_metric > nrt->fib6_metric) - return fallback ?: fib6_entry; + return fib6_entry; } - return fallback; + return NULL; } static int @@ -5316,7 +5304,8 @@ static void mlxsw_sp_fib6_entry_replace(struct mlxsw_sp *mlxsw_sp, } static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, - struct fib6_info *rt, bool replace) + struct fib6_info *rt, bool replace, + bool append) { struct mlxsw_sp_fib6_entry *fib6_entry; struct mlxsw_sp_fib_node *fib_node; @@ -5342,7 +5331,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, /* Before creating a new entry, try to append route to an existing * multipath entry. */ - fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, replace); + fib6_entry = mlxsw_sp_fib6_node_mp_entry_find(fib_node, rt, append); if (fib6_entry) { err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt); if (err) @@ -5350,6 +5339,14 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, return 0; } + /* We received an append event, yet did not find any route to + * append to. + */ + if (WARN_ON(append)) { + err = -EINVAL; + goto err_fib6_entry_append; + } + fib6_entry = mlxsw_sp_fib6_entry_create(mlxsw_sp, fib_node, rt); if (IS_ERR(fib6_entry)) { err = PTR_ERR(fib6_entry); @@ -5367,6 +5364,7 @@ static int mlxsw_sp_router_fib6_add(struct mlxsw_sp *mlxsw_sp, err_fib6_node_entry_link: mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry); err_fib6_entry_create: +err_fib6_entry_append: err_fib6_entry_nexthop_add: mlxsw_sp_fib_node_put(mlxsw_sp, fib_node); return err; @@ -5717,7 +5715,7 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) struct mlxsw_sp_fib_event_work *fib_work = container_of(work, struct mlxsw_sp_fib_event_work, work); struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp; - bool replace; + bool replace, append; int err; rtnl_lock(); @@ -5728,8 +5726,10 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) case FIB_EVENT_ENTRY_APPEND: /* fall through */ case FIB_EVENT_ENTRY_ADD: replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE; + append = fib_work->event == FIB_EVENT_ENTRY_APPEND; err = mlxsw_sp_router_fib6_add(mlxsw_sp, - fib_work->fen6_info.rt, replace); + fib_work->fen6_info.rt, replace, + append); if (err) mlxsw_sp_router_fib_abort(mlxsw_sp); mlxsw_sp_rt6_release(fib_work->fen6_info.rt); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index e97652c40d13..eea5666a86b2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1018,8 +1018,10 @@ mlxsw_sp_port_vlan_bridge_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, int err; /* No need to continue if only VLAN flags were changed */ - if (mlxsw_sp_port_vlan->bridge_port) + if (mlxsw_sp_port_vlan->bridge_port) { + mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); return 0; + } err = mlxsw_sp_port_vlan_fid_join(mlxsw_sp_port_vlan, bridge_port); if (err) diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 19cfa162ac65..1decf3a1cad3 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -455,6 +455,7 @@ static int nfp_flower_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, eth_hw_addr_random(nn->dp.netdev); netif_keep_dst(nn->dp.netdev); + nn->vnic_no_name = true; return 0; diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c index ec524d97869d..78afe75129ab 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c +++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c @@ -381,6 +381,8 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event, err = PTR_ERR_OR_ZERO(rt); if (err) return NOTIFY_DONE; + + ip_rt_put(rt); #else return NOTIFY_DONE; #endif diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 57cb035dcc6d..2a71a9ffd095 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -590,6 +590,8 @@ struct nfp_net_dp { * @vnic_list: Entry on device vNIC list * @pdev: Backpointer to PCI device * @app: APP handle if available + * @vnic_no_name: For non-port PF vNIC make ndo_get_phys_port_name return + * -EOPNOTSUPP to keep backwards compatibility (set by app) * @port: Pointer to nfp_port structure if vNIC is a port * @app_priv: APP private data for this vNIC */ @@ -663,6 +665,8 @@ struct nfp_net { struct pci_dev *pdev; struct nfp_app *app; + bool vnic_no_name; + struct nfp_port *port; void *app_priv; diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 75110c8d6a90..d4c27f849f9b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3121,7 +3121,7 @@ static void nfp_net_stat64(struct net_device *netdev, struct nfp_net *nn = netdev_priv(netdev); int r; - for (r = 0; r < nn->dp.num_r_vecs; r++) { + for (r = 0; r < nn->max_r_vecs; r++) { struct nfp_net_r_vector *r_vec = &nn->r_vecs[r]; u64 data[3]; unsigned int start; @@ -3286,7 +3286,7 @@ nfp_net_get_phys_port_name(struct net_device *netdev, char *name, size_t len) if (nn->port) return nfp_port_get_phys_port_name(netdev, name, len); - if (nn->dp.is_vf) + if (nn->dp.is_vf || nn->vnic_no_name) return -EOPNOTSUPP; n = snprintf(name, len, "n%d", nn->id); diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c index 2dd89dba9311..d32af598da90 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c @@ -98,21 +98,18 @@ struct nfp_resource { static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) { - char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {}; struct nfp_resource_entry entry; u32 cpp_id, key; int ret, i; cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */ - strncpy(name_pad, res->name, sizeof(name_pad)); - /* Search for a matching entry */ - if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) { + if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) { nfp_err(cpp, "Grabbing device lock not supported\n"); return -EOPNOTSUPP; } - key = crc32_posix(name_pad, sizeof(name_pad)); + key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ); for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) { u64 addr = NFP_RESOURCE_TBL_BASE + diff --git a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c index e78e5db39458..c694e3428dfc 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-sgmii.c @@ -384,6 +384,7 @@ int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) } sgmii_pdev = of_find_device_by_node(np); + of_node_put(np); if (!sgmii_pdev) { dev_err(&pdev->dev, "invalid internal-phy property\n"); return -ENODEV; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 4ff231df7322..c5979569fd60 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -334,9 +334,10 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) dwmac->data = (const struct meson8b_dwmac_data *) of_device_get_match_data(&pdev->dev); - if (!dwmac->data) - return -EINVAL; - + if (!dwmac->data) { + ret = -EINVAL; + goto err_remove_config_dt; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); dwmac->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dwmac->regs)) { diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 14770fc8865e..1f50e83cafb2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -252,13 +252,8 @@ int stmmac_hwif_init(struct stmmac_priv *priv) return ret; } - /* Run quirks, if needed */ - if (entry->quirks) { - ret = entry->quirks(priv); - if (ret) - return ret; - } - + /* Save quirks, if needed for posterior use */ + priv->hwif_quirks = entry->quirks; return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 025efbf6145c..76649adf8fb0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -129,6 +129,7 @@ struct stmmac_priv { struct net_device *dev; struct device *device; struct mac_device_info *hw; + int (*hwif_quirks)(struct stmmac_priv *priv); struct mutex lock; /* RX Queue */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 11fb7c777d89..e79b0d7b388a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3182,17 +3182,22 @@ dma_map_err: static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) { - struct ethhdr *ehdr; + struct vlan_ethhdr *veth; + __be16 vlan_proto; u16 vlanid; - if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) == - NETIF_F_HW_VLAN_CTAG_RX && - !__vlan_get_tag(skb, &vlanid)) { + veth = (struct vlan_ethhdr *)skb->data; + vlan_proto = veth->h_vlan_proto; + + if ((vlan_proto == htons(ETH_P_8021Q) && + dev->features & NETIF_F_HW_VLAN_CTAG_RX) || + (vlan_proto == htons(ETH_P_8021AD) && + dev->features & NETIF_F_HW_VLAN_STAG_RX)) { /* pop the vlan tag */ - ehdr = (struct ethhdr *)skb->data; - memmove(skb->data + VLAN_HLEN, ehdr, ETH_ALEN * 2); + vlanid = ntohs(veth->h_vlan_TCI); + memmove(skb->data + VLAN_HLEN, veth, ETH_ALEN * 2); skb_pull(skb, VLAN_HLEN); - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid); + __vlan_hwaccel_put_tag(skb, vlan_proto, vlanid); } } @@ -4130,6 +4135,13 @@ static int stmmac_hw_init(struct stmmac_priv *priv) if (priv->dma_cap.tsoen) dev_info(priv->device, "TSO supported\n"); + /* Run HW quirks, if any */ + if (priv->hwif_quirks) { + ret = priv->hwif_quirks(priv); + if (ret) + return ret; + } + return 0; } @@ -4235,7 +4247,7 @@ int stmmac_dvr_probe(struct device *device, ndev->watchdog_timeo = msecs_to_jiffies(watchdog); #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ - ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; + ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; #endif priv->msg_enable = netif_msg_init(debug, default_msg_level); diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 69e31ceccfae..2a0c06e0f730 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -123,7 +123,6 @@ * @phy_node: pointer to the PHY device node * @mii_bus: pointer to the MII bus * @last_link: last link status - * @has_mdio: indicates whether MDIO is included in the HW */ struct net_local { @@ -144,7 +143,6 @@ struct net_local { struct mii_bus *mii_bus; int last_link; - bool has_mdio; }; @@ -863,14 +861,14 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) bus->write = xemaclite_mdio_write; bus->parent = dev; - lp->mii_bus = bus; - rc = of_mdiobus_register(bus, np); if (rc) { dev_err(dev, "Failed to register mdio bus.\n"); goto err_register; } + lp->mii_bus = bus; + return 0; err_register: @@ -1145,9 +1143,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev) xemaclite_update_address(lp, ndev->dev_addr); lp->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); - rc = xemaclite_mdio_setup(lp, &ofdev->dev); - if (rc) - dev_warn(&ofdev->dev, "error registering MDIO bus\n"); + xemaclite_mdio_setup(lp, &ofdev->dev); dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr); @@ -1191,7 +1187,7 @@ static int xemaclite_of_remove(struct platform_device *of_dev) struct net_local *lp = netdev_priv(ndev); /* Un-register the mii_bus, if configured */ - if (lp->has_mdio) { + if (lp->mii_bus) { mdiobus_unregister(lp->mii_bus); mdiobus_free(lp->mii_bus); lp->mii_bus = NULL; diff --git a/drivers/net/hyperv/Kconfig b/drivers/net/hyperv/Kconfig index 23a2d145813a..0765d5f61714 100644 --- a/drivers/net/hyperv/Kconfig +++ b/drivers/net/hyperv/Kconfig @@ -2,6 +2,5 @@ config HYPERV_NET tristate "Microsoft Hyper-V virtual network driver" depends on HYPERV select UCS2_STRING - select FAILOVER help Select this option to enable the Hyper-V virtual network driver. diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 23304aca25f9..1a924b867b07 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -901,6 +901,8 @@ struct net_device_context { struct hv_device *device_ctx; /* netvsc_device */ struct netvsc_device __rcu *nvdev; + /* list of netvsc net_devices */ + struct list_head list; /* reconfigure work */ struct delayed_work dwork; /* last reconfig time */ @@ -931,8 +933,6 @@ struct net_device_context { u32 vf_alloc; /* Serial number of the VF to team with */ u32 vf_serial; - - struct failover *failover; }; /* Per channel data */ @@ -1277,17 +1277,17 @@ struct ndis_lsov2_offload { struct ndis_ipsecv2_offload { u32 encap; - u16 ip6; - u16 ip4opt; - u16 ip6ext; - u16 ah; - u16 esp; - u16 ah_esp; - u16 xport; - u16 tun; - u16 xport_tun; - u16 lso; - u16 extseq; + u8 ip6; + u8 ip4opt; + u8 ip6ext; + u8 ah; + u8 esp; + u8 ah_esp; + u8 xport; + u8 tun; + u8 xport_tun; + u8 lso; + u8 extseq; u32 udp_esp; u32 auth; u32 crypto; @@ -1295,8 +1295,8 @@ struct ndis_ipsecv2_offload { }; struct ndis_rsc_offload { - u16 ip4; - u16 ip6; + u8 ip4; + u8 ip6; }; struct ndis_encap_offload { diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7b18a8c267c2..fe2256bf1d13 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -42,7 +42,6 @@ #include <net/pkt_sched.h> #include <net/checksum.h> #include <net/ip6_checksum.h> -#include <net/failover.h> #include "hyperv_net.h" @@ -68,6 +67,8 @@ static int debug = -1; module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +static LIST_HEAD(netvsc_dev_list); + static void netvsc_change_rx_flags(struct net_device *net, int change) { struct net_device_context *ndev_ctx = netdev_priv(net); @@ -1780,6 +1781,36 @@ out_unlock: rtnl_unlock(); } +static struct net_device *get_netvsc_bymac(const u8 *mac) +{ + struct net_device_context *ndev_ctx; + + list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { + struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx); + + if (ether_addr_equal(mac, dev->perm_addr)) + return dev; + } + + return NULL; +} + +static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) +{ + struct net_device_context *net_device_ctx; + struct net_device *dev; + + dev = netdev_master_upper_dev_get(vf_netdev); + if (!dev || dev->netdev_ops != &device_ops) + return NULL; /* not a netvsc device */ + + net_device_ctx = netdev_priv(dev); + if (!rtnl_dereference(net_device_ctx->nvdev)) + return NULL; /* device is removed */ + + return dev; +} + /* Called when VF is injecting data into network stack. * Change the associated network device from VF to netvsc. * note: already called with rcu_read_lock @@ -1802,6 +1833,46 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb) return RX_HANDLER_ANOTHER; } +static int netvsc_vf_join(struct net_device *vf_netdev, + struct net_device *ndev) +{ + struct net_device_context *ndev_ctx = netdev_priv(ndev); + int ret; + + ret = netdev_rx_handler_register(vf_netdev, + netvsc_vf_handle_frame, ndev); + if (ret != 0) { + netdev_err(vf_netdev, + "can not register netvsc VF receive handler (err = %d)\n", + ret); + goto rx_handler_failed; + } + + ret = netdev_master_upper_dev_link(vf_netdev, ndev, + NULL, NULL, NULL); + if (ret != 0) { + netdev_err(vf_netdev, + "can not set master device %s (err = %d)\n", + ndev->name, ret); + goto upper_link_failed; + } + + /* set slave flag before open to prevent IPv6 addrconf */ + vf_netdev->flags |= IFF_SLAVE; + + schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT); + + call_netdevice_notifiers(NETDEV_JOIN, vf_netdev); + + netdev_info(vf_netdev, "joined to %s\n", ndev->name); + return 0; + +upper_link_failed: + netdev_rx_handler_unregister(vf_netdev); +rx_handler_failed: + return ret; +} + static void __netvsc_vf_setup(struct net_device *ndev, struct net_device *vf_netdev) { @@ -1852,95 +1923,104 @@ static void netvsc_vf_setup(struct work_struct *w) rtnl_unlock(); } -static int netvsc_pre_register_vf(struct net_device *vf_netdev, - struct net_device *ndev) +static int netvsc_register_vf(struct net_device *vf_netdev) { + struct net_device *ndev; struct net_device_context *net_device_ctx; struct netvsc_device *netvsc_dev; + int ret; + + if (vf_netdev->addr_len != ETH_ALEN) + return NOTIFY_DONE; + + /* + * We will use the MAC address to locate the synthetic interface to + * associate with the VF interface. If we don't find a matching + * synthetic interface, move on. + */ + ndev = get_netvsc_bymac(vf_netdev->perm_addr); + if (!ndev) + return NOTIFY_DONE; net_device_ctx = netdev_priv(ndev); netvsc_dev = rtnl_dereference(net_device_ctx->nvdev); if (!netvsc_dev || rtnl_dereference(net_device_ctx->vf_netdev)) - return -ENODEV; - - return 0; -} + return NOTIFY_DONE; -static int netvsc_register_vf(struct net_device *vf_netdev, - struct net_device *ndev) -{ - struct net_device_context *ndev_ctx = netdev_priv(ndev); - - /* set slave flag before open to prevent IPv6 addrconf */ - vf_netdev->flags |= IFF_SLAVE; - - schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT); + /* if syntihetic interface is a different namespace, + * then move the VF to that namespace; join will be + * done again in that context. + */ + if (!net_eq(dev_net(ndev), dev_net(vf_netdev))) { + ret = dev_change_net_namespace(vf_netdev, + dev_net(ndev), "eth%d"); + if (ret) + netdev_err(vf_netdev, + "could not move to same namespace as %s: %d\n", + ndev->name, ret); + else + netdev_info(vf_netdev, + "VF moved to namespace with: %s\n", + ndev->name); + return NOTIFY_DONE; + } - call_netdevice_notifiers(NETDEV_JOIN, vf_netdev); + netdev_info(ndev, "VF registering: %s\n", vf_netdev->name); - netdev_info(vf_netdev, "joined to %s\n", ndev->name); + if (netvsc_vf_join(vf_netdev, ndev) != 0) + return NOTIFY_DONE; dev_hold(vf_netdev); - rcu_assign_pointer(ndev_ctx->vf_netdev, vf_netdev); - - return 0; + rcu_assign_pointer(net_device_ctx->vf_netdev, vf_netdev); + return NOTIFY_OK; } /* VF up/down change detected, schedule to change data path */ -static int netvsc_vf_changed(struct net_device *vf_netdev, - struct net_device *ndev) +static int netvsc_vf_changed(struct net_device *vf_netdev) { struct net_device_context *net_device_ctx; struct netvsc_device *netvsc_dev; + struct net_device *ndev; bool vf_is_up = netif_running(vf_netdev); + ndev = get_netvsc_byref(vf_netdev); + if (!ndev) + return NOTIFY_DONE; + net_device_ctx = netdev_priv(ndev); netvsc_dev = rtnl_dereference(net_device_ctx->nvdev); if (!netvsc_dev) - return -ENODEV; + return NOTIFY_DONE; netvsc_switch_datapath(ndev, vf_is_up); netdev_info(ndev, "Data path switched %s VF: %s\n", vf_is_up ? "to" : "from", vf_netdev->name); - return 0; + return NOTIFY_OK; } -static int netvsc_pre_unregister_vf(struct net_device *vf_netdev, - struct net_device *ndev) +static int netvsc_unregister_vf(struct net_device *vf_netdev) { + struct net_device *ndev; struct net_device_context *net_device_ctx; - net_device_ctx = netdev_priv(ndev); - cancel_delayed_work_sync(&net_device_ctx->vf_takeover); - - return 0; -} - -static int netvsc_unregister_vf(struct net_device *vf_netdev, - struct net_device *ndev) -{ - struct net_device_context *net_device_ctx; + ndev = get_netvsc_byref(vf_netdev); + if (!ndev) + return NOTIFY_DONE; net_device_ctx = netdev_priv(ndev); + cancel_delayed_work_sync(&net_device_ctx->vf_takeover); netdev_info(ndev, "VF unregistering: %s\n", vf_netdev->name); + netdev_rx_handler_unregister(vf_netdev); + netdev_upper_dev_unlink(vf_netdev, ndev); RCU_INIT_POINTER(net_device_ctx->vf_netdev, NULL); dev_put(vf_netdev); - return 0; + return NOTIFY_OK; } -static struct failover_ops netvsc_failover_ops = { - .slave_pre_register = netvsc_pre_register_vf, - .slave_register = netvsc_register_vf, - .slave_pre_unregister = netvsc_pre_unregister_vf, - .slave_unregister = netvsc_unregister_vf, - .slave_link_change = netvsc_vf_changed, - .slave_handle_frame = netvsc_vf_handle_frame, -}; - static int netvsc_probe(struct hv_device *dev, const struct hv_vmbus_device_id *dev_id) { @@ -2024,23 +2104,19 @@ static int netvsc_probe(struct hv_device *dev, else net->max_mtu = ETH_DATA_LEN; - ret = register_netdev(net); + rtnl_lock(); + ret = register_netdevice(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); goto register_failed; } - net_device_ctx->failover = failover_register(net, &netvsc_failover_ops); - if (IS_ERR(net_device_ctx->failover)) { - ret = PTR_ERR(net_device_ctx->failover); - goto err_failover; - } - - return ret; + list_add(&net_device_ctx->list, &netvsc_dev_list); + rtnl_unlock(); + return 0; -err_failover: - unregister_netdev(net); register_failed: + rtnl_unlock(); rndis_filter_device_remove(dev, nvdev); rndis_failed: free_percpu(net_device_ctx->vf_stats); @@ -2080,14 +2156,13 @@ static int netvsc_remove(struct hv_device *dev) rtnl_lock(); vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev); if (vf_netdev) - failover_slave_unregister(vf_netdev); + netvsc_unregister_vf(vf_netdev); if (nvdev) rndis_filter_device_remove(dev, nvdev); unregister_netdevice(net); - - failover_unregister(ndev_ctx->failover); + list_del(&ndev_ctx->list); rtnl_unlock(); rcu_read_unlock(); @@ -2115,8 +2190,54 @@ static struct hv_driver netvsc_drv = { .remove = netvsc_remove, }; +/* + * On Hyper-V, every VF interface is matched with a corresponding + * synthetic interface. The synthetic interface is presented first + * to the guest. When the corresponding VF instance is registered, + * we will take care of switching the data path. + */ +static int netvsc_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); + + /* Skip our own events */ + if (event_dev->netdev_ops == &device_ops) + return NOTIFY_DONE; + + /* Avoid non-Ethernet type devices */ + if (event_dev->type != ARPHRD_ETHER) + return NOTIFY_DONE; + + /* Avoid Vlan dev with same MAC registering as VF */ + if (is_vlan_dev(event_dev)) + return NOTIFY_DONE; + + /* Avoid Bonding master dev with same MAC registering as VF */ + if ((event_dev->priv_flags & IFF_BONDING) && + (event_dev->flags & IFF_MASTER)) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_REGISTER: + return netvsc_register_vf(event_dev); + case NETDEV_UNREGISTER: + return netvsc_unregister_vf(event_dev); + case NETDEV_UP: + case NETDEV_DOWN: + return netvsc_vf_changed(event_dev); + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block netvsc_netdev_notifier = { + .notifier_call = netvsc_netdev_event, +}; + static void __exit netvsc_drv_exit(void) { + unregister_netdevice_notifier(&netvsc_netdev_notifier); vmbus_driver_unregister(&netvsc_drv); } @@ -2135,6 +2256,7 @@ static int __init netvsc_drv_init(void) if (ret) return ret; + register_netdevice_notifier(&netvsc_netdev_notifier); return 0; } diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 4e4c8daf44c3..33265747bf39 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -26,10 +26,7 @@ #include <linux/platform_device.h> #include <linux/mdio-bitbang.h> #include <linux/mdio-gpio.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> - -#include <linux/of_gpio.h> #include <linux/of_mdio.h> struct mdio_gpio_info { diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9825bfd42abc..18e819d964f1 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3572,11 +3572,14 @@ static int __init init_mac80211_hwsim(void) hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0); if (!hwsim_wq) return -ENOMEM; - rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); + + err = rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params); + if (err) + goto out_free_wq; err = register_pernet_device(&hwsim_net_ops); if (err) - return err; + goto out_free_rht; err = platform_driver_register(&mac80211_hwsim_driver); if (err) @@ -3701,6 +3704,10 @@ out_unregister_driver: platform_driver_unregister(&mac80211_hwsim_driver); out_unregister_pernet: unregister_pernet_device(&hwsim_net_ops); +out_free_rht: + rhashtable_destroy(&hwsim_radios_rht); +out_free_wq: + destroy_workqueue(hwsim_wq); return err; } module_init(init_mac80211_hwsim); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 679da1abd73c..922ce0abf5cf 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -239,7 +239,7 @@ static void rx_refill_timeout(struct timer_list *t) static int netfront_tx_slot_available(struct netfront_queue *queue) { return (queue->tx.req_prod_pvt - queue->tx.rsp_cons) < - (NET_TX_RING_SIZE - MAX_SKB_FRAGS - 2); + (NET_TX_RING_SIZE - XEN_NETIF_NR_SLOTS_MIN - 1); } static void xennet_maybe_wake_tx(struct netfront_queue *queue) @@ -790,7 +790,7 @@ static int xennet_get_responses(struct netfront_queue *queue, RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *skb = xennet_get_rx_skb(queue, cons); grant_ref_t ref = xennet_get_rx_ref(queue, cons); - int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD); + int max = XEN_NETIF_NR_SLOTS_MIN + (rx->status <= RX_COPY_THRESHOLD); int slots = 1; int err = 0; unsigned long ret; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ce8c95b6365b..a502f1af4a21 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -2349,6 +2349,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index d94254263ea5..591a13a59787 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1437,7 +1437,7 @@ config FB_SIS_315 config FB_VIA tristate "VIA UniChrome (Pro) and Chrome9 display support" - depends on FB && PCI && X86 && GPIOLIB && I2C + depends on FB && PCI && GPIOLIB && I2C && (X86 || COMPILE_TEST) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT @@ -1888,7 +1888,6 @@ config FB_W100 config FB_SH_MOBILE_LCDC tristate "SuperH Mobile LCDC framebuffer support" depends on FB && (SUPERH || ARCH_RENESAS) && HAVE_CLK - depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT @@ -2253,39 +2252,6 @@ config FB_BROADSHEET and could also have been called by other names when coupled with a bridge adapter. -config FB_AUO_K190X - tristate "AUO-K190X EPD controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - Provides support for epaper controllers from the K190X series - of AUO. These controllers can be used to drive epaper displays - from Sipix. - - This option enables the common support, shared by the individual - controller drivers. You will also have to enable the driver - for the controller type used in your device. - -config FB_AUO_K1900 - tristate "AUO-K1900 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1900 epd-controller. - This controller can drive Sipix epaper displays but can only do - serial updates, reducing the number of possible frames per second. - -config FB_AUO_K1901 - tristate "AUO-K1901 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1901 epd-controller. - This controller can drive Sipix epaper displays and supports - concurrent updates, making higher frames per second possible. - config FB_JZ4740 tristate "JZ4740 LCD framebuffer support" depends on FB && MACH_JZ4740 @@ -2346,18 +2312,6 @@ source "drivers/video/fbdev/omap/Kconfig" source "drivers/video/fbdev/omap2/Kconfig" source "drivers/video/fbdev/mmp/Kconfig" -config FB_SH_MOBILE_MERAM - tristate "SuperH Mobile MERAM read ahead support" - depends on (SUPERH || ARCH_SHMOBILE) - select GENERIC_ALLOCATOR - ---help--- - Enable MERAM support for the SuperH controller. - - This will allow for caching of the framebuffer to provide more - reliable access under heavy main memory bus traffic situations. - Up to 4 memory channels can be configured, allowing 4 RGB or - 2 YCbCr framebuffers to be configured. - config FB_SSD1307 tristate "Solomon SSD1307 framebuffer support" depends on FB && I2C diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 55282a21b500..13c900320c2c 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -100,9 +100,6 @@ obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o obj-$(CONFIG_FB_MAXINE) += maxinefb.o obj-$(CONFIG_FB_METRONOME) += metronomefb.o obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o -obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o -obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o -obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_SH7760) += sh7760fb.o obj-$(CONFIG_FB_IMX) += imxfb.o @@ -116,7 +113,6 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o obj-$(CONFIG_FB_UDL) += udlfb.o obj-$(CONFIG_FB_SMSCUFX) += smscufx.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o -obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o obj-$(CONFIG_FB_OMAP) += omap/ obj-y += omap2/ diff --git a/drivers/video/fbdev/aty/aty128fb.c b/drivers/video/fbdev/aty/aty128fb.c index 09b0e558dce8..6cc46867ff57 100644 --- a/drivers/video/fbdev/aty/aty128fb.c +++ b/drivers/video/fbdev/aty/aty128fb.c @@ -2442,7 +2442,7 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend) (void)aty_ld_pll(POWER_MANAGEMENT); aty_st_le32(BUS_CNTL1, 0x00000010); aty_st_le32(MEM_POWER_MISC, 0x0c830000); - mdelay(100); + msleep(100); /* Switch PCI power management to D2 */ pci_set_power_state(pdev, PCI_D2); diff --git a/drivers/video/fbdev/aty/radeon_pm.c b/drivers/video/fbdev/aty/radeon_pm.c index 7137c12cbcee..e695adb0e573 100644 --- a/drivers/video/fbdev/aty/radeon_pm.c +++ b/drivers/video/fbdev/aty/radeon_pm.c @@ -2678,17 +2678,17 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) * it, we'll restore the dynamic clocks state on wakeup */ radeon_pm_disable_dynamic_mode(rinfo); - mdelay(50); + msleep(50); radeon_pm_save_regs(rinfo, 1); if (rinfo->is_mobility && !(rinfo->pm_mode & radeon_pm_d2)) { /* Switch off LVDS interface */ - mdelay(1); + usleep_range(1000, 2000); OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_BL_MOD_EN)); - mdelay(1); + usleep_range(1000, 2000); OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_EN | LVDS_ON)); OUTREG(LVDS_PLL_CNTL, (INREG(LVDS_PLL_CNTL) & ~30000) | 0x20000); - mdelay(20); + msleep(20); OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON)); } pci_disable_device(pdev); diff --git a/drivers/video/fbdev/au1100fb.c b/drivers/video/fbdev/au1100fb.c index d555a78df5c6..0adf0683cf08 100644 --- a/drivers/video/fbdev/au1100fb.c +++ b/drivers/video/fbdev/au1100fb.c @@ -464,7 +464,7 @@ static int au1100fb_drv_probe(struct platform_device *dev) PAGE_ALIGN(fbdev->fb_len), &fbdev->fb_phys, GFP_KERNEL); if (!fbdev->fb_mem) { - print_err("fail to allocate frambuffer (size: %dK))", + print_err("fail to allocate framebuffer (size: %dK))", fbdev->fb_len / 1024); return -ENOMEM; } diff --git a/drivers/video/fbdev/au1200fb.c b/drivers/video/fbdev/au1200fb.c index 87d5a62bf6ca..3872ccef4cb2 100644 --- a/drivers/video/fbdev/au1200fb.c +++ b/drivers/video/fbdev/au1200fb.c @@ -1696,7 +1696,7 @@ static int au1200fb_drv_probe(struct platform_device *dev) &fbdev->fb_phys, GFP_KERNEL, DMA_ATTR_NON_CONSISTENT); if (!fbdev->fb_mem) { - print_err("fail to allocate frambuffer (size: %dK))", + print_err("fail to allocate framebuffer (size: %dK))", fbdev->fb_len / 1024); ret = -ENOMEM; goto failed; diff --git a/drivers/video/fbdev/auo_k1900fb.c b/drivers/video/fbdev/auo_k1900fb.c deleted file mode 100644 index 7637c60eae3d..000000000000 --- a/drivers/video/fbdev/auo_k1900fb.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * auok190xfb.c -- FB driver for AUO-K1900 controllers - * - * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de> - * - * based on broadsheetfb.c - * - * Copyright (C) 2008, Jaya Kumar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. - * - * This driver is written to be used with the AUO-K1900 display controller. - * - * It is intended to be architecture independent. A board specific driver - * must be used to perform all the physical IO interactions. - * - * The controller supports different update modes: - * mode0+1 16 step gray (4bit) - * mode2 4 step gray (2bit) - FIXME: add strange refresh - * mode3 2 step gray (1bit) - FIXME: add strange refresh - * mode4 handwriting mode (strange behaviour) - * mode5 automatic selection of update mode - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/list.h> -#include <linux/firmware.h> -#include <linux/gpio.h> -#include <linux/pm_runtime.h> - -#include <video/auo_k190xfb.h> - -#include "auo_k190x.h" - -/* - * AUO-K1900 specific commands - */ - -#define AUOK1900_CMD_PARTIALDISP 0x1001 -#define AUOK1900_CMD_ROTATION 0x1006 -#define AUOK1900_CMD_LUT_STOP 0x1009 - -#define AUOK1900_INIT_TEMP_AVERAGE (1 << 13) -#define AUOK1900_INIT_ROTATE(_x) ((_x & 0x3) << 10) -#define AUOK1900_INIT_RESOLUTION(_res) ((_res & 0x7) << 2) - -static void auok1900_init(struct auok190xfb_par *par) -{ - struct device *dev = par->info->device; - struct auok190x_board *board = par->board; - u16 init_param = 0; - - pm_runtime_get_sync(dev); - - init_param |= AUOK1900_INIT_TEMP_AVERAGE; - init_param |= AUOK1900_INIT_ROTATE(par->rotation); - init_param |= AUOK190X_INIT_INVERSE_WHITE; - init_param |= AUOK190X_INIT_FORMAT0; - init_param |= AUOK1900_INIT_RESOLUTION(par->resolution); - init_param |= AUOK190X_INIT_SHIFT_RIGHT; - - auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param); - - /* let the controller finish */ - board->wait_for_rdy(par); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); -} - -static void auok1900_update_region(struct auok190xfb_par *par, int mode, - u16 y1, u16 y2) -{ - struct device *dev = par->info->device; - unsigned char *buf = (unsigned char *)par->info->screen_base; - int xres = par->info->var.xres; - int line_length = par->info->fix.line_length; - u16 args[4]; - - pm_runtime_get_sync(dev); - - mutex_lock(&(par->io_lock)); - - /* y1 and y2 must be a multiple of 2 so drop the lowest bit */ - y1 &= 0xfffe; - y2 &= 0xfffe; - - dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n", - 1, y1+1, xres, y2-y1, mode); - - /* to FIX handle different partial update modes */ - args[0] = mode | 1; - args[1] = y1 + 1; - args[2] = xres; - args[3] = y2 - y1; - buf += y1 * line_length; - auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args, - ((y2 - y1) * line_length)/2, (u16 *) buf); - auok190x_send_command(par, AUOK190X_CMD_DATA_STOP); - - par->update_cnt++; - - mutex_unlock(&(par->io_lock)); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); -} - -static void auok1900fb_dpy_update_pages(struct auok190xfb_par *par, - u16 y1, u16 y2) -{ - int mode; - - if (par->update_mode < 0) { - mode = AUOK190X_UPDATE_MODE(1); - par->last_mode = -1; - } else { - mode = AUOK190X_UPDATE_MODE(par->update_mode); - par->last_mode = par->update_mode; - } - - if (par->flash) - mode |= AUOK190X_UPDATE_NONFLASH; - - auok1900_update_region(par, mode, y1, y2); -} - -static void auok1900fb_dpy_update(struct auok190xfb_par *par) -{ - int mode; - - if (par->update_mode < 0) { - mode = AUOK190X_UPDATE_MODE(0); - par->last_mode = -1; - } else { - mode = AUOK190X_UPDATE_MODE(par->update_mode); - par->last_mode = par->update_mode; - } - - if (par->flash) - mode |= AUOK190X_UPDATE_NONFLASH; - - auok1900_update_region(par, mode, 0, par->info->var.yres); - par->update_cnt = 0; -} - -static bool auok1900fb_need_refresh(struct auok190xfb_par *par) -{ - return (par->update_cnt > 10); -} - -static int auok1900fb_probe(struct platform_device *pdev) -{ - struct auok190x_init_data init; - struct auok190x_board *board; - - /* pick up board specific routines */ - board = pdev->dev.platform_data; - if (!board) - return -EINVAL; - - /* fill temporary init struct for common init */ - init.id = "auo_k1900fb"; - init.board = board; - init.update_partial = auok1900fb_dpy_update_pages; - init.update_all = auok1900fb_dpy_update; - init.need_refresh = auok1900fb_need_refresh; - init.init = auok1900_init; - - return auok190x_common_probe(pdev, &init); -} - -static int auok1900fb_remove(struct platform_device *pdev) -{ - return auok190x_common_remove(pdev); -} - -static struct platform_driver auok1900fb_driver = { - .probe = auok1900fb_probe, - .remove = auok1900fb_remove, - .driver = { - .name = "auo_k1900fb", - .pm = &auok190x_pm, - }, -}; -module_platform_driver(auok1900fb_driver); - -MODULE_DESCRIPTION("framebuffer driver for the AUO-K1900 EPD controller"); -MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/auo_k1901fb.c b/drivers/video/fbdev/auo_k1901fb.c deleted file mode 100644 index 681fe61957b6..000000000000 --- a/drivers/video/fbdev/auo_k1901fb.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * auok190xfb.c -- FB driver for AUO-K1901 controllers - * - * Copyright (C) 2011, 2012 Heiko Stuebner <heiko@sntech.de> - * - * based on broadsheetfb.c - * - * Copyright (C) 2008, Jaya Kumar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. - * - * This driver is written to be used with the AUO-K1901 display controller. - * - * It is intended to be architecture independent. A board specific driver - * must be used to perform all the physical IO interactions. - * - * The controller supports different update modes: - * mode0+1 16 step gray (4bit) - * mode2+3 4 step gray (2bit) - * mode4+5 2 step gray (1bit) - * - mode4 is described as "without LUT" - * mode7 automatic selection of update mode - * - * The most interesting difference to the K1900 is the ability to do screen - * updates in an asynchronous fashion. Where the K1900 needs to wait for the - * current update to complete, the K1901 can process later updates already. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/list.h> -#include <linux/firmware.h> -#include <linux/gpio.h> -#include <linux/pm_runtime.h> - -#include <video/auo_k190xfb.h> - -#include "auo_k190x.h" - -/* - * AUO-K1901 specific commands - */ - -#define AUOK1901_CMD_LUT_INTERFACE 0x0005 -#define AUOK1901_CMD_DMA_START 0x1001 -#define AUOK1901_CMD_CURSOR_START 0x1007 -#define AUOK1901_CMD_CURSOR_STOP AUOK190X_CMD_DATA_STOP -#define AUOK1901_CMD_DDMA_START 0x1009 - -#define AUOK1901_INIT_GATE_PULSE_LOW (0 << 14) -#define AUOK1901_INIT_GATE_PULSE_HIGH (1 << 14) -#define AUOK1901_INIT_SINGLE_GATE (0 << 13) -#define AUOK1901_INIT_DOUBLE_GATE (1 << 13) - -/* Bits to pixels - * Mode 15-12 11-8 7-4 3-0 - * format2 2 T 1 T - * format3 1 T 2 T - * format4 T 2 T 1 - * format5 T 1 T 2 - * - * halftone modes: - * format6 2 2 1 1 - * format7 1 1 2 2 - */ -#define AUOK1901_INIT_FORMAT2 (1 << 7) -#define AUOK1901_INIT_FORMAT3 ((1 << 7) | (1 << 6)) -#define AUOK1901_INIT_FORMAT4 (1 << 8) -#define AUOK1901_INIT_FORMAT5 ((1 << 8) | (1 << 6)) -#define AUOK1901_INIT_FORMAT6 ((1 << 8) | (1 << 7)) -#define AUOK1901_INIT_FORMAT7 ((1 << 8) | (1 << 7) | (1 << 6)) - -/* res[4] to bit 10 - * res[3-0] to bits 5-2 - */ -#define AUOK1901_INIT_RESOLUTION(_res) (((_res & (1 << 4)) << 6) \ - | ((_res & 0xf) << 2)) - -/* - * portrait / landscape orientation in AUOK1901_CMD_DMA_START - */ -#define AUOK1901_DMA_ROTATE90(_rot) ((_rot & 1) << 13) - -/* - * equivalent to 1 << 11, needs the ~ to have same rotation like K1900 - */ -#define AUOK1901_DDMA_ROTATE180(_rot) ((~_rot & 2) << 10) - -static void auok1901_init(struct auok190xfb_par *par) -{ - struct device *dev = par->info->device; - struct auok190x_board *board = par->board; - u16 init_param = 0; - - pm_runtime_get_sync(dev); - - init_param |= AUOK190X_INIT_INVERSE_WHITE; - init_param |= AUOK190X_INIT_FORMAT0; - init_param |= AUOK1901_INIT_RESOLUTION(par->resolution); - init_param |= AUOK190X_INIT_SHIFT_LEFT; - - auok190x_send_cmdargs(par, AUOK190X_CMD_INIT, 1, &init_param); - - /* let the controller finish */ - board->wait_for_rdy(par); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); -} - -static void auok1901_update_region(struct auok190xfb_par *par, int mode, - u16 y1, u16 y2) -{ - struct device *dev = par->info->device; - unsigned char *buf = (unsigned char *)par->info->screen_base; - int xres = par->info->var.xres; - int line_length = par->info->fix.line_length; - u16 args[5]; - - pm_runtime_get_sync(dev); - - mutex_lock(&(par->io_lock)); - - /* y1 and y2 must be a multiple of 2 so drop the lowest bit */ - y1 &= 0xfffe; - y2 &= 0xfffe; - - dev_dbg(dev, "update (x,y,w,h,mode)=(%d,%d,%d,%d,%d)\n", - 1, y1+1, xres, y2-y1, mode); - - /* K1901: first transfer the region data */ - args[0] = AUOK1901_DMA_ROTATE90(par->rotation) | 1; - args[1] = y1 + 1; - args[2] = xres; - args[3] = y2 - y1; - buf += y1 * line_length; - auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4, - args, ((y2 - y1) * line_length)/2, - (u16 *) buf); - auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP); - - /* K1901: second tell the controller to update the region with mode */ - args[0] = mode | AUOK1901_DDMA_ROTATE180(par->rotation); - args[1] = 1; - args[2] = y1 + 1; - args[3] = xres; - args[4] = y2 - y1; - auok190x_send_cmdargs_nowait(par, AUOK1901_CMD_DDMA_START, 5, args); - - par->update_cnt++; - - mutex_unlock(&(par->io_lock)); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); -} - -static void auok1901fb_dpy_update_pages(struct auok190xfb_par *par, - u16 y1, u16 y2) -{ - int mode; - - if (par->update_mode < 0) { - mode = AUOK190X_UPDATE_MODE(1); - par->last_mode = -1; - } else { - mode = AUOK190X_UPDATE_MODE(par->update_mode); - par->last_mode = par->update_mode; - } - - if (par->flash) - mode |= AUOK190X_UPDATE_NONFLASH; - - auok1901_update_region(par, mode, y1, y2); -} - -static void auok1901fb_dpy_update(struct auok190xfb_par *par) -{ - int mode; - - /* When doing full updates, wait for the controller to be ready - * This will hopefully catch some hangs of the K1901 - */ - par->board->wait_for_rdy(par); - - if (par->update_mode < 0) { - mode = AUOK190X_UPDATE_MODE(0); - par->last_mode = -1; - } else { - mode = AUOK190X_UPDATE_MODE(par->update_mode); - par->last_mode = par->update_mode; - } - - if (par->flash) - mode |= AUOK190X_UPDATE_NONFLASH; - - auok1901_update_region(par, mode, 0, par->info->var.yres); - par->update_cnt = 0; -} - -static bool auok1901fb_need_refresh(struct auok190xfb_par *par) -{ - return (par->update_cnt > 10); -} - -static int auok1901fb_probe(struct platform_device *pdev) -{ - struct auok190x_init_data init; - struct auok190x_board *board; - - /* pick up board specific routines */ - board = pdev->dev.platform_data; - if (!board) - return -EINVAL; - - /* fill temporary init struct for common init */ - init.id = "auo_k1901fb"; - init.board = board; - init.update_partial = auok1901fb_dpy_update_pages; - init.update_all = auok1901fb_dpy_update; - init.need_refresh = auok1901fb_need_refresh; - init.init = auok1901_init; - - return auok190x_common_probe(pdev, &init); -} - -static int auok1901fb_remove(struct platform_device *pdev) -{ - return auok190x_common_remove(pdev); -} - -static struct platform_driver auok1901fb_driver = { - .probe = auok1901fb_probe, - .remove = auok1901fb_remove, - .driver = { - .name = "auo_k1901fb", - .pm = &auok190x_pm, - }, -}; -module_platform_driver(auok1901fb_driver); - -MODULE_DESCRIPTION("framebuffer driver for the AUO-K1901 EPD controller"); -MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/auo_k190x.c b/drivers/video/fbdev/auo_k190x.c deleted file mode 100644 index 9d24d1b3e9ef..000000000000 --- a/drivers/video/fbdev/auo_k190x.c +++ /dev/null @@ -1,1195 +0,0 @@ -/* - * Common code for AUO-K190X framebuffer drivers - * - * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/sched/mm.h> -#include <linux/kernel.h> -#include <linux/gpio.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/fb.h> -#include <linux/delay.h> -#include <linux/uaccess.h> -#include <linux/vmalloc.h> -#include <linux/regulator/consumer.h> - -#include <video/auo_k190xfb.h> - -#include "auo_k190x.h" - -struct panel_info { - int w; - int h; -}; - -/* table of panel specific parameters to be indexed into by the board drivers */ -static struct panel_info panel_table[] = { - /* standard 6" */ - [AUOK190X_RESOLUTION_800_600] = { - .w = 800, - .h = 600, - }, - /* standard 9" */ - [AUOK190X_RESOLUTION_1024_768] = { - .w = 1024, - .h = 768, - }, - [AUOK190X_RESOLUTION_600_800] = { - .w = 600, - .h = 800, - }, - [AUOK190X_RESOLUTION_768_1024] = { - .w = 768, - .h = 1024, - }, -}; - -/* - * private I80 interface to the board driver - */ - -static void auok190x_issue_data(struct auok190xfb_par *par, u16 data) -{ - par->board->set_ctl(par, AUOK190X_I80_WR, 0); - par->board->set_hdb(par, data); - par->board->set_ctl(par, AUOK190X_I80_WR, 1); -} - -static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data) -{ - par->board->set_ctl(par, AUOK190X_I80_DC, 0); - auok190x_issue_data(par, data); - par->board->set_ctl(par, AUOK190X_I80_DC, 1); -} - -/** - * Conversion of 16bit color to 4bit grayscale - * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2 - */ -static inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var) -{ - return ((((data & 0xF800) >> var->red.offset) * 77 + - ((data & 0x07E0) >> (var->green.offset + 1)) * 151 + - ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1); -} - -static int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size, - u16 *data) -{ - struct fb_var_screeninfo *var = &par->info->var; - struct device *dev = par->info->device; - int i; - u16 tmp; - - if (size & 7) { - dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n", - size); - return -EINVAL; - } - - for (i = 0; i < (size >> 2); i++) { - par->board->set_ctl(par, AUOK190X_I80_WR, 0); - - tmp = (rgb565_to_gray4(data[4*i], var) & 0x000F); - tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0; - tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00; - tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000; - - par->board->set_hdb(par, tmp); - par->board->set_ctl(par, AUOK190X_I80_WR, 1); - } - - return 0; -} - -static int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size, - u16 *data) -{ - struct device *dev = par->info->device; - int i; - u16 tmp; - - if (size & 3) { - dev_err(dev, "issue_pixels: size %d must be a multiple of 4\n", - size); - return -EINVAL; - } - - for (i = 0; i < (size >> 1); i++) { - par->board->set_ctl(par, AUOK190X_I80_WR, 0); - - /* simple reduction of 8bit staticgray to 4bit gray - * combines 4 * 4bit pixel values into a 16bit value - */ - tmp = (data[2*i] & 0xF0) >> 4; - tmp |= (data[2*i] & 0xF000) >> 8; - tmp |= (data[2*i+1] & 0xF0) << 4; - tmp |= (data[2*i+1] & 0xF000); - - par->board->set_hdb(par, tmp); - par->board->set_ctl(par, AUOK190X_I80_WR, 1); - } - - return 0; -} - -static int auok190x_issue_pixels(struct auok190xfb_par *par, int size, - u16 *data) -{ - struct fb_info *info = par->info; - struct device *dev = par->info->device; - - if (info->var.bits_per_pixel == 8 && info->var.grayscale) - auok190x_issue_pixels_gray8(par, size, data); - else if (info->var.bits_per_pixel == 16) - auok190x_issue_pixels_rgb565(par, size, data); - else - dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n", - info->var.bits_per_pixel, info->var.grayscale); - - return 0; -} - -static u16 auok190x_read_data(struct auok190xfb_par *par) -{ - u16 data; - - par->board->set_ctl(par, AUOK190X_I80_OE, 0); - data = par->board->get_hdb(par); - par->board->set_ctl(par, AUOK190X_I80_OE, 1); - - return data; -} - -/* - * Command interface for the controller drivers - */ - -void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data) -{ - par->board->set_ctl(par, AUOK190X_I80_CS, 0); - auok190x_issue_cmd(par, data); - par->board->set_ctl(par, AUOK190X_I80_CS, 1); -} -EXPORT_SYMBOL_GPL(auok190x_send_command_nowait); - -void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv) -{ - int i; - - par->board->set_ctl(par, AUOK190X_I80_CS, 0); - auok190x_issue_cmd(par, cmd); - - for (i = 0; i < argc; i++) - auok190x_issue_data(par, argv[i]); - par->board->set_ctl(par, AUOK190X_I80_CS, 1); -} -EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_nowait); - -int auok190x_send_command(struct auok190xfb_par *par, u16 data) -{ - int ret; - - ret = par->board->wait_for_rdy(par); - if (ret) - return ret; - - auok190x_send_command_nowait(par, data); - return 0; -} -EXPORT_SYMBOL_GPL(auok190x_send_command); - -int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv) -{ - int ret; - - ret = par->board->wait_for_rdy(par); - if (ret) - return ret; - - auok190x_send_cmdargs_nowait(par, cmd, argc, argv); - return 0; -} -EXPORT_SYMBOL_GPL(auok190x_send_cmdargs); - -int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv) -{ - int i, ret; - - ret = par->board->wait_for_rdy(par); - if (ret) - return ret; - - par->board->set_ctl(par, AUOK190X_I80_CS, 0); - auok190x_issue_cmd(par, cmd); - - for (i = 0; i < argc; i++) - argv[i] = auok190x_read_data(par); - par->board->set_ctl(par, AUOK190X_I80_CS, 1); - - return 0; -} -EXPORT_SYMBOL_GPL(auok190x_read_cmdargs); - -void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv, int size, u16 *data) -{ - int i; - - par->board->set_ctl(par, AUOK190X_I80_CS, 0); - - auok190x_issue_cmd(par, cmd); - - for (i = 0; i < argc; i++) - auok190x_issue_data(par, argv[i]); - - auok190x_issue_pixels(par, size, data); - - par->board->set_ctl(par, AUOK190X_I80_CS, 1); -} -EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels_nowait); - -int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv, int size, u16 *data) -{ - int ret; - - ret = par->board->wait_for_rdy(par); - if (ret) - return ret; - - auok190x_send_cmdargs_pixels_nowait(par, cmd, argc, argv, size, data); - - return 0; -} -EXPORT_SYMBOL_GPL(auok190x_send_cmdargs_pixels); - -/* - * fbdefio callbacks - common on both controllers. - */ - -static void auok190xfb_dpy_first_io(struct fb_info *info) -{ - /* tell runtime-pm that we wish to use the device in a short time */ - pm_runtime_get(info->device); -} - -/* this is called back from the deferred io workqueue */ -static void auok190xfb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) -{ - struct fb_deferred_io *fbdefio = info->fbdefio; - struct auok190xfb_par *par = info->par; - u16 line_length = info->fix.line_length; - u16 yres = info->var.yres; - u16 y1 = 0, h = 0; - int prev_index = -1; - struct page *cur; - int h_inc; - int threshold; - - if (!list_empty(pagelist)) - /* the device resume should've been requested through first_io, - * if the resume did not finish until now, wait for it. - */ - pm_runtime_barrier(info->device); - else - /* We reached this via the fsync or some other way. - * In either case the first_io function did not run, - * so we runtime_resume the device here synchronously. - */ - pm_runtime_get_sync(info->device); - - /* Do a full screen update every n updates to prevent - * excessive darkening of the Sipix display. - * If we do this, there is no need to walk the pages. - */ - if (par->need_refresh(par)) { - par->update_all(par); - goto out; - } - - /* height increment is fixed per page */ - h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length); - - /* calculate number of pages from pixel height */ - threshold = par->consecutive_threshold / h_inc; - if (threshold < 1) - threshold = 1; - - /* walk the written page list and swizzle the data */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - if (prev_index < 0) { - /* just starting so assign first page */ - y1 = (cur->index << PAGE_SHIFT) / line_length; - h = h_inc; - } else if ((cur->index - prev_index) <= threshold) { - /* page is within our threshold for single updates */ - h += h_inc * (cur->index - prev_index); - } else { - /* page not consecutive, issue previous update first */ - par->update_partial(par, y1, y1 + h); - - /* start over with our non consecutive page */ - y1 = (cur->index << PAGE_SHIFT) / line_length; - h = h_inc; - } - prev_index = cur->index; - } - - /* if we still have any pages to update we do so now */ - if (h >= yres) - /* its a full screen update, just do it */ - par->update_all(par); - else - par->update_partial(par, y1, min((u16) (y1 + h), yres)); - -out: - pm_runtime_mark_last_busy(info->device); - pm_runtime_put_autosuspend(info->device); -} - -/* - * framebuffer operations - */ - -/* - * this is the slow path from userspace. they can seek and write to - * the fb. it's inefficient to do anything less than a full screen draw - */ -static ssize_t auok190xfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct auok190xfb_par *par = info->par; - unsigned long p = *ppos; - void *dst; - int err = 0; - unsigned long total_size; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->fix.smem_len; - - if (p > total_size) - return -EFBIG; - - if (count > total_size) { - err = -EFBIG; - count = total_size; - } - - if (count + p > total_size) { - if (!err) - err = -ENOSPC; - - count = total_size - p; - } - - dst = (void *)(info->screen_base + p); - - if (copy_from_user(dst, buf, count)) - err = -EFAULT; - - if (!err) - *ppos += count; - - par->update_all(par); - - return (err) ? err : count; -} - -static void auok190xfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct auok190xfb_par *par = info->par; - - sys_fillrect(info, rect); - - par->update_all(par); -} - -static void auok190xfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct auok190xfb_par *par = info->par; - - sys_copyarea(info, area); - - par->update_all(par); -} - -static void auok190xfb_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct auok190xfb_par *par = info->par; - - sys_imageblit(info, image); - - par->update_all(par); -} - -static int auok190xfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct device *dev = info->device; - struct auok190xfb_par *par = info->par; - struct panel_info *panel = &panel_table[par->resolution]; - int size; - - /* - * Color depth - */ - - if (var->bits_per_pixel == 8 && var->grayscale == 1) { - /* - * For 8-bit grayscale, R, G, and B offset are equal. - */ - var->red.length = 8; - var->red.offset = 0; - var->red.msb_right = 0; - - var->green.length = 8; - var->green.offset = 0; - var->green.msb_right = 0; - - var->blue.length = 8; - var->blue.offset = 0; - var->blue.msb_right = 0; - - var->transp.length = 0; - var->transp.offset = 0; - var->transp.msb_right = 0; - } else if (var->bits_per_pixel == 16) { - var->red.length = 5; - var->red.offset = 11; - var->red.msb_right = 0; - - var->green.length = 6; - var->green.offset = 5; - var->green.msb_right = 0; - - var->blue.length = 5; - var->blue.offset = 0; - var->blue.msb_right = 0; - - var->transp.length = 0; - var->transp.offset = 0; - var->transp.msb_right = 0; - } else { - dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n", - info->var.bits_per_pixel, info->var.grayscale); - return -EINVAL; - } - - /* - * Dimensions - */ - - switch (var->rotate) { - case FB_ROTATE_UR: - case FB_ROTATE_UD: - var->xres = panel->w; - var->yres = panel->h; - break; - case FB_ROTATE_CW: - case FB_ROTATE_CCW: - var->xres = panel->h; - var->yres = panel->w; - break; - default: - dev_dbg(dev, "Invalid rotation request\n"); - return -EINVAL; - } - - var->xres_virtual = var->xres; - var->yres_virtual = var->yres; - - /* - * Memory limit - */ - - size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8; - if (size > info->fix.smem_len) { - dev_err(dev, "Memory limit exceeded, requested %dK\n", - size >> 10); - return -ENOMEM; - } - - return 0; -} - -static int auok190xfb_set_fix(struct fb_info *info) -{ - struct fb_fix_screeninfo *fix = &info->fix; - struct fb_var_screeninfo *var = &info->var; - - fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; - - fix->type = FB_TYPE_PACKED_PIXELS; - fix->accel = FB_ACCEL_NONE; - fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR - : FB_VISUAL_TRUECOLOR; - fix->xpanstep = 0; - fix->ypanstep = 0; - fix->ywrapstep = 0; - - return 0; -} - -static int auok190xfb_set_par(struct fb_info *info) -{ - struct auok190xfb_par *par = info->par; - - par->rotation = info->var.rotate; - auok190xfb_set_fix(info); - - /* reinit the controller to honor the rotation */ - par->init(par); - - /* wait for init to complete */ - par->board->wait_for_rdy(par); - - return 0; -} - -static struct fb_ops auok190xfb_ops = { - .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = auok190xfb_write, - .fb_fillrect = auok190xfb_fillrect, - .fb_copyarea = auok190xfb_copyarea, - .fb_imageblit = auok190xfb_imageblit, - .fb_check_var = auok190xfb_check_var, - .fb_set_par = auok190xfb_set_par, -}; - -/* - * Controller-functions common to both K1900 and K1901 - */ - -static int auok190x_read_temperature(struct auok190xfb_par *par) -{ - struct device *dev = par->info->device; - u16 data[4]; - int temp; - - pm_runtime_get_sync(dev); - - mutex_lock(&(par->io_lock)); - - auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); - - mutex_unlock(&(par->io_lock)); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - - /* sanitize and split of half-degrees for now */ - temp = ((data[0] & AUOK190X_VERSION_TEMP_MASK) >> 1); - - /* handle positive and negative temperatures */ - if (temp >= 201) - return (255 - temp + 1) * (-1); - else - return temp; -} - -static void auok190x_identify(struct auok190xfb_par *par) -{ - struct device *dev = par->info->device; - u16 data[4]; - - pm_runtime_get_sync(dev); - - mutex_lock(&(par->io_lock)); - - auok190x_read_cmdargs(par, AUOK190X_CMD_READ_VERSION, 4, data); - - mutex_unlock(&(par->io_lock)); - - par->epd_type = data[1] & AUOK190X_VERSION_TEMP_MASK; - - par->panel_size_int = AUOK190X_VERSION_SIZE_INT(data[2]); - par->panel_size_float = AUOK190X_VERSION_SIZE_FLOAT(data[2]); - par->panel_model = AUOK190X_VERSION_MODEL(data[2]); - - par->tcon_version = AUOK190X_VERSION_TCON(data[3]); - par->lut_version = AUOK190X_VERSION_LUT(data[3]); - - dev_dbg(dev, "panel %d.%din, model 0x%x, EPD 0x%x TCON-rev 0x%x, LUT-rev 0x%x", - par->panel_size_int, par->panel_size_float, par->panel_model, - par->epd_type, par->tcon_version, par->lut_version); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); -} - -/* - * Sysfs functions - */ - -static ssize_t update_mode_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct auok190xfb_par *par = info->par; - - return sprintf(buf, "%d\n", par->update_mode); -} - -static ssize_t update_mode_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct auok190xfb_par *par = info->par; - int mode, ret; - - ret = kstrtoint(buf, 10, &mode); - if (ret) - return ret; - - par->update_mode = mode; - - /* if we enter a better mode, do a full update */ - if (par->last_mode > 1 && mode < par->last_mode) - par->update_all(par); - - return count; -} - -static ssize_t flash_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct auok190xfb_par *par = info->par; - - return sprintf(buf, "%d\n", par->flash); -} - -static ssize_t flash_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct auok190xfb_par *par = info->par; - int flash, ret; - - ret = kstrtoint(buf, 10, &flash); - if (ret) - return ret; - - if (flash > 0) - par->flash = 1; - else - par->flash = 0; - - return count; -} - -static ssize_t temp_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fb_info *info = dev_get_drvdata(dev); - struct auok190xfb_par *par = info->par; - int temp; - - temp = auok190x_read_temperature(par); - return sprintf(buf, "%d\n", temp); -} - -static DEVICE_ATTR_RW(update_mode); -static DEVICE_ATTR_RW(flash); -static DEVICE_ATTR(temp, 0644, temp_show, NULL); - -static struct attribute *auok190x_attributes[] = { - &dev_attr_update_mode.attr, - &dev_attr_flash.attr, - &dev_attr_temp.attr, - NULL -}; - -static const struct attribute_group auok190x_attr_group = { - .attrs = auok190x_attributes, -}; - -static int auok190x_power(struct auok190xfb_par *par, bool on) -{ - struct auok190x_board *board = par->board; - int ret; - - if (on) { - /* We should maintain POWER up for at least 80ms before set - * RST_N and SLP_N to high (TCON spec 20100803_v35 p59) - */ - ret = regulator_enable(par->regulator); - if (ret) - return ret; - - msleep(200); - gpio_set_value(board->gpio_nrst, 1); - gpio_set_value(board->gpio_nsleep, 1); - msleep(200); - } else { - regulator_disable(par->regulator); - gpio_set_value(board->gpio_nrst, 0); - gpio_set_value(board->gpio_nsleep, 0); - } - - return 0; -} - -/* - * Recovery - powercycle the controller - */ - -static void auok190x_recover(struct auok190xfb_par *par) -{ - struct device *dev = par->info->device; - - auok190x_power(par, 0); - msleep(100); - auok190x_power(par, 1); - - /* after powercycling the device, it's always active */ - pm_runtime_set_active(dev); - par->standby = 0; - - par->init(par); - - /* wait for init to complete */ - par->board->wait_for_rdy(par); -} - -/* - * Power-management - */ -static int __maybe_unused auok190x_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fb_info *info = platform_get_drvdata(pdev); - struct auok190xfb_par *par = info->par; - struct auok190x_board *board = par->board; - u16 standby_param; - - /* take and keep the lock until we are resumed, as the controller - * will never reach the non-busy state when in standby mode - */ - mutex_lock(&(par->io_lock)); - - if (par->standby) { - dev_warn(dev, "already in standby, runtime-pm pairing mismatch\n"); - mutex_unlock(&(par->io_lock)); - return 0; - } - - /* according to runtime_pm.txt runtime_suspend only means, that the - * device will not process data and will not communicate with the CPU - * As we hold the lock, this stays true even without standby - */ - if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { - dev_dbg(dev, "runtime suspend without standby\n"); - goto finish; - } else if (board->quirks & AUOK190X_QUIRK_STANDBYPARAM) { - /* for some TCON versions STANDBY expects a parameter (0) but - * it seems the real tcon version has to be determined yet. - */ - dev_dbg(dev, "runtime suspend with additional empty param\n"); - standby_param = 0; - auok190x_send_cmdargs(par, AUOK190X_CMD_STANDBY, 1, - &standby_param); - } else { - dev_dbg(dev, "runtime suspend without param\n"); - auok190x_send_command(par, AUOK190X_CMD_STANDBY); - } - - msleep(64); - -finish: - par->standby = 1; - - return 0; -} - -static int __maybe_unused auok190x_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fb_info *info = platform_get_drvdata(pdev); - struct auok190xfb_par *par = info->par; - struct auok190x_board *board = par->board; - - if (!par->standby) { - dev_warn(dev, "not in standby, runtime-pm pairing mismatch\n"); - return 0; - } - - if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { - dev_dbg(dev, "runtime resume without standby\n"); - } else { - /* when in standby, controller is always busy - * and only accepts the wakeup command - */ - dev_dbg(dev, "runtime resume from standby\n"); - auok190x_send_command_nowait(par, AUOK190X_CMD_WAKEUP); - - msleep(160); - - /* wait for the controller to be ready and release the lock */ - board->wait_for_rdy(par); - } - - par->standby = 0; - - mutex_unlock(&(par->io_lock)); - - return 0; -} - -static int __maybe_unused auok190x_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fb_info *info = platform_get_drvdata(pdev); - struct auok190xfb_par *par = info->par; - struct auok190x_board *board = par->board; - int ret; - - dev_dbg(dev, "suspend\n"); - if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { - /* suspend via powering off the ic */ - dev_dbg(dev, "suspend with broken standby\n"); - - auok190x_power(par, 0); - } else { - dev_dbg(dev, "suspend using sleep\n"); - - /* the sleep state can only be entered from the standby state. - * pm_runtime_get_noresume gets called before the suspend call. - * So the devices usage count is >0 but it is not necessarily - * active. - */ - if (!pm_runtime_status_suspended(dev)) { - ret = auok190x_runtime_suspend(dev); - if (ret < 0) { - dev_err(dev, "auok190x_runtime_suspend failed with %d\n", - ret); - return ret; - } - par->manual_standby = 1; - } - - gpio_direction_output(board->gpio_nsleep, 0); - } - - msleep(100); - - return 0; -} - -static int __maybe_unused auok190x_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fb_info *info = platform_get_drvdata(pdev); - struct auok190xfb_par *par = info->par; - struct auok190x_board *board = par->board; - - dev_dbg(dev, "resume\n"); - if (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) { - dev_dbg(dev, "resume with broken standby\n"); - - auok190x_power(par, 1); - - par->init(par); - } else { - dev_dbg(dev, "resume from sleep\n"); - - /* device should be in runtime suspend when we were suspended - * and pm_runtime_put_sync gets called after this function. - * So there is no need to touch the standby mode here at all. - */ - gpio_direction_output(board->gpio_nsleep, 1); - msleep(100); - - /* an additional init call seems to be necessary after sleep */ - auok190x_runtime_resume(dev); - par->init(par); - - /* if we were runtime-suspended before, suspend again*/ - if (!par->manual_standby) - auok190x_runtime_suspend(dev); - else - par->manual_standby = 0; - } - - return 0; -} - -const struct dev_pm_ops auok190x_pm = { - SET_RUNTIME_PM_OPS(auok190x_runtime_suspend, auok190x_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(auok190x_suspend, auok190x_resume) -}; -EXPORT_SYMBOL_GPL(auok190x_pm); - -/* - * Common probe and remove code - */ - -int auok190x_common_probe(struct platform_device *pdev, - struct auok190x_init_data *init) -{ - struct auok190x_board *board = init->board; - struct auok190xfb_par *par; - struct fb_info *info; - struct panel_info *panel; - int videomemorysize, ret; - unsigned char *videomemory; - - /* check board contents */ - if (!board->init || !board->cleanup || !board->wait_for_rdy - || !board->set_ctl || !board->set_hdb || !board->get_hdb - || !board->setup_irq) - return -EINVAL; - - info = framebuffer_alloc(sizeof(struct auok190xfb_par), &pdev->dev); - if (!info) - return -ENOMEM; - - par = info->par; - par->info = info; - par->board = board; - par->recover = auok190x_recover; - par->update_partial = init->update_partial; - par->update_all = init->update_all; - par->need_refresh = init->need_refresh; - par->init = init->init; - - /* init update modes */ - par->update_cnt = 0; - par->update_mode = -1; - par->last_mode = -1; - par->flash = 0; - - par->regulator = regulator_get(info->device, "vdd"); - if (IS_ERR(par->regulator)) { - ret = PTR_ERR(par->regulator); - dev_err(info->device, "Failed to get regulator: %d\n", ret); - goto err_reg; - } - - ret = board->init(par); - if (ret) { - dev_err(info->device, "board init failed, %d\n", ret); - goto err_board; - } - - ret = gpio_request(board->gpio_nsleep, "AUOK190x sleep"); - if (ret) { - dev_err(info->device, "could not request sleep gpio, %d\n", - ret); - goto err_gpio1; - } - - ret = gpio_direction_output(board->gpio_nsleep, 0); - if (ret) { - dev_err(info->device, "could not set sleep gpio, %d\n", ret); - goto err_gpio2; - } - - ret = gpio_request(board->gpio_nrst, "AUOK190x reset"); - if (ret) { - dev_err(info->device, "could not request reset gpio, %d\n", - ret); - goto err_gpio2; - } - - ret = gpio_direction_output(board->gpio_nrst, 0); - if (ret) { - dev_err(info->device, "could not set reset gpio, %d\n", ret); - goto err_gpio3; - } - - ret = auok190x_power(par, 1); - if (ret) { - dev_err(info->device, "could not power on the device, %d\n", - ret); - goto err_gpio3; - } - - mutex_init(&par->io_lock); - - init_waitqueue_head(&par->waitq); - - ret = par->board->setup_irq(par->info); - if (ret) { - dev_err(info->device, "could not setup ready-irq, %d\n", ret); - goto err_irq; - } - - /* wait for init to complete */ - par->board->wait_for_rdy(par); - - /* - * From here on the controller can talk to us - */ - - /* initialise fix, var, resolution and rotation */ - - strlcpy(info->fix.id, init->id, 16); - info->var.bits_per_pixel = 8; - info->var.grayscale = 1; - - panel = &panel_table[board->resolution]; - - par->resolution = board->resolution; - par->rotation = 0; - - /* videomemory handling */ - - videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE); - videomemory = vzalloc(videomemorysize); - if (!videomemory) { - ret = -ENOMEM; - goto err_irq; - } - - info->screen_base = (char *)videomemory; - info->fix.smem_len = videomemorysize; - - info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; - info->fbops = &auok190xfb_ops; - - ret = auok190xfb_check_var(&info->var, info); - if (ret) - goto err_defio; - - auok190xfb_set_fix(info); - - /* deferred io init */ - - info->fbdefio = devm_kzalloc(info->device, - sizeof(struct fb_deferred_io), - GFP_KERNEL); - if (!info->fbdefio) { - dev_err(info->device, "Failed to allocate memory\n"); - ret = -ENOMEM; - goto err_defio; - } - - dev_dbg(info->device, "targeting %d frames per second\n", board->fps); - info->fbdefio->delay = HZ / board->fps; - info->fbdefio->first_io = auok190xfb_dpy_first_io, - info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io, - fb_deferred_io_init(info); - - /* color map */ - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret < 0) { - dev_err(info->device, "Failed to allocate colormap\n"); - goto err_cmap; - } - - /* controller init */ - - par->consecutive_threshold = 100; - par->init(par); - auok190x_identify(par); - - platform_set_drvdata(pdev, info); - - ret = register_framebuffer(info); - if (ret < 0) - goto err_regfb; - - ret = sysfs_create_group(&info->device->kobj, &auok190x_attr_group); - if (ret) - goto err_sysfs; - - dev_info(info->device, "fb%d: %dx%d using %dK of video memory\n", - info->node, info->var.xres, info->var.yres, - videomemorysize >> 10); - - /* increase autosuspend_delay when we use alternative methods - * for runtime_pm - */ - par->autosuspend_delay = (board->quirks & AUOK190X_QUIRK_STANDBYBROKEN) - ? 1000 : 200; - - pm_runtime_set_active(info->device); - pm_runtime_enable(info->device); - pm_runtime_set_autosuspend_delay(info->device, par->autosuspend_delay); - pm_runtime_use_autosuspend(info->device); - - return 0; - -err_sysfs: - unregister_framebuffer(info); -err_regfb: - fb_dealloc_cmap(&info->cmap); -err_cmap: - fb_deferred_io_cleanup(info); -err_defio: - vfree((void *)info->screen_base); -err_irq: - auok190x_power(par, 0); -err_gpio3: - gpio_free(board->gpio_nrst); -err_gpio2: - gpio_free(board->gpio_nsleep); -err_gpio1: - board->cleanup(par); -err_board: - regulator_put(par->regulator); -err_reg: - framebuffer_release(info); - - return ret; -} -EXPORT_SYMBOL_GPL(auok190x_common_probe); - -int auok190x_common_remove(struct platform_device *pdev) -{ - struct fb_info *info = platform_get_drvdata(pdev); - struct auok190xfb_par *par = info->par; - struct auok190x_board *board = par->board; - - pm_runtime_disable(info->device); - - sysfs_remove_group(&info->device->kobj, &auok190x_attr_group); - - unregister_framebuffer(info); - - fb_dealloc_cmap(&info->cmap); - - fb_deferred_io_cleanup(info); - - vfree((void *)info->screen_base); - - auok190x_power(par, 0); - - gpio_free(board->gpio_nrst); - gpio_free(board->gpio_nsleep); - - board->cleanup(par); - - regulator_put(par->regulator); - - framebuffer_release(info); - - return 0; -} -EXPORT_SYMBOL_GPL(auok190x_common_remove); - -MODULE_DESCRIPTION("Common code for AUO-K190X controllers"); -MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/auo_k190x.h b/drivers/video/fbdev/auo_k190x.h deleted file mode 100644 index e35af1f51b28..000000000000 --- a/drivers/video/fbdev/auo_k190x.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Private common definitions for AUO-K190X framebuffer drivers - * - * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * I80 interface specific defines - */ - -#define AUOK190X_I80_CS 0x01 -#define AUOK190X_I80_DC 0x02 -#define AUOK190X_I80_WR 0x03 -#define AUOK190X_I80_OE 0x04 - -/* - * AUOK190x commands, common to both controllers - */ - -#define AUOK190X_CMD_INIT 0x0000 -#define AUOK190X_CMD_STANDBY 0x0001 -#define AUOK190X_CMD_WAKEUP 0x0002 -#define AUOK190X_CMD_TCON_RESET 0x0003 -#define AUOK190X_CMD_DATA_STOP 0x1002 -#define AUOK190X_CMD_LUT_START 0x1003 -#define AUOK190X_CMD_DISP_REFRESH 0x1004 -#define AUOK190X_CMD_DISP_RESET 0x1005 -#define AUOK190X_CMD_PRE_DISPLAY_START 0x100D -#define AUOK190X_CMD_PRE_DISPLAY_STOP 0x100F -#define AUOK190X_CMD_FLASH_W 0x2000 -#define AUOK190X_CMD_FLASH_E 0x2001 -#define AUOK190X_CMD_FLASH_STS 0x2002 -#define AUOK190X_CMD_FRAMERATE 0x3000 -#define AUOK190X_CMD_READ_VERSION 0x4000 -#define AUOK190X_CMD_READ_STATUS 0x4001 -#define AUOK190X_CMD_READ_LUT 0x4003 -#define AUOK190X_CMD_DRIVERTIMING 0x5000 -#define AUOK190X_CMD_LBALANCE 0x5001 -#define AUOK190X_CMD_AGINGMODE 0x6000 -#define AUOK190X_CMD_AGINGEXIT 0x6001 - -/* - * Common settings for AUOK190X_CMD_INIT - */ - -#define AUOK190X_INIT_DATA_FILTER (0 << 12) -#define AUOK190X_INIT_DATA_BYPASS (1 << 12) -#define AUOK190X_INIT_INVERSE_WHITE (0 << 9) -#define AUOK190X_INIT_INVERSE_BLACK (1 << 9) -#define AUOK190X_INIT_SCAN_DOWN (0 << 1) -#define AUOK190X_INIT_SCAN_UP (1 << 1) -#define AUOK190X_INIT_SHIFT_LEFT (0 << 0) -#define AUOK190X_INIT_SHIFT_RIGHT (1 << 0) - -/* Common bits to pixels - * Mode 15-12 11-8 7-4 3-0 - * format0 4 3 2 1 - * format1 3 4 1 2 - */ - -#define AUOK190X_INIT_FORMAT0 0 -#define AUOK190X_INIT_FORMAT1 (1 << 6) - -/* - * settings for AUOK190X_CMD_RESET - */ - -#define AUOK190X_RESET_TCON (0 << 0) -#define AUOK190X_RESET_NORMAL (1 << 0) -#define AUOK190X_RESET_PON (1 << 1) - -/* - * AUOK190X_CMD_VERSION - */ - -#define AUOK190X_VERSION_TEMP_MASK (0x1ff) -#define AUOK190X_VERSION_EPD_MASK (0xff) -#define AUOK190X_VERSION_SIZE_INT(_val) ((_val & 0xfc00) >> 10) -#define AUOK190X_VERSION_SIZE_FLOAT(_val) ((_val & 0x3c0) >> 6) -#define AUOK190X_VERSION_MODEL(_val) (_val & 0x3f) -#define AUOK190X_VERSION_LUT(_val) (_val & 0xff) -#define AUOK190X_VERSION_TCON(_val) ((_val & 0xff00) >> 8) - -/* - * update modes for CMD_PARTIALDISP on K1900 and CMD_DDMA on K1901 - */ - -#define AUOK190X_UPDATE_MODE(_res) ((_res & 0x7) << 12) -#define AUOK190X_UPDATE_NONFLASH (1 << 15) - -/* - * track panel specific parameters for common init - */ - -struct auok190x_init_data { - char *id; - struct auok190x_board *board; - - void (*update_partial)(struct auok190xfb_par *par, u16 y1, u16 y2); - void (*update_all)(struct auok190xfb_par *par); - bool (*need_refresh)(struct auok190xfb_par *par); - void (*init)(struct auok190xfb_par *par); -}; - - -extern void auok190x_send_command_nowait(struct auok190xfb_par *par, u16 data); -extern int auok190x_send_command(struct auok190xfb_par *par, u16 data); -extern void auok190x_send_cmdargs_nowait(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv); -extern int auok190x_send_cmdargs(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv); -extern void auok190x_send_cmdargs_pixels_nowait(struct auok190xfb_par *par, - u16 cmd, int argc, u16 *argv, - int size, u16 *data); -extern int auok190x_send_cmdargs_pixels(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv, int size, - u16 *data); -extern int auok190x_read_cmdargs(struct auok190xfb_par *par, u16 cmd, - int argc, u16 *argv); - -extern int auok190x_common_probe(struct platform_device *pdev, - struct auok190x_init_data *init); -extern int auok190x_common_remove(struct platform_device *pdev); - -extern const struct dev_pm_ops auok190x_pm; diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c index 487d5e336e1b..82c20c6047b0 100644 --- a/drivers/video/fbdev/core/fb_defio.c +++ b/drivers/video/fbdev/core/fb_defio.c @@ -37,7 +37,7 @@ static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs } /* this is to find and return the vmalloc-ed fb pages */ -static int fb_deferred_io_fault(struct vm_fault *vmf) +static vm_fault_t fb_deferred_io_fault(struct vm_fault *vmf) { unsigned long offset; struct page *page; @@ -90,7 +90,7 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); /* vm_ops->page_mkwrite handler */ -static int fb_deferred_io_mkwrite(struct vm_fault *vmf) +static vm_fault_t fb_deferred_io_mkwrite(struct vm_fault *vmf) { struct page *page = vmf->page; struct fb_info *info = vmf->vma->vm_private_data; diff --git a/drivers/video/fbdev/mmp/fb/mmpfb.c b/drivers/video/fbdev/mmp/fb/mmpfb.c index f27697e07c55..ee212be67dc6 100644 --- a/drivers/video/fbdev/mmp/fb/mmpfb.c +++ b/drivers/video/fbdev/mmp/fb/mmpfb.c @@ -495,10 +495,9 @@ static int modes_setup(struct mmpfb_info *fbi) /* put videomode list to info structure */ videomodes = kcalloc(videomode_num, sizeof(struct fb_videomode), GFP_KERNEL); - if (!videomodes) { - dev_err(fbi->dev, "can't malloc video modes\n"); + if (!videomodes) return -ENOMEM; - } + for (i = 0; i < videomode_num; i++) mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]); fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist); diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c index b6f83d5df9fd..fcdbb2df137f 100644 --- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c +++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c @@ -406,12 +406,10 @@ static int path_init(struct mmphw_path_plat *path_plat, dev_info(ctrl->dev, "%s: %s\n", __func__, config->name); /* init driver data */ - path_info = kzalloc(sizeof(struct mmp_path_info), GFP_KERNEL); - if (!path_info) { - dev_err(ctrl->dev, "%s: unable to alloc path_info for %s\n", - __func__, config->name); + path_info = kzalloc(sizeof(*path_info), GFP_KERNEL); + if (!path_info) return 0; - } + path_info->name = config->name; path_info->id = path_plat->id; path_info->dev = ctrl->dev; diff --git a/drivers/video/fbdev/nvidia/nvidia.c b/drivers/video/fbdev/nvidia/nvidia.c index 2e50120bcfae..fbeeed5afe35 100644 --- a/drivers/video/fbdev/nvidia/nvidia.c +++ b/drivers/video/fbdev/nvidia/nvidia.c @@ -1548,7 +1548,7 @@ MODULE_PARM_DESC(noaccel, "(default=0)"); module_param(noscale, int, 0); MODULE_PARM_DESC(noscale, - "Disables screen scaleing. (0 or 1=disable) " + "Disables screen scaling. (0 or 1=disable) " "(default=0, do scaling)"); module_param(paneltweak, int, 0); MODULE_PARM_DESC(paneltweak, diff --git a/drivers/video/fbdev/omap/lcd_ams_delta.c b/drivers/video/fbdev/omap/lcd_ams_delta.c index a4ee947006c7..e8c748a0dfe2 100644 --- a/drivers/video/fbdev/omap/lcd_ams_delta.c +++ b/drivers/video/fbdev/omap/lcd_ams_delta.c @@ -197,3 +197,7 @@ static struct platform_driver ams_delta_panel_driver = { }; module_platform_driver(ams_delta_panel_driver); + +MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); +MODULE_DESCRIPTION("LCD panel support for the Amstrad E3 (Delta) videophone"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_h3.c b/drivers/video/fbdev/omap/lcd_h3.c index 796f4634c4c6..fd0ac997fb8c 100644 --- a/drivers/video/fbdev/omap/lcd_h3.c +++ b/drivers/video/fbdev/omap/lcd_h3.c @@ -89,3 +89,7 @@ static struct platform_driver h3_panel_driver = { }; module_platform_driver(h3_panel_driver); + +MODULE_AUTHOR("Imre Deak"); +MODULE_DESCRIPTION("LCD panel support for the TI OMAP H3 board"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_htcherald.c b/drivers/video/fbdev/omap/lcd_htcherald.c index 9d692f5b8025..db4ff1c6add9 100644 --- a/drivers/video/fbdev/omap/lcd_htcherald.c +++ b/drivers/video/fbdev/omap/lcd_htcherald.c @@ -66,3 +66,7 @@ static struct platform_driver htcherald_panel_driver = { }; module_platform_driver(htcherald_panel_driver); + +MODULE_AUTHOR("Cory Maccarrone"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LCD panel support for the HTC Herald"); diff --git a/drivers/video/fbdev/omap/lcd_inn1510.c b/drivers/video/fbdev/omap/lcd_inn1510.c index b284050f5471..1ea775f17bc1 100644 --- a/drivers/video/fbdev/omap/lcd_inn1510.c +++ b/drivers/video/fbdev/omap/lcd_inn1510.c @@ -73,3 +73,7 @@ static struct platform_driver innovator1510_panel_driver = { }; module_platform_driver(innovator1510_panel_driver); + +MODULE_AUTHOR("Imre Deak"); +MODULE_DESCRIPTION("LCD panel support for the TI OMAP1510 Innovator board"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_inn1610.c b/drivers/video/fbdev/omap/lcd_inn1610.c index 1841710e796f..8d0cf68d2de3 100644 --- a/drivers/video/fbdev/omap/lcd_inn1610.c +++ b/drivers/video/fbdev/omap/lcd_inn1610.c @@ -106,3 +106,7 @@ static struct platform_driver innovator1610_panel_driver = { }; module_platform_driver(innovator1610_panel_driver); + +MODULE_AUTHOR("Imre Deak"); +MODULE_DESCRIPTION("LCD panel support for the TI OMAP1610 Innovator board"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_osk.c b/drivers/video/fbdev/omap/lcd_osk.c index b0be5771fe90..9fc43a14957d 100644 --- a/drivers/video/fbdev/omap/lcd_osk.c +++ b/drivers/video/fbdev/omap/lcd_osk.c @@ -93,3 +93,7 @@ static struct platform_driver osk_panel_driver = { }; module_platform_driver(osk_panel_driver); + +MODULE_AUTHOR("Imre Deak"); +MODULE_DESCRIPTION("LCD panel support for the TI OMAP OSK board"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_palmte.c b/drivers/video/fbdev/omap/lcd_palmte.c index cef96386cf80..a0e888643131 100644 --- a/drivers/video/fbdev/omap/lcd_palmte.c +++ b/drivers/video/fbdev/omap/lcd_palmte.c @@ -59,3 +59,7 @@ static struct platform_driver palmte_panel_driver = { }; module_platform_driver(palmte_panel_driver); + +MODULE_AUTHOR("Romain Goyet <r.goyet@gmail.com>, Laurent Gonzalez <palmte.linux@free.fr>"); +MODULE_DESCRIPTION("LCD panel support for the Palm Tungsten E"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_palmtt.c b/drivers/video/fbdev/omap/lcd_palmtt.c index 627f13dae5ad..2c45375e456f 100644 --- a/drivers/video/fbdev/omap/lcd_palmtt.c +++ b/drivers/video/fbdev/omap/lcd_palmtt.c @@ -72,3 +72,7 @@ static struct platform_driver palmtt_panel_driver = { }; module_platform_driver(palmtt_panel_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("LCD panel support for Palm Tungsten|T"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/omap/lcd_palmz71.c b/drivers/video/fbdev/omap/lcd_palmz71.c index c46d4db1f839..c99a15ab1826 100644 --- a/drivers/video/fbdev/omap/lcd_palmz71.c +++ b/drivers/video/fbdev/omap/lcd_palmz71.c @@ -66,3 +66,7 @@ static struct platform_driver palmz71_panel_driver = { }; module_platform_driver(palmz71_panel_driver); + +MODULE_AUTHOR("Romain Goyet, Laurent Gonzalez, Marek Vasut"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LCD panel support for the Palm Zire71"); diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 3479a47a3082..585f39efcff6 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -1645,7 +1645,7 @@ static int omapfb_do_probe(struct platform_device *pdev, goto cleanup; } - fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL); + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); if (fbdev == NULL) { dev_err(&pdev->dev, "unable to allocate memory for device info\n"); diff --git a/drivers/video/fbdev/omap2/omapfb/Kconfig b/drivers/video/fbdev/omap2/omapfb/Kconfig index e6226aeed17e..3bf154e676d1 100644 --- a/drivers/video/fbdev/omap2/omapfb/Kconfig +++ b/drivers/video/fbdev/omap2/omapfb/Kconfig @@ -5,6 +5,7 @@ menuconfig FB_OMAP2 tristate "OMAP2+ frame buffer support" depends on FB depends on DRM_OMAP = n + depends on GPIOLIB select FB_OMAP2_DSS select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index bef431530090..87497a00241f 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -387,8 +387,7 @@ static void dsicm_get_resolution(struct omap_dss_device *dssdev, static ssize_t dsicm_num_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *in = ddata->in; u8 errors = 0; int r; @@ -419,8 +418,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev, static ssize_t dsicm_hw_revision_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *in = ddata->in; u8 id1, id2, id3; int r; @@ -451,8 +449,7 @@ static ssize_t dsicm_store_ulps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *in = ddata->in; unsigned long t; int r; @@ -486,8 +483,7 @@ static ssize_t dsicm_show_ulps(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); unsigned t; mutex_lock(&ddata->lock); @@ -501,8 +497,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); struct omap_dss_device *in = ddata->in; unsigned long t; int r; @@ -533,8 +528,7 @@ static ssize_t dsicm_show_ulps_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct panel_drv_data *ddata = dev_get_drvdata(dev); unsigned t; mutex_lock(&ddata->lock); diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index c3d49e13643c..76722a59f55e 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -2115,12 +2115,10 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp, if (ret) s = "color-tft"; - for (i = 0; lcd_types[i]; i++) - if (!strcmp(s, lcd_types[i])) - break; - if (!i || !lcd_types[i]) { + i = match_string(lcd_types, -1, s); + if (i < 0) { dev_err(dev, "lcd-type %s is unknown\n", s); - return -EINVAL; + return i; } info->lcd_conn |= LCD_CONN_TYPE(i); info->lcd_conn |= LCD_CONN_WIDTH(bus_width); diff --git a/drivers/video/fbdev/savage/savagefb_driver.c b/drivers/video/fbdev/savage/savagefb_driver.c index c20468362f11..c09d7426cd92 100644 --- a/drivers/video/fbdev/savage/savagefb_driver.c +++ b/drivers/video/fbdev/savage/savagefb_driver.c @@ -1892,11 +1892,11 @@ static int savage_init_hw(struct savagefb_par *par) vga_out8(0x3d4, 0x66, par); cr66 = vga_in8(0x3d5, par); vga_out8(0x3d5, cr66 | 0x02, par); - mdelay(10); + usleep_range(10000, 11000); vga_out8(0x3d4, 0x66, par); vga_out8(0x3d5, cr66 & ~0x02, par); /* clear reset flag */ - mdelay(10); + usleep_range(10000, 11000); /* @@ -1906,11 +1906,11 @@ static int savage_init_hw(struct savagefb_par *par) vga_out8(0x3d4, 0x3f, par); cr3f = vga_in8(0x3d5, par); vga_out8(0x3d5, cr3f | 0x08, par); - mdelay(10); + usleep_range(10000, 11000); vga_out8(0x3d4, 0x3f, par); vga_out8(0x3d5, cr3f & ~0x08, par); /* clear reset flags */ - mdelay(10); + usleep_range(10000, 11000); /* Savage ramdac speeds */ par->numClocks = 4; diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c index c3a46506e47e..dc46be38c970 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c @@ -29,7 +29,6 @@ #include <linux/vmalloc.h> #include <video/sh_mobile_lcdc.h> -#include <video/sh_mobile_meram.h> #include "sh_mobile_lcdcfb.h" @@ -217,7 +216,6 @@ struct sh_mobile_lcdc_priv { struct notifier_block notifier; int started; int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ - struct sh_mobile_meram_info *meram_dev; }; /* ----------------------------------------------------------------------------- @@ -346,16 +344,12 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) if (priv->dot_clk) clk_prepare_enable(priv->dot_clk); pm_runtime_get_sync(priv->dev); - if (priv->meram_dev && priv->meram_dev->pdev) - pm_runtime_get_sync(&priv->meram_dev->pdev->dev); } } static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) { if (atomic_sub_return(1, &priv->hw_usecnt) == -1) { - if (priv->meram_dev && priv->meram_dev->pdev) - pm_runtime_put_sync(&priv->meram_dev->pdev->dev); pm_runtime_put(priv->dev); if (priv->dot_clk) clk_disable_unprepare(priv->dot_clk); @@ -1073,7 +1067,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { - struct sh_mobile_meram_info *mdev = priv->meram_dev; struct sh_mobile_lcdc_chan *ch; unsigned long tmp; int ret; @@ -1106,9 +1099,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) /* Compute frame buffer base address and pitch for each channel. */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { - int pixelformat; - void *cache; - ch = &priv->ch[k]; if (!ch->enabled) continue; @@ -1117,45 +1107,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual; ch->line_size = ch->pitch; - - /* Enable MERAM if possible. */ - if (mdev == NULL || ch->cfg->meram_cfg == NULL) - continue; - - /* Free the allocated MERAM cache. */ - if (ch->cache) { - sh_mobile_meram_cache_free(mdev, ch->cache); - ch->cache = NULL; - } - - switch (ch->format->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - pixelformat = SH_MOBILE_MERAM_PF_NV; - break; - case V4L2_PIX_FMT_NV24: - case V4L2_PIX_FMT_NV42: - pixelformat = SH_MOBILE_MERAM_PF_NV24; - break; - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_BGR32: - default: - pixelformat = SH_MOBILE_MERAM_PF_RGB; - break; - } - - cache = sh_mobile_meram_cache_alloc(mdev, ch->cfg->meram_cfg, - ch->pitch, ch->yres, pixelformat, - &ch->line_size); - if (!IS_ERR(cache)) { - sh_mobile_meram_cache_update(mdev, cache, - ch->base_addr_y, ch->base_addr_c, - &ch->base_addr_y, &ch->base_addr_c); - ch->cache = cache; - } } for (k = 0; k < ARRAY_SIZE(priv->overlays); ++k) { @@ -1223,13 +1174,6 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } sh_mobile_lcdc_display_off(ch); - - /* Free the MERAM cache. */ - if (ch->cache) { - sh_mobile_meram_cache_free(priv->meram_dev, ch->cache); - ch->cache = NULL; - } - } /* stop the lcdc */ @@ -1851,11 +1795,6 @@ static int sh_mobile_lcdc_pan(struct fb_var_screeninfo *var, base_addr_c = ch->dma_handle + ch->xres_virtual * ch->yres_virtual + c_offset; - if (ch->cache) - sh_mobile_meram_cache_update(priv->meram_dev, ch->cache, - base_addr_y, base_addr_c, - &base_addr_y, &base_addr_c); - ch->base_addr_y = base_addr_y; ch->base_addr_c = base_addr_c; ch->pan_y_offset = y_offset; @@ -2149,10 +2088,8 @@ sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch) if (info->fbdefio) { ch->sglist = vmalloc(sizeof(struct scatterlist) * ch->fb_size >> PAGE_SHIFT); - if (!ch->sglist) { - dev_err(ch->lcdc->dev, "cannot allocate sglist\n"); + if (!ch->sglist) return -ENOMEM; - } } info->bl_dev = ch->bl; @@ -2354,8 +2291,7 @@ static int sh_mobile_lcdc_resume(struct device *dev) static int sh_mobile_lcdc_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); + struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev); /* turn off LCDC hardware */ lcdc_write(priv, _LDCNT1R, 0); @@ -2365,8 +2301,7 @@ static int sh_mobile_lcdc_runtime_suspend(struct device *dev) static int sh_mobile_lcdc_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev); + struct sh_mobile_lcdc_priv *priv = dev_get_drvdata(dev); __sh_mobile_lcdc_start(priv); @@ -2718,13 +2653,11 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev) } priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "cannot allocate device data\n"); + if (!priv) return -ENOMEM; - } priv->dev = &pdev->dev; - priv->meram_dev = pdata->meram_dev; + for (i = 0; i < ARRAY_SIZE(priv->ch); i++) mutex_init(&priv->ch[i].open_lock); platform_set_drvdata(pdev, priv); diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.h b/drivers/video/fbdev/sh_mobile_lcdcfb.h index cc52c74721fe..b8e47a8bd8ab 100644 --- a/drivers/video/fbdev/sh_mobile_lcdcfb.h +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.h @@ -61,7 +61,6 @@ struct sh_mobile_lcdc_chan { unsigned long *reg_offs; unsigned long ldmt1r_value; unsigned long enabled; /* ME and SE in LDCNT2R */ - void *cache; struct mutex open_lock; /* protects the use counter */ int use_count; diff --git a/drivers/video/fbdev/sh_mobile_meram.c b/drivers/video/fbdev/sh_mobile_meram.c deleted file mode 100644 index baadfb207b2e..000000000000 --- a/drivers/video/fbdev/sh_mobile_meram.c +++ /dev/null @@ -1,758 +0,0 @@ -/* - * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver - * - * Copyright (c) 2011 Damian Hobson-Garcia <dhobsong@igel.co.jp> - * Takanari Hayama <taki@igel.co.jp> - * - * 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/device.h> -#include <linux/err.h> -#include <linux/export.h> -#include <linux/genalloc.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> - -#include <video/sh_mobile_meram.h> - -/* ----------------------------------------------------------------------------- - * MERAM registers - */ - -#define MEVCR1 0x4 -#define MEVCR1_RST (1 << 31) -#define MEVCR1_WD (1 << 30) -#define MEVCR1_AMD1 (1 << 29) -#define MEVCR1_AMD0 (1 << 28) -#define MEQSEL1 0x40 -#define MEQSEL2 0x44 - -#define MExxCTL 0x400 -#define MExxCTL_BV (1 << 31) -#define MExxCTL_BSZ_SHIFT 28 -#define MExxCTL_MSAR_MASK (0x7ff << MExxCTL_MSAR_SHIFT) -#define MExxCTL_MSAR_SHIFT 16 -#define MExxCTL_NXT_MASK (0x1f << MExxCTL_NXT_SHIFT) -#define MExxCTL_NXT_SHIFT 11 -#define MExxCTL_WD1 (1 << 10) -#define MExxCTL_WD0 (1 << 9) -#define MExxCTL_WS (1 << 8) -#define MExxCTL_CB (1 << 7) -#define MExxCTL_WBF (1 << 6) -#define MExxCTL_WF (1 << 5) -#define MExxCTL_RF (1 << 4) -#define MExxCTL_CM (1 << 3) -#define MExxCTL_MD_READ (1 << 0) -#define MExxCTL_MD_WRITE (2 << 0) -#define MExxCTL_MD_ICB_WB (3 << 0) -#define MExxCTL_MD_ICB (4 << 0) -#define MExxCTL_MD_FB (7 << 0) -#define MExxCTL_MD_MASK (7 << 0) -#define MExxBSIZE 0x404 -#define MExxBSIZE_RCNT_SHIFT 28 -#define MExxBSIZE_YSZM1_SHIFT 16 -#define MExxBSIZE_XSZM1_SHIFT 0 -#define MExxMNCF 0x408 -#define MExxMNCF_KWBNM_SHIFT 28 -#define MExxMNCF_KRBNM_SHIFT 24 -#define MExxMNCF_BNM_SHIFT 16 -#define MExxMNCF_XBV (1 << 15) -#define MExxMNCF_CPL_YCBCR444 (1 << 12) -#define MExxMNCF_CPL_YCBCR420 (2 << 12) -#define MExxMNCF_CPL_YCBCR422 (3 << 12) -#define MExxMNCF_CPL_MSK (3 << 12) -#define MExxMNCF_BL (1 << 2) -#define MExxMNCF_LNM_SHIFT 0 -#define MExxSARA 0x410 -#define MExxSARB 0x414 -#define MExxSBSIZE 0x418 -#define MExxSBSIZE_HDV (1 << 31) -#define MExxSBSIZE_HSZ16 (0 << 28) -#define MExxSBSIZE_HSZ32 (1 << 28) -#define MExxSBSIZE_HSZ64 (2 << 28) -#define MExxSBSIZE_HSZ128 (3 << 28) -#define MExxSBSIZE_SBSIZZ_SHIFT 0 - -#define MERAM_MExxCTL_VAL(next, addr) \ - ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \ - (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK)) -#define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \ - (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \ - ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \ - ((xszm1) << MExxBSIZE_XSZM1_SHIFT)) - -static const unsigned long common_regs[] = { - MEVCR1, - MEQSEL1, - MEQSEL2, -}; -#define MERAM_REGS_SIZE ARRAY_SIZE(common_regs) - -static const unsigned long icb_regs[] = { - MExxCTL, - MExxBSIZE, - MExxMNCF, - MExxSARA, - MExxSARB, - MExxSBSIZE, -}; -#define ICB_REGS_SIZE ARRAY_SIZE(icb_regs) - -/* - * sh_mobile_meram_icb - MERAM ICB information - * @regs: Registers cache - * @index: ICB index - * @offset: MERAM block offset - * @size: MERAM block size in KiB - * @cache_unit: Bytes to cache per ICB - * @pixelformat: Video pixel format of the data stored in the ICB - * @current_reg: Which of Start Address Register A (0) or B (1) is in use - */ -struct sh_mobile_meram_icb { - unsigned long regs[ICB_REGS_SIZE]; - unsigned int index; - unsigned long offset; - unsigned int size; - - unsigned int cache_unit; - unsigned int pixelformat; - unsigned int current_reg; -}; - -#define MERAM_ICB_NUM 32 - -struct sh_mobile_meram_fb_plane { - struct sh_mobile_meram_icb *marker; - struct sh_mobile_meram_icb *cache; -}; - -struct sh_mobile_meram_fb_cache { - unsigned int nplanes; - struct sh_mobile_meram_fb_plane planes[2]; -}; - -/* - * sh_mobile_meram_priv - MERAM device - * @base: Registers base address - * @meram: MERAM physical address - * @regs: Registers cache - * @lock: Protects used_icb and icbs - * @used_icb: Bitmask of used ICBs - * @icbs: ICBs - * @pool: Allocation pool to manage the MERAM - */ -struct sh_mobile_meram_priv { - void __iomem *base; - unsigned long meram; - unsigned long regs[MERAM_REGS_SIZE]; - - struct mutex lock; - unsigned long used_icb; - struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM]; - - struct gen_pool *pool; -}; - -/* settings */ -#define MERAM_GRANULARITY 1024 -#define MERAM_SEC_LINE 15 -#define MERAM_LINE_WIDTH 2048 - -/* ----------------------------------------------------------------------------- - * Registers access - */ - -#define MERAM_ICB_OFFSET(base, idx, off) ((base) + (off) + (idx) * 0x20) - -static inline void meram_write_icb(void __iomem *base, unsigned int idx, - unsigned int off, unsigned long val) -{ - iowrite32(val, MERAM_ICB_OFFSET(base, idx, off)); -} - -static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx, - unsigned int off) -{ - return ioread32(MERAM_ICB_OFFSET(base, idx, off)); -} - -static inline void meram_write_reg(void __iomem *base, unsigned int off, - unsigned long val) -{ - iowrite32(val, base + off); -} - -static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off) -{ - return ioread32(base + off); -} - -/* ----------------------------------------------------------------------------- - * MERAM allocation and free - */ - -static unsigned long meram_alloc(struct sh_mobile_meram_priv *priv, size_t size) -{ - return gen_pool_alloc(priv->pool, size); -} - -static void meram_free(struct sh_mobile_meram_priv *priv, unsigned long mem, - size_t size) -{ - gen_pool_free(priv->pool, mem, size); -} - -/* ----------------------------------------------------------------------------- - * LCDC cache planes allocation, init, cleanup and free - */ - -/* Allocate ICBs and MERAM for a plane. */ -static int meram_plane_alloc(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane, - size_t size) -{ - unsigned long mem; - unsigned long idx; - - idx = find_first_zero_bit(&priv->used_icb, 28); - if (idx == 28) - return -ENOMEM; - plane->cache = &priv->icbs[idx]; - - idx = find_next_zero_bit(&priv->used_icb, 32, 28); - if (idx == 32) - return -ENOMEM; - plane->marker = &priv->icbs[idx]; - - mem = meram_alloc(priv, size * 1024); - if (mem == 0) - return -ENOMEM; - - __set_bit(plane->marker->index, &priv->used_icb); - __set_bit(plane->cache->index, &priv->used_icb); - - plane->marker->offset = mem - priv->meram; - plane->marker->size = size; - - return 0; -} - -/* Free ICBs and MERAM for a plane. */ -static void meram_plane_free(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane) -{ - meram_free(priv, priv->meram + plane->marker->offset, - plane->marker->size * 1024); - - __clear_bit(plane->marker->index, &priv->used_icb); - __clear_bit(plane->cache->index, &priv->used_icb); -} - -/* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */ -static int is_nvcolor(int cspace) -{ - if (cspace == SH_MOBILE_MERAM_PF_NV || - cspace == SH_MOBILE_MERAM_PF_NV24) - return 1; - return 0; -} - -/* Set the next address to fetch. */ -static void meram_set_next_addr(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_cache *cache, - unsigned long base_addr_y, - unsigned long base_addr_c) -{ - struct sh_mobile_meram_icb *icb = cache->planes[0].marker; - unsigned long target; - - icb->current_reg ^= 1; - target = icb->current_reg ? MExxSARB : MExxSARA; - - /* set the next address to fetch */ - meram_write_icb(priv->base, cache->planes[0].cache->index, target, - base_addr_y); - meram_write_icb(priv->base, cache->planes[0].marker->index, target, - base_addr_y + cache->planes[0].marker->cache_unit); - - if (cache->nplanes == 2) { - meram_write_icb(priv->base, cache->planes[1].cache->index, - target, base_addr_c); - meram_write_icb(priv->base, cache->planes[1].marker->index, - target, base_addr_c + - cache->planes[1].marker->cache_unit); - } -} - -/* Get the next ICB address. */ -static void -meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata, - struct sh_mobile_meram_fb_cache *cache, - unsigned long *icb_addr_y, unsigned long *icb_addr_c) -{ - struct sh_mobile_meram_icb *icb = cache->planes[0].marker; - unsigned long icb_offset; - - if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0) - icb_offset = 0x80000000 | (icb->current_reg << 29); - else - icb_offset = 0xc0000000 | (icb->current_reg << 23); - - *icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24); - if (cache->nplanes == 2) - *icb_addr_c = icb_offset - | (cache->planes[1].marker->index << 24); -} - -#define MERAM_CALC_BYTECOUNT(x, y) \ - (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1)) - -/* Initialize MERAM. */ -static int meram_plane_init(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane, - unsigned int xres, unsigned int yres, - unsigned int *out_pitch) -{ - struct sh_mobile_meram_icb *marker = plane->marker; - unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres); - unsigned long bnm; - unsigned int lcdc_pitch; - unsigned int xpitch; - unsigned int line_cnt; - unsigned int save_lines; - - /* adjust pitch to 1024, 2048, 4096 or 8192 */ - lcdc_pitch = (xres - 1) | 1023; - lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1); - lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2); - lcdc_pitch += 1; - - /* derive settings */ - if (lcdc_pitch == 8192 && yres >= 1024) { - lcdc_pitch = xpitch = MERAM_LINE_WIDTH; - line_cnt = total_byte_count >> 11; - *out_pitch = xres; - save_lines = plane->marker->size / 16 / MERAM_SEC_LINE; - save_lines *= MERAM_SEC_LINE; - } else { - xpitch = xres; - line_cnt = yres; - *out_pitch = lcdc_pitch; - save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2; - save_lines &= 0xff; - } - bnm = (save_lines - 1) << 16; - - /* TODO: we better to check if we have enough MERAM buffer size */ - - /* set up ICB */ - meram_write_icb(priv->base, plane->cache->index, MExxBSIZE, - MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1)); - meram_write_icb(priv->base, plane->marker->index, MExxBSIZE, - MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1)); - - meram_write_icb(priv->base, plane->cache->index, MExxMNCF, bnm); - meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm); - - meram_write_icb(priv->base, plane->cache->index, MExxSBSIZE, xpitch); - meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch); - - /* save a cache unit size */ - plane->cache->cache_unit = xres * save_lines; - plane->marker->cache_unit = xres * save_lines; - - /* - * Set MERAM for framebuffer - * - * we also chain the cache_icb and the marker_icb. - * we also split the allocated MERAM buffer between two ICBs. - */ - meram_write_icb(priv->base, plane->cache->index, MExxCTL, - MERAM_MExxCTL_VAL(plane->marker->index, marker->offset) - | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | - MExxCTL_MD_FB); - meram_write_icb(priv->base, plane->marker->index, MExxCTL, - MERAM_MExxCTL_VAL(plane->cache->index, marker->offset + - plane->marker->size / 2) | - MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM | - MExxCTL_MD_FB); - - return 0; -} - -static void meram_plane_cleanup(struct sh_mobile_meram_priv *priv, - struct sh_mobile_meram_fb_plane *plane) -{ - /* disable ICB */ - meram_write_icb(priv->base, plane->cache->index, MExxCTL, - MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); - meram_write_icb(priv->base, plane->marker->index, MExxCTL, - MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF); - - plane->cache->cache_unit = 0; - plane->marker->cache_unit = 0; -} - -/* ----------------------------------------------------------------------------- - * MERAM operations - */ - -unsigned long sh_mobile_meram_alloc(struct sh_mobile_meram_info *pdata, - size_t size) -{ - struct sh_mobile_meram_priv *priv = pdata->priv; - - return meram_alloc(priv, size); -} -EXPORT_SYMBOL_GPL(sh_mobile_meram_alloc); - -void sh_mobile_meram_free(struct sh_mobile_meram_info *pdata, unsigned long mem, - size_t size) -{ - struct sh_mobile_meram_priv *priv = pdata->priv; - - meram_free(priv, mem, size); -} -EXPORT_SYMBOL_GPL(sh_mobile_meram_free); - -/* Allocate memory for the ICBs and mark them as used. */ -static struct sh_mobile_meram_fb_cache * -meram_cache_alloc(struct sh_mobile_meram_priv *priv, - const struct sh_mobile_meram_cfg *cfg, - int pixelformat) -{ - unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; - struct sh_mobile_meram_fb_cache *cache; - int ret; - - cache = kzalloc(sizeof(*cache), GFP_KERNEL); - if (cache == NULL) - return ERR_PTR(-ENOMEM); - - cache->nplanes = nplanes; - - ret = meram_plane_alloc(priv, &cache->planes[0], - cfg->icb[0].meram_size); - if (ret < 0) - goto error; - - cache->planes[0].marker->current_reg = 1; - cache->planes[0].marker->pixelformat = pixelformat; - - if (cache->nplanes == 1) - return cache; - - ret = meram_plane_alloc(priv, &cache->planes[1], - cfg->icb[1].meram_size); - if (ret < 0) { - meram_plane_free(priv, &cache->planes[0]); - goto error; - } - - return cache; - -error: - kfree(cache); - return ERR_PTR(-ENOMEM); -} - -void *sh_mobile_meram_cache_alloc(struct sh_mobile_meram_info *pdata, - const struct sh_mobile_meram_cfg *cfg, - unsigned int xres, unsigned int yres, - unsigned int pixelformat, unsigned int *pitch) -{ - struct sh_mobile_meram_fb_cache *cache; - struct sh_mobile_meram_priv *priv = pdata->priv; - struct platform_device *pdev = pdata->pdev; - unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1; - unsigned int out_pitch; - - if (priv == NULL) - return ERR_PTR(-ENODEV); - - if (pixelformat != SH_MOBILE_MERAM_PF_NV && - pixelformat != SH_MOBILE_MERAM_PF_NV24 && - pixelformat != SH_MOBILE_MERAM_PF_RGB) - return ERR_PTR(-EINVAL); - - dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres, - !pixelformat ? "yuv" : "rgb"); - - /* we can't handle wider than 8192px */ - if (xres > 8192) { - dev_err(&pdev->dev, "width exceeding the limit (> 8192)."); - return ERR_PTR(-EINVAL); - } - - if (cfg->icb[0].meram_size == 0) - return ERR_PTR(-EINVAL); - - if (nplanes == 2 && cfg->icb[1].meram_size == 0) - return ERR_PTR(-EINVAL); - - mutex_lock(&priv->lock); - - /* We now register the ICBs and allocate the MERAM regions. */ - cache = meram_cache_alloc(priv, cfg, pixelformat); - if (IS_ERR(cache)) { - dev_err(&pdev->dev, "MERAM allocation failed (%ld).", - PTR_ERR(cache)); - goto err; - } - - /* initialize MERAM */ - meram_plane_init(priv, &cache->planes[0], xres, yres, &out_pitch); - *pitch = out_pitch; - if (pixelformat == SH_MOBILE_MERAM_PF_NV) - meram_plane_init(priv, &cache->planes[1], - xres, (yres + 1) / 2, &out_pitch); - else if (pixelformat == SH_MOBILE_MERAM_PF_NV24) - meram_plane_init(priv, &cache->planes[1], - 2 * xres, (yres + 1) / 2, &out_pitch); - -err: - mutex_unlock(&priv->lock); - return cache; -} -EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_alloc); - -void -sh_mobile_meram_cache_free(struct sh_mobile_meram_info *pdata, void *data) -{ - struct sh_mobile_meram_fb_cache *cache = data; - struct sh_mobile_meram_priv *priv = pdata->priv; - - mutex_lock(&priv->lock); - - /* Cleanup and free. */ - meram_plane_cleanup(priv, &cache->planes[0]); - meram_plane_free(priv, &cache->planes[0]); - - if (cache->nplanes == 2) { - meram_plane_cleanup(priv, &cache->planes[1]); - meram_plane_free(priv, &cache->planes[1]); - } - - kfree(cache); - - mutex_unlock(&priv->lock); -} -EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_free); - -void -sh_mobile_meram_cache_update(struct sh_mobile_meram_info *pdata, void *data, - unsigned long base_addr_y, - unsigned long base_addr_c, - unsigned long *icb_addr_y, - unsigned long *icb_addr_c) -{ - struct sh_mobile_meram_fb_cache *cache = data; - struct sh_mobile_meram_priv *priv = pdata->priv; - - mutex_lock(&priv->lock); - - meram_set_next_addr(priv, cache, base_addr_y, base_addr_c); - meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c); - - mutex_unlock(&priv->lock); -} -EXPORT_SYMBOL_GPL(sh_mobile_meram_cache_update); - -/* ----------------------------------------------------------------------------- - * Power management - */ - -#ifdef CONFIG_PM -static int sh_mobile_meram_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); - unsigned int i, j; - - for (i = 0; i < MERAM_REGS_SIZE; i++) - priv->regs[i] = meram_read_reg(priv->base, common_regs[i]); - - for (i = 0; i < 32; i++) { - if (!test_bit(i, &priv->used_icb)) - continue; - for (j = 0; j < ICB_REGS_SIZE; j++) { - priv->icbs[i].regs[j] = - meram_read_icb(priv->base, i, icb_regs[j]); - /* Reset ICB on resume */ - if (icb_regs[j] == MExxCTL) - priv->icbs[i].regs[j] |= - MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF; - } - } - return 0; -} - -static int sh_mobile_meram_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); - unsigned int i, j; - - for (i = 0; i < 32; i++) { - if (!test_bit(i, &priv->used_icb)) - continue; - for (j = 0; j < ICB_REGS_SIZE; j++) - meram_write_icb(priv->base, i, icb_regs[j], - priv->icbs[i].regs[j]); - } - - for (i = 0; i < MERAM_REGS_SIZE; i++) - meram_write_reg(priv->base, common_regs[i], priv->regs[i]); - return 0; -} -#endif /* CONFIG_PM */ - -static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops, - sh_mobile_meram_suspend, - sh_mobile_meram_resume, NULL); - -/* ----------------------------------------------------------------------------- - * Probe/remove and driver init/exit - */ - -static int sh_mobile_meram_probe(struct platform_device *pdev) -{ - struct sh_mobile_meram_priv *priv; - struct sh_mobile_meram_info *pdata = pdev->dev.platform_data; - struct resource *regs; - struct resource *meram; - unsigned int i; - int error; - - if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - meram = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (regs == NULL || meram == NULL) { - dev_err(&pdev->dev, "cannot get platform resources\n"); - return -ENOENT; - } - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "cannot allocate device data\n"); - return -ENOMEM; - } - - /* Initialize private data. */ - mutex_init(&priv->lock); - priv->used_icb = pdata->reserved_icbs; - - for (i = 0; i < MERAM_ICB_NUM; ++i) - priv->icbs[i].index = i; - - pdata->priv = priv; - pdata->pdev = pdev; - - /* Request memory regions and remap the registers. */ - if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) { - dev_err(&pdev->dev, "MERAM registers region already claimed\n"); - error = -EBUSY; - goto err_req_regs; - } - - if (!request_mem_region(meram->start, resource_size(meram), - pdev->name)) { - dev_err(&pdev->dev, "MERAM memory region already claimed\n"); - error = -EBUSY; - goto err_req_meram; - } - - priv->base = ioremap_nocache(regs->start, resource_size(regs)); - if (!priv->base) { - dev_err(&pdev->dev, "ioremap failed\n"); - error = -EFAULT; - goto err_ioremap; - } - - priv->meram = meram->start; - - /* Create and initialize the MERAM memory pool. */ - priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1); - if (priv->pool == NULL) { - error = -ENOMEM; - goto err_genpool; - } - - error = gen_pool_add(priv->pool, meram->start, resource_size(meram), - -1); - if (error < 0) - goto err_genpool; - - /* initialize ICB addressing mode */ - if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1) - meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1); - - platform_set_drvdata(pdev, priv); - pm_runtime_enable(&pdev->dev); - - dev_info(&pdev->dev, "sh_mobile_meram initialized."); - - return 0; - -err_genpool: - if (priv->pool) - gen_pool_destroy(priv->pool); - iounmap(priv->base); -err_ioremap: - release_mem_region(meram->start, resource_size(meram)); -err_req_meram: - release_mem_region(regs->start, resource_size(regs)); -err_req_regs: - mutex_destroy(&priv->lock); - kfree(priv); - - return error; -} - - -static int sh_mobile_meram_remove(struct platform_device *pdev) -{ - struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev); - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - pm_runtime_disable(&pdev->dev); - - gen_pool_destroy(priv->pool); - - iounmap(priv->base); - release_mem_region(meram->start, resource_size(meram)); - release_mem_region(regs->start, resource_size(regs)); - - mutex_destroy(&priv->lock); - - kfree(priv); - - return 0; -} - -static struct platform_driver sh_mobile_meram_driver = { - .driver = { - .name = "sh_mobile_meram", - .pm = &sh_mobile_meram_dev_pm_ops, - }, - .probe = sh_mobile_meram_probe, - .remove = sh_mobile_meram_remove, -}; - -module_platform_driver(sh_mobile_meram_driver); - -MODULE_DESCRIPTION("SuperH Mobile MERAM driver"); -MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c index 6f0a19501c6a..dde52d027416 100644 --- a/drivers/video/fbdev/sm501fb.c +++ b/drivers/video/fbdev/sm501fb.c @@ -1932,8 +1932,7 @@ static int sm501fb_probe(struct platform_device *pdev) int ret; /* allocate our framebuffers */ - - info = kzalloc(sizeof(struct sm501fb_info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { dev_err(dev, "failed to allocate state\n"); return -ENOMEM; diff --git a/drivers/video/fbdev/via/global.h b/drivers/video/fbdev/via/global.h index 275dbbbd6b81..649d2ca5516e 100644 --- a/drivers/video/fbdev/via/global.h +++ b/drivers/video/fbdev/via/global.h @@ -33,6 +33,12 @@ #include <linux/console.h> #include <linux/timer.h> +#ifdef CONFIG_X86 +#include <asm/olpc.h> +#else +#define machine_is_olpc(x) 0 +#endif + #include "debug.h" #include "viafbdev.h" diff --git a/drivers/video/fbdev/via/hw.c b/drivers/video/fbdev/via/hw.c index 22450908306c..48969c644599 100644 --- a/drivers/video/fbdev/via/hw.c +++ b/drivers/video/fbdev/via/hw.c @@ -20,7 +20,6 @@ */ #include <linux/via-core.h> -#include <asm/olpc.h> #include "global.h" #include "via_clock.h" diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c index 77774d8abf94..b041eb27a9bf 100644 --- a/drivers/video/fbdev/via/via-core.c +++ b/drivers/video/fbdev/via/via-core.c @@ -17,7 +17,6 @@ #include <linux/platform_device.h> #include <linux/list.h> #include <linux/pm.h> -#include <asm/olpc.h> /* * The default port config. diff --git a/drivers/video/fbdev/via/via_clock.c b/drivers/video/fbdev/via/via_clock.c index bf269fa43977..3d0efdbaea58 100644 --- a/drivers/video/fbdev/via/via_clock.c +++ b/drivers/video/fbdev/via/via_clock.c @@ -25,7 +25,7 @@ #include <linux/kernel.h> #include <linux/via-core.h> -#include <asm/olpc.h> + #include "via_clock.h" #include "global.h" #include "debug.h" diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index 52f577b0669b..d2f785068ef4 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -25,7 +25,6 @@ #include <linux/stat.h> #include <linux/via-core.h> #include <linux/via_i2c.h> -#include <asm/olpc.h> #define _MASTER_FILE #include "global.h" diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index b563a4499cc8..705aebd74e56 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -578,6 +578,8 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); struct device *dev = get_device(&vp_dev->vdev.dev); + pci_disable_sriov(pci_dev); + unregister_virtio_device(&vp_dev->vdev); if (vp_dev->ioaddr) @@ -589,6 +591,33 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) put_device(dev); } +static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs) +{ + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + struct virtio_device *vdev = &vp_dev->vdev; + int ret; + + if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK)) + return -EBUSY; + + if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV)) + return -EINVAL; + + if (pci_vfs_assigned(pci_dev)) + return -EPERM; + + if (num_vfs == 0) { + pci_disable_sriov(pci_dev); + return 0; + } + + ret = pci_enable_sriov(pci_dev, num_vfs); + if (ret < 0) + return ret; + + return num_vfs; +} + static struct pci_driver virtio_pci_driver = { .name = "virtio-pci", .id_table = virtio_pci_id_table, @@ -597,6 +626,7 @@ static struct pci_driver virtio_pci_driver = { #ifdef CONFIG_PM_SLEEP .driver.pm = &virtio_pci_pm_ops, #endif + .sriov_configure = virtio_pci_sriov_configure, }; module_pci_driver(virtio_pci_driver); diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 2555d80f6eec..07571daccfec 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -153,14 +153,28 @@ static u64 vp_get_features(struct virtio_device *vdev) return features; } +static void vp_transport_features(struct virtio_device *vdev, u64 features) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + struct pci_dev *pci_dev = vp_dev->pci_dev; + + if ((features & BIT_ULL(VIRTIO_F_SR_IOV)) && + pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV)) + __virtio_set_bit(vdev, VIRTIO_F_SR_IOV); +} + /* virtio config->finalize_features() implementation */ static int vp_finalize_features(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); + u64 features = vdev->features; /* Give virtio_ring a chance to accept features. */ vring_transport_features(vdev); + /* Give virtio_pci a chance to accept features. */ + vp_transport_features(vdev, features); + if (!__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) { dev_err(&vdev->dev, "virtio: device uses modern interface " "but does not have VIRTIO_F_VERSION_1\n"); |